File Coverage

lib/Crypt/RSA/SS/PSS.pm
Criterion Covered Total %
statement 87 107 81.3
branch 7 24 29.2
condition 5 21 23.8
subroutine 19 21 90.5
pod 5 11 45.5
total 123 184 66.8


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -sw
2             ##
3             ## Crypt::RSA::SS:PSS
4             ##
5             ## Copyright (c) 2001, Vipul Ved Prakash. All rights reserved.
6             ## This code is free software; you can redistribute it and/or modify
7             ## it under the same terms as Perl itself.
8             ##
9             ## $Id: PSS.pm,v 1.5 2001/06/22 23:27:38 vipul Exp $
10              
11             package Crypt::RSA::SS::PSS;
12 3     3   48 use lib qw(lib);
  3         203  
  3         69  
13 3     3   46 use strict;
  3         27  
  3         47  
14 3     3   40 use vars qw(@ISA $VERSION);
  3         27  
  3         45  
15 3     3   130 use Crypt::RSA::Errorhandler;
  3         30  
  3         58  
16 3     3   47 use Crypt::Random qw(makerandom_octet);
  3         29  
  3         51  
17 3     3   46 use Crypt::RSA::DataFormat qw(octet_len os2ip i2osp octet_xor mgf1);
  3         28  
  3         58  
18 3     3   89 use Crypt::RSA::Primitives;
  3         30  
  3         69  
19 3     3   49 use Crypt::RSA::Debug qw(debug);
  3         30  
  3         51  
20 3     3   47 use Digest::SHA1 qw(sha1);
  3         29  
  3         48  
21 3     3   128 use Math::Pari qw(floor);
  3         28  
  3         48  
