File Coverage

lib/Crypt/RSA/Key/Private.pm
Criterion Covered Total %
statement 134 143 93.7
branch 50 70 71.4
condition 18 37 48.6
subroutine 20 20 100.0
pod 8 8 100.0
total 230 278 82.7


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -sw
2             ##
3             ## Crypt::RSA::Key::Private
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: Private.pm,v 1.15 2001/09/25 14:11:22 vipul Exp $
10              
11             package Crypt::RSA::Key::Private;
12 11     11   164 use lib qw(lib);
  11         331  
  11         472  
13 11     11   176 use strict;
  11         98  
  11         195  
14 11     11   153 use vars qw($AUTOLOAD $VERSION);
  11         99  
  11         160  
15 11     11   211 use Crypt::RSA::Errorhandler;
  11         99  
  11         257  
16 11     11   299 use Crypt::RSA;
  11         109  
  11         318  
17 11     11   486 use Tie::EncryptedHash;
  11         113  
  11         247  
18 11     11   230 use Data::Dumper;
  11         106  
  11         217  
19 11     11   176 use Math::Pari qw(PARI pari2pv Mod isprime lcm lift);
  11         104  
  11         208  
20 11     11   269 use Carp;
  11         103  
  11         279  
21 11     11   168 use vars qw(@ISA);
  11         97  
  11         178  
