File Coverage

lib/Crypt/RSA/Key.pm
Criterion Covered Total %
statement 77 81 95.1
branch 12 20 60.0
condition 16 26 61.5
subroutine 13 13 100.0
pod 2 3 66.7
total 120 143 83.9


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -sw
2             ##
3             ## Crypt::RSA::Keys
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: Key.pm,v 1.13 2001/05/25 00:20:40 vipul Exp $
10              
11             package Crypt::RSA::Key;
12 11     11   186 use lib qw(lib);
  11         160  
  11         171  
13 11     11   175 use strict;
  11         170  
  11         167  
14 11     11   152 use vars qw(@ISA $VERSION);
  11         183  
  11         165  
15 11     11   289 use Class::Loader;
  11         114  
  11         293  
16 11     11   445 use Crypt::RSA::Errorhandler;
  11         109  
  11         181  
17 11     11   471 use Crypt::Primes qw(rsaparams);
  11         199  
  11         398  
18 11     11   699 use Crypt::RSA::DataFormat qw(bitsize);
  11         2231  
  11         289  
19 11     11   176 use Math::Pari qw(PARI Mod lift);
  11         99  
  11         172  
20 11     11   2936 use Crypt::RSA::Key::Private;
  11         164  
  11         419  
21 11     11   411 use Crypt::RSA::Key::Public;
  11         205  
  11         278  