22             @ISA = qw(Crypt::RSA::Errorhandler);
23             ($VERSION)  = '$Revision: 1.5 $' =~ /\s(\d+\.\d+)\s/;
24              
25              
26             sub new {
27 3     3 1 215     my ($class, %params) = @_;
28 3         47     my $self = bless { primitives => new Crypt::RSA::Primitives,
29                                    hlen => 20,
30                                    VERSION => $VERSION,
31                                  }, $class;
32 3 50       41     if ($params{Version}) {
33             # do versioning here
34                 }
35 3         47     return $self;
36             }
37              
38              
39             sub sign {
40 208     208 1 4451     my ($self, %params) = @_;
41 208   33     2038     my $key = $params{Key}; my $M = $params{Message} || $params{Plaintext};
  208         2432  
42 208         3391     my $k = octet_len ($key->n);
43 208         5480     my $salt = makerandom_octet (Length => $self->{hlen});
44 208         3326     my $em = $self->encode ($M, $salt, $k-1);
45 208         3164     my $m = os2ip ($em);
46 208         3850     my $sig = $self->{primitives}->core_sign (Key => $key, Message => $m);
47 208         3191     my $S = i2osp ($sig, $k);
48 208 50       2747     return ($S, $salt) if wantarray;
49 208         6079     return $S;
50             }    
51              
52              
53             sub verify_with_salt {
54 0     0 1 0     my ($self, %params) = @_;
55 0   0     0     my $key = $params{Key}; my $M = $params{Message} || $params{Plaintext};
  0         0  
56 0         0     my $S = $params{Signature}; my $salt = $params{Salt};
  0         0  
57 0         0     my $k = octet_len ($key->n);
58 0         0     my $em;
59 0 0       0     unless ($em = $self->encode ($M, $salt, $k-1)) {
60 0 0       0         return if $self->errstr eq "Message too long.";
61 0 0       0         return $self->error ("Modulus too short.", \$M, \$S, \$key, \%params) if
62                     $self->errstr eq "Intended encoded message length too short.";
63                 }
64 0 0       0     return $self->error ("Invalid signature.", \$M, \$S, $key, \%params) if length($S) < $k;
65 0         0     my $s = os2ip ($S);
66 0   0     0     my $m = $self->{primitives}->core_verify (Key => $key, Signature => $s) ||
67                     $self->error ("Invalid signature.", \$M, \$S, $key, \%params);
68 0   0     0     my $em1 = i2osp ($m, $k-1) ||
69                     return $self->error ("Invalid signature.", \$M, \$S, $key, \%params);
70 0 0       0     return 1 if $em eq $em1;
71 0         0     return $self->error ("Invalid signature.", \$M, \$S, $key, \%params);
72             }
73              
74              
75             sub verify {
76 207     207 1 3358     my ($self, %params) = @_;
77 207   33     2153     my $key = $params{Key}; my $M = $params{Message} || $params{Plaintext};
  207         2790  
78 207         1882     my $S = $params{Signature};
79 207         3974     my $k = octet_len ($key->n);
80 207         6300     my $s = os2ip ($S);
81 207   33     3637     my $m = $self->{primitives}->core_verify (Key => $key, Signature => $s) ||
82                     $self->error ("Invalid signature.", \$M, \$S, $key, \%params);
83 207   66     220416     my $em1 = i2osp ($m, $k-1) ||
84                     return $self->error ("Invalid signature.", \$M, \$S, $key, \%params);
85 107 50       1455     return 1 if $self->verify_with_salt_recovery ($M, $em1);
86 0         0     print $self->errstr;
87 0         0     return $self->error ("Invalid signature.", \$M, \$S, $key, \%params);
88             }
89              
90              
91             sub encode {
92 208     208 0 2266     my ($self, $M, $salt, $emlen) = @_;
93 208 50       2482     return $self->error ("Intended encoded message length too short.", \$M, \$salt )
94                     if $emlen < 2 * $self->{hlen};
95 208         2533     my $H = $self->hash ("$salt$M");
96 208         4051     my $padlength = $emlen - (2*$$self{hlen});
97 208         2096     my $PS = chr(0)x$padlength;
98 208         2137     my $db = $salt . $PS;
99 208         2565     my $dbmask = $self->mgf ($H, $emlen - $self->{hlen});
100 208         2506     my $maskeddb = octet_xor ($db, $dbmask);
101 208         215039     my $em = $H . $maskeddb;
102 208         2691     return $em;
103             }
104              
105              
106             sub verify_with_salt_recovery {
107 107     107 0 2802     my ($self, $M, $EM) = @_;
108 107         1056     my $hlen = $$self{hlen};
109 107         1251     my $emlen = length ($EM);
110 107 50       1175     return $self->error ("Encoded message too short.", \$M, \$EM) if $emlen < (2*$hlen);
111 107         1032     my $H = substr $EM, 0, $hlen;
112 107         989     my $maskeddb = substr $EM, $hlen;
113 107         1273     my $dbmask = $self->mgf ($H, $emlen-$hlen);
114 107         1923     my $db = octet_xor ($maskeddb, $dbmask);
115 107         1493     my $salt = substr $db, 0, $hlen;
116 107         1239     my $PS = substr $db, $hlen;
117 107         3735     my $check = chr(0) x ($emlen-(2*$hlen)); debug ("PS: $PS");
  107         1872  
118 107 50       1276     return $self->error ("Inconsistent.") unless $check eq $PS;
119 107         1719     my $H1 = $self->hash ("$salt$M");
120 107 50       3757     return 1 if $H eq $H1;
121 0         0     return $self->error ("Inconsistent.");
122             } 
123              
124              
125             sub hash {
126 315     315 0 3301     my ($self, $data) = @_;
127 315         7405     return sha1 ($data);
128             }
129                 
130              
131             sub mgf {
132 315     315 0 4398     my ($self, @data) = @_;
133 315         4369     return mgf1 (@data);
134             }
135              
136              
137             sub version {
138 3     3 1 30     my $self = shift;
139 3         77     return $self->{VERSION};
140             }
141              
142              
143             sub signblock {
144 0     0 0 0     return -1;
145             }
146              
147              
148             sub verifyblock {
149 4     4 0 92     my ($self, %params) = @_;
150 4         77     return octet_len($params{Key}->n);
151             }
152              
153              
154             1;
155              
156             =head1 NAME
157            
158             Crypt::RSA::SS::PSS - Probabilistic Signature Scheme based on RSA.
159            
160             =head1 SYNOPSIS
161            
162             my $pss = new Crypt::RSA::SS::PSS;
163            
164             my $signature = $pss->sign (
165             Message => $message,
166             Key => $private,
167             ) || die $pss->errstr;
168            
169             my $verify = $pss->verify (
170             Message => $message,
171             Key => $key,
172             Signature => $signature,
173             ) || die $pss->errstr;
174            
175            
176             =head1 DESCRIPTION
177            
178             PSS (Probabilistic Signature Scheme) is a provably secure method of
179             creating digital signatures with RSA. "Provable" means that the
180             difficulty of forging signatures can be directly related to inverting
181             the RSA function. "Probabilistic" alludes to the randomly generated salt
182             value included in the signature to enhance security. For more details
183             on PSS, see [4] & [13].
184            
185             =head1 METHODS
186            
187             =head2 B<new()>
188            
189             Constructor.
190            
191             =head2 B<version()>
192            
193             Returns the version number of the module.
194            
195             =head2 B<sign()>
196            
197             Computes a PSS signature on a message with the private key of the signer.
198             In scalar context, sign() returns the computed signature. In array
199             context, it returns the signature and the random salt. The signature can
200             verified with verify() or verify_with_salt(). sign() takes a hash argument
201             with the following mandatory keys:
202            
203             =over 4
204            
205             =item B<Message>
206            
207             Message to be signed, a string of arbitrary length.
208            
209             =item B<Key>
210            
211             Private key of the signer, a Crypt::RSA::Key::Private object.
212            
213             =back
214            
215             =head2 B<verify()>
216            
217             Verifies a signature generated with sign(). The salt is recovered from the
218             signature and need not be passed. Returns a true value on success and
219             false on failure. $self->errstr is set to "Invalid signature." or
220             appropriate error on failure. verify() takes a hash argument with the
221             following mandatory keys:
222            
223             =over 4
224            
225             =item B<Key>
226            
227             Public key of the signer, a Crypt::RSA::Key::Public object.
228            
229             =item B<Message>
230            
231             The original signed message, a string of arbitrary length.
232            
233             =item B<Signature>
234            
235             Signature computed with sign(), a string.
236            
237             =item B<Version>
238            
239             Version of the module that was used for creating the Signature. This is an
240             optional argument. When present, verify() will ensure before proceeding
241             that the installed version of the module can successfully verify the
242             Signature.
243            
244             =back
245            
246             =head2 B<verify_with_salt()>
247            
248             Verifies a signature given the salt. Takes the same arguments as verify()
249             in addition to B<Salt>, which is a 20-byte string returned by sign() in
250             array context.
251            
252             =head1 ERROR HANDLING
253            
254             See ERROR HANDLING in Crypt::RSA(3) manpage.
255            
256             =head1 BIBLIOGRAPHY
257            
258             See BIBLIOGRAPHY in Crypt::RSA(3) manpage.
259            
260             =head1 AUTHOR
261            
262             Vipul Ved Prakash, E<lt>mail@vipul.netE<gt>
263            
264             =head1 SEE ALSO
265            
266             Crypt::RSA(3), Crypt::RSA::Primitives(3), Crypt::RSA::Keys(3),
267             Crypt::RSA::EME::OAEP(3)
268            
269             =cut
270              
271              
272