File Coverage

blib/lib/Crypt/RSA/Key/Private.pm
Criterion Covered Total %
statement 144 145 99.3
branch 59 80 73.7
condition 10 26 38.4
subroutine 19 19 100.0
pod 8 8 100.0
total 240 278 86.3


line stmt bran cond sub pod time code
1             package Crypt::RSA::Key::Private;
2 13     13   15256 use strict;
  13         29  
  13         310  
3 13     13   60 use warnings;
  13         28  
  13         337  
4              
5             ## Crypt::RSA::Key::Private
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 13     13   58 use vars qw($AUTOLOAD $VERSION);
  13         25  
  13         493  
12 13     13   63 use base 'Crypt::RSA::Errorhandler';
  13         30  
  13         1062  
13 13     13   5173 use Tie::EncryptedHash;
  13         74741  
  13         1225  
14 13     13   94 use Data::Dumper;
  13         28  
  13         515  
15 13     13   1021 use Math::BigInt try => 'GMP, Pari';
  13         20354  
  13         126  
16 13     13   28780 use Math::Prime::Util qw/is_prime/;
  13         9221  
  13         95  
17 13     13   738 use Carp;
  13         33  
  13         16067  
18              
19             $Crypt::RSA::Key::Private::VERSION = '1.99';
20              
21             sub new {
22              
23 20     20 1 4561 my ($class, %params) = @_;
24 20         81 my $self = { Version => $Crypt::RSA::Key::Private::VERSION };
25 20 100       80 if ($params{Filename}) {
26 1         3 bless $self, $class;
27 1         5 $self = $self->read (%params);
28 1         3 return bless $self, $class;
29             } else {
30 19         57 bless $self, $class;
31 19 100       110 $self->Identity ($params{Identity}) if $params{Identity};
32 19   50     274 $self->Cipher ($params{Cipher}||"Blowfish");
33 19 100       167 $self->Password ($params{Password}) if $params{Password};
34 19         142 return $self;
35             }
36              
37             }
38              
39              
40             sub AUTOLOAD {
41              
42 4766     4766   466847 my ($self, $value) = @_;
43 4766         7486 my $key = $AUTOLOAD; $key =~ s/.*:://;
  4766         14762  
44 4766 100       15991 if ($key =~ /^(e|n|d|p|q|dp|dq|u|phi)$/) {
    100          
    50          
45 4695         11380 my $prikey = \$self->{private}{"_$key"};
46 4695 100       10923 if (defined $value) {
47 154         276 $self->{Checked} = 0;
48 154 100       380 if (ref $value eq 'Math::BigInt') {
    50          
49 145         275 $$prikey = $value;
50             } elsif (ref $value eq 'Math::Pari') {
51 0         0 $$prikey = Math::BigInt->new($value->pari2pv);
52             } else {
53 9         57 $$prikey = Math::BigInt->new("$value");
54             }
55             }
56 4695 100       11269 if (defined $$prikey) {
57 4656 100       11395 $$prikey = Math::BigInt->new("$$prikey") unless ref($$prikey) eq 'Math::BigInt';
58 4656         15657 return $$prikey;
59             }
60 39 100       137 return $self->{private_encrypted}{"_$key"} if defined $self->{private_encrypted}{"_$key"};
61 35         149 return;
62             } elsif ($key =~ /^Identity|Cipher|Password$/) {
63 57 100       230 $self->{$key} = $value if $value;
64 57         145 return $self->{$key};
65             } elsif ($key =~ /^Checked$/) {
66 14         74 my ($package) = caller();
67 14 50 33     123 $self->{Checked} = $value if ($value && $package eq "Crypt::RSA::Key::Private") ;
68 14         43 return $self->{Checked};
69             }
70             }
71              
72              
73             sub hide {
74              
75 2     2 1 15 my ($self) = @_;
76              
77 2 50       7 return unless $$self{Password};
78              
79             $self->{private_encrypted} = new Tie::EncryptedHash
80             __password => $self->{Password},
81 2         13 __cipher => $self->{Cipher};
82              
83 2         158 for (keys %{$$self{private}}) {
  2         9  
84 4         4996 $$self{private_encrypted}{$_} = $$self{private}{$_}->bstr;
85             }
86              
87 2         3222 my $private = $self->{private_encrypted};
88 2         10 delete $private->{__password};
89 2         92 delete $$self{private};
90 2         5 delete $$self{Password};
91              
92             # Mark ourselves as hidden
93 2         6 $self->{Hidden} = 1;
94             }
95              
96              
97             sub reveal {
98              
99 3     3 1 1014 my ($self, %params) = @_;
100 3 100       10 $$self{Password} = $params{Password} if $params{Password};
101 3 100       11 return unless $$self{Password};
102 2         11 $$self{private_encrypted}{__password} = $params{Password};
103 2         59 for (keys %{$$self{private_encrypted}}) {
  2         10  
104 4         5218 $$self{private}{$_} = Math::BigInt->new("$$self{private_encrypted}{$_}");
105             }
106 2         1813 $self->{Hidden} = 0;
107              
108             }
109              
110              
111             sub check {
112              
113 559     559 1 7049 my ($self) = @_;
114              
115 559 100       3167 return 1 if $self->{Checked};
116              
117             return $self->error ("Cannot check hidden key - call reveal first.")
118 14 50       68 if $self->{Hidden};
119              
120 14 0 33     105 return $self->error ("Incomplete key.") unless
      0        
      0        
      33        
121             ($self->n && $self->d) || ($self->n && $self->p && $self->q);
122              
123 14 100 66     569 if ($self->p && $self->q) {
124 11 50       407 return $self->error ("n is not a number.") if $self->n =~ /\D/;
125 11 50       614 return $self->error ("p is not a number.") if $self->p =~ /\D/;
126 11 50       405 return $self->error ("q is not a number.") if $self->q =~ /\D/;
127 11 50       403 return $self->error ("n is not p*q." ) unless $self->n == $self->p * $self->q;
128 11 50       5653 return $self->error ("p is not prime.") unless is_prime( $self->p );
129 11 50       13560902 return $self->error ("q is not prime.") unless is_prime( $self->q );
130             }
131              
132 14 100       13643623 if ($self->e) {
133             # d * e == 1 mod lcm(p-1, q-1)
134 11 50       396 return $self->error ("e is not a number.") if $self->e =~ /\D/;
135 11         360 my $k = Math::BigInt::blcm($self->p-1, $self->q-1);
136 11         238885 my $KI = ($self->e)->copy->bmul($self->d)->bmodinv($k);
137 11 50       8041 return $self->error ("Bad `d'.") unless $KI == 1;
138             }
139              
140 14 100       1633 if ($self->dp) {
141             # dp == d mod (p-1)
142 11 50       329 return $self->error ("Bad `dp'.") unless $self->dp == $self->d % ($self->p - 1);
143             }
144              
145 14 100       10674 if ($self->dq) {
146             # dq == d mod (q-1)
147 11 50       320 return $self->error ("Bad `dq'.") unless $self->dq == $self->d % ($self->q - 1);
148             }
149              
150 14 50 66     10618 if ($self->u && $self->q && $self->p) {
      66        
151 11         439 my $m = ($self->p)->copy->bmodinv($self->q);
152 11 50       310493 return $self->error ("Bad `u'.") unless $self->u == $m;
153             }
154              
155 14         954 $self->Checked(1);
156 14         88 return 1;
157              
158             }
159              
160              
161             sub DESTROY {
162              
163 23     23   17749 my $self = shift;
164 23         82 delete $$self{private_encrypted}{__password};
165 23         141 delete $$self{private_encrypted};
166 23         321 delete $$self{private};
167 23         58 delete $$self{Password};
168 23         201 undef $self;
169              
170             }
171              
172              
173             sub write {
174              
175 1     1 1 4 my ($self, %params) = @_;
176 1         5 $self->hide();
177 1         5 my $string = $self->serialize (%params);
178 1 50       435 open(my $disk, '>', $params{Filename}) or
179             croak "Can't open $params{Filename} for writing.";
180 1         5 binmode $disk;
181 1         10 print $disk $string;
182 1         42 close $disk;
183              
184             }
185              
186              
187             sub read {
188 1     1 1 4 my ($self, %params) = @_;
189 1 50       25 open(my $disk, '<', $params{Filename}) or
190             croak "Can't open $params{Filename} to read.";
191 1         4 binmode $disk;
192 1         18 my @key = <$disk>;
193 1         7 close $disk;
194 1         6 $self = $self->deserialize (String => \@key);
195 1         5 $self->reveal(%params);
196 1         5 return $self;
197             }
198              
199              
200             sub serialize {
201              
202 2     2 1 768 my ($self, %params) = @_;
203 2 100       11 if ($$self{private}) { # this is an unencrypted key
204 1         3 for (keys %{$$self{private}}) {
  1         5  
205 9         244 $$self{private}{$_} = ($$self{private}{$_})->bstr;
206             }
207             }
208 2         33 return Dumper $self;
209              
210             }
211              
212              
213             sub deserialize {
214              
215 2     2 1 98 my ($self, %params) = @_;
216 2         5 my $string = join'', @{$params{String}};
  2         10  
217 2         11 $string =~ s/\$VAR1 =//;
218 2         160 $self = eval $string;
219 2 100       12 if ($$self{private}) { # the key is unencrypted
220 1         2 for (keys %{$$self{private}}) {
  1         5  
221 9         392 $$self{private}{$_} = Math::BigInt->new("$$self{private}{$_}");
222             }
223 1         56 return $self;
224             }
225 1         5 my $private = new Tie::EncryptedHash;
226 1         47 %$private = %{$$self{private_encrypted}};
  1         6  
227 1         90 $self->{private_encrypted} = $private;
228 1         4 return $self;
229              
230             }
231              
232              
233             1;
234              
235             =head1 NAME
236              
237             Crypt::RSA::Key::Private -- RSA Private Key Management.
238              
239             =head1 SYNOPSIS
240              
241             $key = new Crypt::RSA::Key::Private (
242             Identity => 'Lord Banquo ',
243             Password => 'The earth hath bubbles',
244             );
245              
246             $key->hide();
247              
248             $key->write( Filename => 'rsakeys/banquo.private' );
249              
250             $akey = new Crypt::RSA::Key::Private (
251             Filename => 'rsakeys/banquo.private'
252             );
253              
254             $akey->reveal ( Password => 'The earth hath bubbles' );
255              
256             =head1 DESCRIPTION
257              
258             Crypt::RSA::Key::Private provides basic private key management
259             functionality for Crypt::RSA private keys. Following methods are
260             available:
261              
262             =over 4
263              
264             =item B
265              
266             The constructor. Takes a hash, usually with two arguments: C and
267             C. C indicates a file from which the private key
268             should be read. More often than not, private keys are kept encrypted with
269             a symmetric cipher and MUST be decrypted before use. When a C
270             argument is provided, the key is also decrypted before it is returned by
271             C. Here's a complete list of arguments accepted by C (all of
272             which are optional):
273              
274             =over 4
275              
276             =item Identity
277              
278             A string identifying the owner of the key. Canonically, a name and
279             email address.
280              
281             =item Filename
282              
283             Name of the file that contains the private key.
284              
285             =item Password
286              
287             Password with which the private key is encrypted, or should be encrypted
288             (in case of a new key).
289              
290             =item Cipher
291              
292             Name of the symmetric cipher in which the private key is encrypted (or
293             should be encrypted). The default is "Blowfish" and possible values
294             include DES, IDEA, Twofish and other ciphers supported by Crypt::CBC.
295              
296             =back
297              
298             =item B
299              
300             If the key is not decrypted at C, it can be decrypted by
301             calling C with a C argument.
302              
303             =item B
304              
305             C causes the key to be encrypted by the chosen symmetric cipher
306             and password.
307              
308             =item B
309              
310             Causes the key to be written to a disk file specified by the
311             C argument. C will call C before
312             writing the key to disk. If you wish to store the key in plain,
313             don't specify a password at C.
314              
315             =item B
316              
317             Causes the key to be read from a disk file specified by
318             C into the object. If C is provided, the
319             method automatically calls reveal() to decrypt the key.
320              
321             =item B
322              
323             Creates a Data::Dumper(3) serialization of the private key and
324             returns the string representation.
325              
326             =item B
327              
328             Accepts a serialized key under the C parameter and
329             coverts it into the perl representation stored in the object.
330              
331             =item C
332              
333             Check the consistency of the key. If the key checks out, it sets
334             $self->{Checked} = 1. Returns undef on failure.
335              
336             =back
337              
338             =head1 AUTHOR
339              
340             Vipul Ved Prakash, Email@vipul.netE
341              
342             =head1 SEE ALSO
343              
344             Crypt::RSA::Key(3), Crypt::RSA::Public(3)
345              
346             =cut
347              
348