File Coverage

blib/lib/Crypt/RSA/Key.pm
Criterion Covered Total %
statement 66 96 68.7
branch 6 30 20.0
condition 8 26 30.7
subroutine 13 14 92.8
pod 2 2 100.0
total 95 168 56.5


line stmt bran cond sub pod time code
1             package Crypt::RSA::Key;
2 4     4   39624 use strict;
  4         9  
  4         103  
3 4     4   20 use warnings;
  4         7  
  4         155  
4              
5             ## Crypt::RSA::Keys
6             ##
7             ## Copyright (c) 2001, Vipul Ved Prakash. All rights reserved.
8             ## This code is free software; you can redistribute it and/or modify
9             ## it under the same terms as Perl itself.
10              
11 4     4   18 use base 'Class::Loader';
  4         15  
  4         2584  
12 4     4   35910 use base 'Crypt::RSA::Errorhandler';
  4         11  
  4         1514  
13 4     4   6713 use Math::Prime::Util qw(prime_set_config random_nbit_prime is_strong_pseudoprime primes);
  4         41826  
  4         18  
14 4     4   3311 use Bytes::Random::Secure qw(random_bytes);
  4         32271  
  4         220  
15 4     4   1514 use Crypt::RSA::DataFormat qw(bitsize);
  4         15  
  4         228  
16 4     4   20 use Math::BigInt try => 'GMP, Pari';
  4         9  
  4         28  
17 4     4   6715 use Crypt::RSA::Key::Private;
  4         11  
  4         126  
18 4     4   2371 use Crypt::RSA::Key::Public;
  4         9  
  4         92  
19 4     4   21 use Carp;
  4         8  
  4         3502  