22             @ISA = qw(Class::Loader Crypt::RSA::Errorhandler);
23              
24              
25             ($VERSION)  = '$Revision: 1.91 $' =~ /\s(\d+\.\d+)\s/;
26              
27              
28             my %MODMAP = (
29                 Native_PKF => { Module => "Crypt::RSA::Key::Public" },
30                 Native_SKF => { Module => "Crypt::RSA::Key::Private" },
31                    SSH_PKF => { Module => "Crypt::RSA::Key::Public::SSH" },
32                    SSH_SKF => { Module => "Crypt::RSA::Key::Private::SSH" },
33             );
34              
35              
36             sub new {
37 8     8 1 206     my $class = shift;
38 8         105     my $self = {};
39 8         254     bless $self, $class;
40 8         178     $self->_storemap ( %MODMAP );
41 8         462     return $self;
42             }
43              
44              
45             sub generate {
46              
47 12     12 1 2961     my ($self, %params) = @_;
48              
49 12         119     my $key;
50 12 100 66     218     unless ($params{q} && $params{p} && $params{e}) {
      66        
51              
52 11 50       125         return $self->error ("Missing argument.") unless $params{Size};
53              
54 11 50       154         return $self->error ("Keysize too small.") if
55                         $params{Size} < 48;
56              
57 11 50       134         return $self->error ("Odd keysize.") if
58                         $params{Size} % 2;
59              
60 11         126         my $size = int($params{Size}/2);
61 11   100     128         my $verbosity = $params{Verbosity} || 0;
62              
63 11         103         my $cbitsize = 0;
64 11         126         while (!($cbitsize)) {
65 18         922             $key = rsaparams ( Size => $size, Verbosity => $verbosity );
66 18         273354             my $n = $$key{p} * $$key{q};
67 18 100       325             $cbitsize = 1 if bitsize($n) == $params{Size}
68                     }
69              
70                 }
71              
72 12 50       1209     if ($params{KF}) {
73 0         0         $params{PKF} = { Name => "$params{KF}_PKF" };
74 0         0         $params{SKF} = { Name => "$params{KF}_SKF" }
75                 }
76              
77 12 50       195     my $pubload = $params{PKF} ? $params{PKF} : { Name => "Native_PKF" };
78 12 50       163     my $priload = $params{SKF} ? $params{SKF} : { Name => "Native_SKF" };
79              
80 12   33     365     my $pubkey = $self->_load (%$pubload) ||
81                     return $self->error ("Couldn't load the public key module.");
82 12   33     450     my $prikey = $self->_load ((%$priload), Args => ['Password', $params{Password} ]) ||
83                     return $self->error ("Couldn't load the private key module.");
84 12         584     $pubkey->Identity ($params{Identity});
85 12         338     $prikey->Identity ($params{Identity});
86              
87 12   66     329     $pubkey->e ($$key{e} || $params{e});
88 12   66     322     $prikey->e ($$key{e} || $params{e});
89 12   66     340     $prikey->p ($$key{p} || $params{p});
90 12   66     5087     $prikey->q ($$key{q} || $params{q});
91              
92 12         274     $prikey->phi (($prikey->p - 1) * ($prikey->q - 1));
93 12         297     my $m = Mod (1, $prikey->phi);
94              
95 12         208     $prikey->d (lift($m/$pubkey->e));
96 12         266     $prikey->n ($prikey->p * $prikey->q);
97 12         264     $pubkey->n ($prikey->n);
98              
99 12         169     $prikey->dp ($prikey->d % ($prikey->p - 1));
100 12         252     $prikey->dq ($prikey->d % ($prikey->q - 1));
101 12         227     $prikey->u (mod_inverse($prikey->p, $prikey->q));
102              
103 12 50       412     return $self->error ("d is too small. Regenerate.") if
104                     bitsize($prikey->d) < 0.25 * bitsize($prikey->n);
105              
106 12         288     $$key{p} = 0; $$key{q} = 0; $$key{e} = 0; $m = 0;
  12         152  
  12         140  
  12         112  
107              
108 12 50       186     if ($params{Filename}) {
109 0         0         $pubkey->write (Filename => "$params{Filename}.public");
110 0         0         $prikey->write (Filename => "$params{Filename}.private");
111                 }
112              
113 12         1461     return ($pubkey, $prikey);
114              
115             }
116              
117              
118             sub mod_inverse {
119 12     12 0 143     my($a, $n) = @_;
120 12         252     my $m = Mod(1, $n);
121 12         1039     lift($m / $a);
122             }
123              
124              
125             1;
126              
127             =head1 NAME
128            
129             Crypt::RSA::Key - RSA Key Pair Generator.
130            
131             =head1 SYNOPSIS
132            
133             my $keychain = new Crypt::RSA::Key;
134             my ($public, $private) = $keychain->generate (
135             Identity => 'Lord Macbeth <macbeth@glamis.com>',
136             Size => 2048,
137             Password => 'A day so foul & fair',
138             Verbosity => 1,
139             ) or die $keychain->errstr();
140            
141             =head1 DESCRIPTION
142            
143             This module provides a method to generate an RSA key pair.
144            
145             =head1 METHODS
146            
147             =head2 new()
148            
149             Constructor.
150            
151             =head2 generate()
152            
153             generate() generates an RSA key of specified bitsize. It returns a list of
154             two elements, a Crypt::RSA::Key::Public object that holds the public part
155             of the key pair and a Crypt::RSA::Key::Private object that holds that
156             private part. On failure, it returns undef and sets $self->errstr to
157             appropriate error string. generate() takes a hash argument with the
158             following keys:
159            
160             =over 4
161            
162             =item B<Size>
163            
164             Bitsize of the key to be generated. This should be an even integer > 48.
165             Bitsize is a mandatory argument.
166            
167             =item B<Password>
168            
169             String with which the private key will be encrypted. If Password is not
170             provided the key will be stored unencrypted.
171            
172             =item B<Identity>
173            
174             A string that identifies the owner of the key. This string usually takes
175             the form of a name and an email address. The identity is not bound to the
176             key with a signature. However, a future release or another module will
177             provide this facility.
178            
179             =item B<Cipher>
180            
181             The block cipher which is used for encrypting the private key. Defaults to
182             `Blowfish'. Cipher could be set to any value that works with Crypt::CBC(3)
183             and Tie::EncryptedHash(3).
184            
185             =item B<Verbosity>
186            
187             When set to 1, generate() will draw a progress display on STDOUT.
188            
189             =item B<Filename>
190            
191             The generated key pair will be written to disk, in $Filename.public and
192             $Filename.private files, if this argument is provided. Disk writes can be
193             deferred by skipping this argument and achieved later with the write()
194             method of Crypt::RSA::Key::Public(3) and Crypt::RSA::Key::Private(3).
195            
196             =item B<KF>
197            
198             A string that specifies the key format. As of this writing, two key
199             formats, `Native' and `SSH', are supported. KF defaults to `Native'.
200            
201             =item B<SKF>
202            
203             Secret (Private) Key Format. Instead of specifying KF, the user could
204             choose to specify secret and public key formats separately. The value for
205             SKF can be a string ("Native" or "SSH") or a hash reference that specifies
206             a module name, its constructor and constructor arguments. The specified
207             module is loaded with Class::Loader(3) and must be interface compatible
208             with Crypt::RSA::Key::Private(3).
209            
210             =item B<PKF>
211            
212             Public Key Format. This option is like SKF but for the public key.
213            
214             =back
215            
216             =head1 ERROR HANDLING
217            
218             See B<ERROR HANDLING> in Crypt::RSA(3) manpage.
219            
220             =head1 BUGS
221            
222             There's an inefficiency in the way generate() ensures the key pair is
223             exactly Size bits long. This will be fixed in a future release.
224            
225             =head1 AUTHOR
226            
227             Vipul Ved Prakash, E<lt>mail@vipul.netE<gt>
228            
229             =head1 SEE ALSO
230            
231             Crypt::RSA(3), Crypt::RSA::Key::Public(3), Crypt::RSA::Key::Private(3),
232             Crypt::Primes(3), Tie::EncryptedHash(3), Class::Loader(3)
233            
234             =cut
235              
236              
237