Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Help verifying RSA PSS signature in Perl with Crypt::RSA and Crypt::RSA::SS::PSS

by cryptques (Novice)
on Mar 31, 2013 at 02:52 UTC ( [id://1026320]=perlquestion: print w/replies, xml ) Need Help??

cryptques has asked for the wisdom of the Perl Monks concerning the following question:

I'm unable to verify a PSS-signed signature in Perl using Crypt::RSA and Crypt::RSA::SS::PSS.
Here's the situation:

I have a device that has a 1024-bit RSA key, and signs data using PSS, SHA1 and AES-128.

I extract the device's public key successfully, save it in a file with PEM_write_RSA_PUBKEY()

I am able to verify this in C/C++ using RSA_verify_PKCS1_PSS(), and also using openssl on the command line, like this:

echo -n hello | openssl dgst -verify pubkey.pem -signature hello.sig -sha1 \             -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:20

Where:

  • The string "hello" is the buffer that's been signed by the device.
  • "pubkey.pem" is the device's RSA Public Key, exported from the device with PEM_write_RSA_PUBKEY().
  • "hello.sig" contains the binary (raw) signature generated by the device. (It's 128 bytes, because of the padding.)

I'm trying to do the above in Perl, using Crypt::RSA and Crypt::RSA::SS::PSS, and can't get it to work.

I've tested those two modules and I *am* able to generate and verify a PSS signature in Perl when generating my own key, like this:

#### use Crypt::RSA; use Crypt::RSA::SS::PSS; my ($message, $rsa, $pss, $signature, $verify); my ($public, $private); # The message to be encrypted # $message = "hello"; # Generate RSA key # $rsa = new Crypt::RSA; ($public, $private) = $rsa->keygen( Size => 1024, Filename => "key" ); # Generate PSS signature # $pss = new Crypt::RSA::SS::PSS; $signature = $pss->sign ( Message => $message, Key => $private ) || die $pss->errstr; $verify = $pss->verify ( Message => $message, Key => $public, Signature => $signature) || die $pss->errstr; # $verify returns true, it worked. ####
So, instead of creating my own RSA key I read in a public key using something like this:
#### $publicKey = new Crypt::RSA::Key::Public (Filename => "key.public"); …. # I pack the 256 character (128 byte) hex string of the signature # that's generated by the device. $signature = pack ("H*", '03808458…..73E92'); ####
Where "key.public" contains the device's public key, converted to a decimal string, inserted into the "n" field of the structure that is read/written by Crypt::RSA::Key::Public.

But I can't get it to verify :-(

Methinks I should be able to indicate that it should be using SHA1 and AES-128 (as opposed to, say, Blowfish). Am I barking up the wrong tree?

Thanks….

Replies are listed 'Best First'.
Re: Help verifying RSA PSS signature in Perl with Crypt::RSA and Crypt::RSA::SS::PSS
by Athanasius (Archbishop) on Mar 31, 2013 at 04:01 UTC

    Hello cryptques, and welcome to the Monastery!

    I've tested those two modules and I *am* able to generate and verify a PSS signature in Perl...

    Are you sure it’s working correctly? When I run your script with the line:

    print ($verify ? 'verified' : 'failed'), "\n";

    added at the end, I get an intermittent error:

    13:17 >perl 592_SoPW.pl verified 13:17 >perl 592_SoPW.pl verified 13:17 >perl 592_SoPW.pl verified 13:18 >perl 592_SoPW.pl PARI: *** forbidden division t_INT % t_REAL. at C:/Perl/Strawberry +/spp-spec-64int-5.16.0.1-beta3-32bit-portable/perl/vendor/lib/Crypt/R +SA/Key/Private.pm line 127. 13:18 >

    I’m running the latest version (1.99) of Crypt::RSA.

    With a little detective work using eval and Carp, it appears the error is generated by the line:

    $signature = $pss->sign ( Message => $message, Key => $private ) || die $pss->errstr;

    Maybe some other monk knows of a fix or workaround?

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Yikes, you're right, Athanasius! It fails intermittently!

      When I run the script several times consecutively it sometimes fails with the same PARI "forbidden division" error that you point out. I hadn't seen that before.

      Sounds like a bug in Math::Pari, which I had to build in order to build Crypt::RSA :-(

      Thanks for your help and for taking time to try it out. I'll have to figure out some other way of doing this...

Re: Help verifying RSA PSS signature in Perl with Crypt::RSA and Crypt::RSA::SS::PSS
by Anonymous Monk on Mar 31, 2013 at 04:07 UTC

      The bug in Crypt::RSA::Key::Private:SSH that you mention is something I had been wondering about (i.e., how to indicate what cipher to use) so I see now that I'm not the only one.

      I don't believe I can use Crypt::OpenSSL::RSA because there's nothing there that explicitly indicates that it supports PSS. However, I'll keep looking.

      Thanks again!

Re: Help verifying RSA PSS signature in Perl with Crypt::RSA and Crypt::RSA::SS::PSS
by Khen1950fx (Canon) on Mar 31, 2013 at 20:22 UTC
    It verified for me by passing trial division:
    #!/usr/bin/perl -l use strict 'refs'; use warnings FATAL => 'syntax'; use Crypt::RSA::Key; use Crypt::RSA::Key::Public; use Crypt::RSA::Key::Private; use Crypt::RSA::SS::PSS; use Math::Pari qw(PARI); my ($message, $rsa, $pss, $signature, $verify); my ($public, $private); $message = "hello"; $rsa = new Crypt::RSA::Key; ($public, $private) = $rsa->generate( Size => 1024, Verbosity => 2, Filename => "key", ) or die $rsa->errstr(); $pss = new Crypt::RSA::SS::PSS; $signature = $pss->sign( Message => $message, Key => $private, ) || die $pss->errstr; $verify = $pss->verify( Message => $message, Key => $public, Signature => $signature, ) || die $pss->errstr; my $i = 0; foreach $verify(1 .. 10) { print $verify ? "ok" : "not ok"; print " ", ++$i; sleep 1; } my $key = new Crypt::RSA::Key::Public( Filename => "key.public", ); $signature = pack("H*", '03808458..73E92'); foreach $verify(1 .. 10) { print $key ? "ok" : "not ok"; print " ", ++$i; sleep 1; }

      Yes, Khen1950fx, I'm also able to verify most of the time with a key that I generate (as in your example. However, sometimes it fails with the error I posted above. Also, the problem is trying to verify with a public key that I've gotten from another device

      (By the way, my code snippet "$signature = pack("H*", '03808458..73E92'); " was just an example (so I wouldn't have to include the whole hex-string signature)).

        I didn't feel like writing the whole hex-string either:).

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1026320]
Approved by Athanasius
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (5)
As of 2024-04-26 08:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found