20              
21             $Crypt::RSA::Key::VERSION = '1.99';
22              
23             my %MODMAP = (
24             Native_PKF => { Module => "Crypt::RSA::Key::Public" },
25             Native_SKF => { Module => "Crypt::RSA::Key::Private" },
26             SSH_PKF => { Module => "Crypt::RSA::Key::Public::SSH" },
27             SSH_SKF => { Module => "Crypt::RSA::Key::Private::SSH" },
28             );
29              
30              
31             sub new {
32 2     2 1 18 my $class = shift;
33 2         48 my $self = {};
34             # Use one BRS object per key object. It should be ok to re-use between
35             # keys, since BRS is a CSPRNG. We could share one BRS object between all
36             # objects which would be a bit more efficient (that would be similar to
37             # using BRS's functional interface).
38 2         23 $self->{RandomObject} = Bytes::Random::Secure->new( Bits => 256 );
39 2         173 bless $self, $class;
40 2         31 $self->_storemap ( %MODMAP );
41 2         36 return $self;
42             }
43              
44              
45             sub generate {
46              
47 1     1 1 11 my ($self, %params) = @_;
48              
49 1         3 my $key;
50 1 50 33     14 unless ($params{q} && $params{p} && $params{e}) {
      33        
51              
52 0 0       0 return $self->error ("Missing argument.") unless $params{Size};
53              
54             return $self->error ("Keysize too small.") if
55 0 0       0 $params{Size} < 48;
56              
57             return $self->error ("Odd keysize.") if
58 0 0       0 $params{Size} % 2;
59              
60 0         0 my $size = int($params{Size}/2);
61 0   0     0 my $verbosity = $params{Verbosity} || 0;
62              
63 0         0 my $randobj = $self->{RandomObject};
64 0   0 0   0 my $randsub = $params{RandomSub} || sub { $randobj->irand() };
  0            
65 0 0       0 return $self->error("RandomSub must be a CODE reference.")
66             unless ref($randsub) eq 'CODE';
67 0         0 prime_set_config( irand => $randsub );
68              
69             # Switch from Maurer prime to nbit prime, then add some more primality
70             # testing. This is faster and gives us a wider set of possible primes.
71 0         0 my @prplist = @{primes( 200 )};
  0         0  
72              
73 0         0 while (1) {
74 0         0 my $p = random_nbit_prime($size);
75 0         0 my $q = random_nbit_prime($size);
76 0 0       0 $p = Math::BigInt->new("$p") unless ref($p) eq 'Math::BigInt';
77 0 0       0 $q = Math::BigInt->new("$q") unless ref($q) eq 'Math::BigInt';
78              
79 0 0       0 next unless bitsize($p * $q) == $params{Size};
80              
81             # p and q have passed the strong BPSW test, so it would be shocking
82             # if they were not prime. We'll add a few more tests because they're
83             # cheap and we want to be extra careful, but also don't want to spend
84             # the time doing a full primality proof. The results will have
85             # passed BPSW as well as being strong pseudoprimes to the first 46
86             # prime bases.
87 0 0       0 do { carp "$p passes BPSW but fails pseudoprime tests!"; next; }
  0         0  
  0         0  
88             unless is_strong_pseudoprime($p, @prplist);
89 0 0       0 do { carp "$q passes BPSW but fails pseudoprime tests!"; next; }
  0         0  
  0         0  
90             unless is_strong_pseudoprime($q, @prplist);
91              
92             # We could add some more conditions here. Possibilities:
93             # - make sure |p-q| is large enough. With large bit sizes this is
94             # exceedingly unlikely, but we could easily double check.
95             # - run some trivial factoring tests, or check the smoothness of
96             # p-1 and q-1. Using random_strong_prime could also do this.
97              
98 0         0 $key = { p => $p, q => $q, e => Math::BigInt->new(65537) };
99 0         0 last;
100             }
101             }
102              
103 1 50       4 if ($params{KF}) {
104 0         0 $params{PKF} = { Name => "$params{KF}_PKF" };
105 0         0 $params{SKF} = { Name => "$params{KF}_SKF" }
106             }
107              
108 1 50       7 my $pubload = $params{PKF} ? $params{PKF} : { Name => "Native_PKF" };
109 1 50       4 my $priload = $params{SKF} ? $params{SKF} : { Name => "Native_SKF" };
110              
111 1   50     10 my $pubkey = $self->_load (%$pubload) ||
112             return $self->error ("Couldn't load the public key module: $@");
113 1   50     22 my $prikey = $self->_load ((%$priload), Args => ['Cipher' => $params{Cipher}, 'Password' => $params{Password} ]) ||
114             return $self->error ("Couldn't load the private key module: $@");
115 1         22 $pubkey->Identity ($params{Identity});
116 1         10 $prikey->Identity ($params{Identity});
117              
118 1   33     13 $pubkey->e ($$key{e} || $params{e});
119 1   33     12 $prikey->e ($$key{e} || $params{e});
120 1   33     17 $prikey->p ($$key{p} || $params{p});
121 1   33     17 $prikey->q ($$key{q} || $params{q});
122              
123 1         6 $prikey->phi ( ($prikey->p - 1) * ($prikey->q - 1) );
124              
125 1         9 $prikey->d ( ($pubkey->e)->copy->bmodinv($prikey->phi) );
126 1         7 $prikey->n ( $prikey->p * $prikey->q );
127 1         7 $pubkey->n ( $prikey->n );
128              
129 1         5 $prikey->dp ($prikey->d % ($prikey->p - 1));
130 1         7 $prikey->dq ($prikey->d % ($prikey->q - 1));
131 1         7 $prikey->u ( ($prikey->p)->copy->bmodinv($prikey->q) );
132              
133 1 50       6 return $self->error ("d is too small. Regenerate.") if
134             bitsize($prikey->d) < 0.25 * bitsize($prikey->n);
135              
136 1         4 $$key{p} = 0; $$key{q} = 0; $$key{e} = 0;
  1         2  
  1         3  
137              
138 1 50       4 if ($params{Filename}) {
139 0         0 $pubkey->write (Filename => "$params{Filename}.public");
140 0         0 $prikey->write (Filename => "$params{Filename}.private");
141             }
142              
143 1         7 return ($pubkey, $prikey);
144              
145             }
146              
147             1;
148              
149             =head1 NAME
150              
151             Crypt::RSA::Key - RSA Key Pair Generator.
152              
153             =head1 SYNOPSIS
154              
155             my $keychain = new Crypt::RSA::Key;
156             my ($public, $private) = $keychain->generate (
157             Identity => 'Lord Macbeth ',
158             Size => 2048,
159             Password => 'A day so foul & fair',
160             Verbosity => 1,
161             ) or die $keychain->errstr();
162              
163             =head1 DESCRIPTION
164              
165             This module provides a method to generate an RSA key pair.
166              
167             =head1 METHODS
168              
169             =head2 new()
170              
171             Constructor.
172              
173             =head2 generate()
174              
175             generate() generates an RSA key of specified bitsize. It returns a list of
176             two elements, a Crypt::RSA::Key::Public object that holds the public part
177             of the key pair and a Crypt::RSA::Key::Private object that holds that
178             private part. On failure, it returns undef and sets $self->errstr to
179             appropriate error string. generate() takes a hash argument with the
180             following keys:
181              
182             =over 4
183              
184             =item B
185              
186             Bitsize of the key to be generated. This should be an even integer > 48.
187             Bitsize is a mandatory argument.
188              
189             =item B
190              
191             String with which the private key will be encrypted. If Password is not
192             provided the key will be stored unencrypted.
193              
194             =item B
195              
196             A string that identifies the owner of the key. This string usually takes
197             the form of a name and an email address. The identity is not bound to the
198             key with a signature. However, a future release or another module will
199             provide this facility.
200              
201             =item B
202              
203             The block cipher which is used for encrypting the private key. Defaults to
204             `Blowfish'. Cipher could be set to any value that works with Crypt::CBC(3)
205             and Tie::EncryptedHash(3).
206              
207             =item B
208              
209             When set to 1, generate() will draw a progress display on STDOUT.
210              
211             =item B
212              
213             The generated key pair will be written to disk, in $Filename.public and
214             $Filename.private files, if this argument is provided. Disk writes can be
215             deferred by skipping this argument and achieved later with the write()
216             method of Crypt::RSA::Key::Public(3) and Crypt::RSA::Key::Private(3).
217              
218             =item B
219              
220             A string that specifies the key format. As of this writing, two key
221             formats, `Native' and `SSH', are supported. KF defaults to `Native'.
222              
223             =item B
224              
225             Secret (Private) Key Format. Instead of specifying KF, the user could
226             choose to specify secret and public key formats separately. The value for
227             SKF can be a string ("Native" or "SSH") or a hash reference that specifies
228             a module name, its constructor and constructor arguments. The specified
229             module is loaded with Class::Loader(3) and must be interface compatible
230             with Crypt::RSA::Key::Private(3).
231              
232             =item B
233              
234             Public Key Format. This option is like SKF but for the public key.
235              
236             =item B
237              
238             A code reference that returns a 32-bit random number when called. This will
239             be used to generate random data for selecting the random primes needed for key
240             generation. The default source is almost always a good choice so you should
241             never need to use this parameter for normal use. It is specifically available
242             for special needs such as selecting a non-blocking seed source for tests.
243              
244             =back
245              
246             =head1 ERROR HANDLING
247              
248             See B in Crypt::RSA(3) manpage.
249              
250             =head1 BUGS
251              
252             There's an inefficiency in the way generate() ensures the key pair is
253             exactly Size bits long. This will be fixed in a future release.
254              
255             =head1 AUTHOR
256              
257             Vipul Ved Prakash, Email@vipul.netE
258              
259             =head1 SEE ALSO
260              
261             Crypt::RSA(3), Crypt::RSA::Key::Public(3), Crypt::RSA::Key::Private(3),
262             Tie::EncryptedHash(3), Class::Loader(3),
263             Math::Prime::Util(3)
264              
265             =cut
266              
267