22              
23             ($VERSION) = '$Revision: 1.15 $' =~ /\s(\d+\.\d+)\s/;
24             @ISA       = qw(Crypt::RSA::Errorhandler);
25              
26              
27             sub new {
28              
29 17     17 1 269     my ($class, %params) = @_;
30 17         208     my $self = { Version => $Crypt::RSA::Key::VERSION };
31 17 100       229     if ($params{Filename}) {
32 1         22         bless $self, $class;
33 1         14         $self = $self->read (%params);
34 1         10         return bless $self, $class;
35                 } else {
36 16         353         bless $self, $class;
37 16 100       316         $self->Identity ($params{Identity}) if $params{Identity};
38 16   50     1683         $self->Cipher ($params{Cipher}||"Blowfish");
39 16 50       394         $self->Password ($params{Password}) if $params{Password};
40 16         330         return $self;
41                 }
42              
43             } 
44              
45              
46             sub AUTOLOAD {
47              
48 9026     9026   578167     my ($self, $value) = @_;
49 9026         97751     my $key = $AUTOLOAD; $key =~ s/.*:://;
  9026         108829  
50 9026 100       130020     if ($key =~ /^(e|n|d|p|q|dp|dq|u|phi)$/) {
    100          
    50          
51 8964 100 66     757304         if (ref $value eq 'Math::Pari') {
    100          
52 96         1223             $self->{private}{"_$key"} = $value;
53 96         985             $self->{Checked} = 0;
54                     } elsif ($value && !(ref $value)) {
55 20 50       256             if ($value =~ /^0x/) {
56 0         0                 $self->{private}->{"_$key"} =
57                             $self->{Checked} = 0;
58 0         0                     Math::Pari::_hex_cvt($value);
59 20         391             } else { $self->{private}{"_$key"} = PARI($value) }
60                     }
61 8964   100     2775424         return $self->{private}{"_$key"} ||
      100        
62                            $self->{private_encrypted}{"_$key"} ||
63                            "";
64                 } elsif ($key =~ /^Identity|Cipher|Password$/) {
65 47 100       579         $self->{$key} = $value if $value;
66 47         3172         return $self->{$key};
67                 } elsif ($key =~ /^Checked$/) {
68 15         190         my ($package) = caller();
69 15 50 33     298         $self->{Checked} = $value if ($value && $package eq "Crypt::RSA::Key::Private") ;
70 15         199         return $self->{Checked};
71                 }
72             } 
73              
74              
75             sub hide {
76              
77 2     2 1 19     my ($self) = @_;
78              
79 2 50       24     return undef unless $$self{Password};
80              
81 2         95     $self->{private_encrypted} = new Tie::EncryptedHash
82                         __password => $self->{Password},
83                         __cipher => $self->{Cipher};
84              
85 2         72     for (keys %{$$self{private}}) {
  2         38  
86 4         50         $$self{private_encrypted}{$_} = pari2pv($$self{private}{$_});
87                 }
88              
89 2         110     my $private = $self->{private_encrypted};
90 2         27     delete $private->{__password};
91 2         221     delete $$self{private};
92 2         25     delete $$self{Password};
93              
94             } 
95              
96              
97             sub reveal {
98              
99 3     3 1 40     my ($self, %params) = @_;
100 3 100       106     $$self{Password} = $params{Password} if $params{Password};
101 3 100       34     return undef unless $$self{Password};
102 2         33     $$self{private_encrypted}{__password} = $params{Password};
103 2         136     for (keys %{$$self{private_encrypted}}) {
  2         24  
104 4         57         $$self{private}{$_} = PARI($$self{private_encrypted}{$_});
105                 }
106              
107             }
108              
109              
110             sub check {
111              
112 1104     1104 1 10769     my ($self) = @_;
113              
114 1104 100       16734     return 1 if $self->{Checked};
115              
116 15 50 33     271     return $self->error ("Incomplete key.") unless
      0        
      0        
      33        
117                     ($self->n && $self->d) || ($self->n && $self->p && $self->q);
118              
119 15 100 66     324     if ($self->p && $self->q) {
120 12 50       180         return $self->error ("n is not a number.") if $self->n =~ /\D/;
121 12 50       246         return $self->error ("p is not a number.") if $self->p =~ /\D/;
122 12 50       162         return $self->error ("p is not a number.") if $self->p =~ /\D/;
123 12 50       269         return $self->error ("n is not p*q." ) unless $self->n == $self->p * $self->q;
124 12 50       199         return $self->error ("p is not prime.") unless isprime($self->p);
125 12 50       311         return $self->error ("q is not prime.") unless isprime($self->q);
126                 }
127              
128 15 100       443     if ($self->e) {
129             # d * e == 1 mod lcm(p-1, q-1)
130 12 50       361         return $self->error ("e is not a number.") if $self->e =~ /\D/;
131 12         169         my $k = lcm (($self->p -1), ($self->q -1));
132 12         270         my $K = Mod (1, $k); my $KI = lift($K * $self->d * $self->e);
  12         174  
133 12 50       323         return $self->error ("Bad `d'.") unless $KI == 1;
134                 }
135              
136 15 100       245     if ($self->dp) {
137             # dp == d mod (p-1)
138 12 50       152         return $self->error ("Bad `dp'.") unless $self->dp == $self->d % ($self->p - 1);
139                 }
140              
141 15 100       324     if ($self->dq) {
142             # dq == d mod (q-1)
143 12 50       176         return $self->error ("Bad `dq'.") unless $self->dq == $self->d % ($self->q - 1);
144                 }
145              
146 15 100 66     267     if ($self->u && $self->q && $self->p) {
      66        
147 12         333         my $m = Mod (1,$self->q); $m = lift ($m / $self->p);
  12         166  
148 12 50       261         return $self->error ("Bad `u'.") unless $self->u == $m;
149                 }
150              
151 15         356     $self->Checked(1);
152 15         207     return 1;
153              
154             }
155              
156              
157             sub DESTROY {
158              
159 19     19   235     my $self = shift;
160 19         370     delete $$self{private_encrypted}{__password};
161 19         201     delete $$self{private_encrypted};
162 19         1072     delete $$self{private};
163 19         249     delete $$self{Password};
164 19         419     undef $self;
165              
166             }
167              
168              
169             sub write {
170              
171 1     1 1 12     my ($self, %params) = @_;
172 1         12     $self->hide();
173 1         15     my $string = $self->serialize (%params);
174 1   33     11     open DISK, ">$params{Filename}" ||
175                     croak "Can't open $params{Filename} for writing.";
176 1         4549     binmode DISK;
177 1         81     print DISK $string;
178 1         934     close DISK;
179              
180             } 
181              
182              
183             sub read {
184 1     1 1 12     my ($self, %params) = @_;
185 1 50       55     open DISK, $params{Filename} or
186                     croak "Can't open $params{Filename} to read.";
187 1         11     binmode DISK;
188 1         1351     my @key = <DISK>;
189 1         25     close DISK;
190 1         14     $self = $self->deserialize (String => \@key);
191 1         28     $self->reveal(%params);
192 1         16     return $self;
193             }
194              
195              
196             sub serialize {
197              
198 1     1 1 13     my ($self, %params) = @_;
199 1 50       13     if ($$self{private}) { # this is an unencrypted key
200 0         0         for (keys %{$$self{private}}) {
  0         0  
201 0         0             $$self{private}{$_} = pari2pv($$self{private}{$_});
202                     }
203                 }
204 1         15     return Dumper $self;
205              
206             } 
207              
208              
209             sub deserialize {
210              
211 1     1 1 13     my ($self, %params) = @_;
212 1         15     my $string = join'', @{$params{String}};
  1         17  
213 1         13     $string =~ s/\$VAR1 =//;
214 1         146     $self = eval $string;
215 1 50       16     if ($$self{private}) { # the key is unencrypted
216 0         0         for (keys %{$$self{private}}) {
  0         0  
217 0         0             $$self{private}{$_} = PARI($$self{private}{$_});
218                     }
219 0         0         return $self;
220                 }
221 1         15     my $private = new Tie::EncryptedHash;
222 1         72     %$private = %{$$self{private_encrypted}};
  1         13  
223 1         167     $self->{private_encrypted} = $private;
224 1         11     return $self;
225              
226             }
227              
228              
229             1;
230              
231             =head1 NAME
232            
233             Crypt::RSA::Key::Private -- RSA Private Key Management.
234            
235             =head1 SYNOPSIS
236            
237             $key = new Crypt::RSA::Key::Private (
238             Identity => 'Lord Banquo <banquo@lochaber.com>',
239             Password => 'The earth hath bubbles',
240             );
241            
242             $key->hide();
243            
244             $key->write( Filename => 'rsakeys/banquo.private' );
245            
246             $akey = new Crypt::RSA::Key::Private (
247             Filename => 'rsakeys/banquo.private'
248             );
249            
250             $akey->reveal ( Password => 'The earth hath bubbles' );
251            
252             =head1 DESCRIPTION
253            
254             Crypt::RSA::Key::Private provides basic private key management
255             functionality for Crypt::RSA private keys. Following methods are
256             available:
257            
258             =over 4
259            
260             =item B<new()>
261            
262             The constructor. Takes a hash, usually with two arguments: C<Filename> and
263             C<Password>. C<Filename> indicates a file from which the private key
264             should be read. More often than not, private keys are kept encrypted with
265             a symmetric cipher and MUST be decrypted before use. When a C<Password>
266             argument is provided, the key is also decrypted before it is returned by
267             C<new()>. Here's a complete list of arguments accepted by C<new()> (all of
268             which are optional):
269            
270             =over 4
271            
272             =item Identity
273            
274             A string identifying the owner of the key. Canonically, a name and
275             email address.
276            
277             =item Filename
278            
279             Name of the file that contains the private key.
280            
281             =item Password
282            
283             Password with which the private key is encrypted, or should be encrypted
284             (in case of a new key).
285            
286             =item Cipher
287            
288             Name of the symmetric cipher in which the private key is encrypted (or
289             should be encrypted). The default is "Blowfish" and possible values
290             include DES, IDEA, Twofish and other ciphers supported by Crypt::CBC.
291            
292             =back
293            
294             =item B<reveal()>
295            
296             If the key is not decrypted at C<new()>, it can be decrypted by
297             calling C<reveal()> with a C<Password> argument.
298            
299             =item B<hide()>
300            
301             C<hide()> causes the key to be encrypted by the chosen symmetric cipher
302             and password.
303            
304             =item B<write()>
305            
306             Causes the key to be written to a disk file specified by the
307             C<Filename> argument. C<write()> will call C<hide()> before
308             writing the key to disk. If you wish to store the key in plain,
309             don't specify a password at C<new()>.
310