File Coverage

blib/lib/Crypt/RSA/Key/Private.pm
Criterion Covered Total %
statement 137 145 94.4
branch 55 80 68.7
condition 10 26 38.4
subroutine 19 19 100.0
pod 8 8 100.0
total 229 278 82.3


line stmt bran cond sub pod time code
1             package Crypt::RSA::Key::Private;
2 5     5   18484 use strict;
  5         8  
  5         113  
3 5     5   24 use warnings;
  5         8  
  5         142  
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 5     5   22 use vars qw($AUTOLOAD $VERSION);
  5         8  
  5         275  
12 5     5   22 use base 'Crypt::RSA::Errorhandler';
  5         8  
  5         803  
13 5     5   3504 use Tie::EncryptedHash;
  5         45746  
  5         140  
14 5     5   41 use Data::Dumper;
  5         10  
  5         216  
15 5     5   1458 use Math::BigInt try => 'GMP, Pari';
  5         21173  
  5         81  
16 5     5   21839 use Math::Prime::Util qw/is_prime/;
  5         9138  
  5         42  
17 5     5   365 use Carp;
  5         8  
  5         8574  
18              
19             $Crypt::RSA::Key::Private::VERSION = '1.99';
20              
21             sub new {
22              
23 5     5 1 1010 my ($class, %params) = @_;
24 5         19 my $self = { Version => $Crypt::RSA::Key::Private::VERSION };
25 5 100       22 if ($params{Filename}) {
26 1         3 bless $self, $class;
27 1         5 $self = $self->read (%params);
28 1         4 return bless $self, $class;
29             } else {
30 4         7 bless $self, $class;
31 4 100       38 $self->Identity ($params{Identity}) if $params{Identity};
32 4   50     63 $self->Cipher ($params{Cipher}||"Blowfish");
33 4 50       40 $self->Password ($params{Password}) if $params{Password};
34 4         60 return $self;
35             }
36              
37             }
38              
39              
40             sub AUTOLOAD {
41              
42 149     149   3966 my ($self, $value) = @_;
43 149         212 my $key = $AUTOLOAD; $key =~ s/.*:://;
  149         546  
44 149 100       633 if ($key =~ /^(e|n|d|p|q|dp|dq|u|phi)$/) {
    100          
    50          
45 135         359 my $prikey = \$self->{private}{"_$key"};
46 135 100       316 if (defined $value) {
47 15         21 $self->{Checked} = 0;
48 15 100       42 if (ref $value eq 'Math::BigInt') {
    50          
49 8         11 $$prikey = $value;
50             } elsif (ref $value eq 'Math::Pari') {
51 0         0 $$prikey = Math::BigInt->new($value->pari2pv);
52             } else {
53 7         26 $$prikey = Math::BigInt->new("$value");
54             }
55             }
56 135 100       494 if (defined $$prikey) {
57 113 50       258 $$prikey = Math::BigInt->new("$$prikey") unless ref($$prikey) eq 'Math::BigInt';
58 113         436 return $$prikey;
59             }
60 22 100       82 return $self->{private_encrypted}{"_$key"} if defined $self->{private_encrypted}{"_$key"};
61 18         87 return;
62             } elsif ($key =~ /^Identity|Cipher|Password$/) {
63 11 100       72 $self->{$key} = $value if $value;
64 11         25 return $self->{$key};
65             } elsif ($key =~ /^Checked$/) {
66 3         17 my ($package) = caller();
67 3 50 33     23 $self->{Checked} = $value if ($value && $package eq "Crypt::RSA::Key::Private") ;
68 3         9 return $self->{Checked};
69             }
70             }
71              
72              
73             sub hide {
74              
75 2     2 1 26 my ($self) = @_;
76              
77 2 50       6 return unless $$self{Password};
78              
79             $self->{private_encrypted} = new Tie::EncryptedHash
80             __password => $self->{Password},
81 2         16 __cipher => $self->{Cipher};
82              
83 2         4279 for (keys %{$$self{private}}) {
  2         13  
84 4         14021 $$self{private_encrypted}{$_} = $$self{private}{$_}->bstr;
85             }
86              
87 2         3602 my $private = $self->{private_encrypted};
88 2         11 delete $private->{__password};
89 2         81 delete $$self{private};
90 2         4 delete $$self{Password};
91              
92             # Mark ourselves as hidden
93 2         5 $self->{Hidden} = 1;
94             }
95              
96              
97             sub reveal {
98              
99 3     3 1 1094 my ($self, %params) = @_;
100 3 100       13 $$self{Password} = $params{Password} if $params{Password};
101 3 100       10 return unless $$self{Password};
102 2         10 $$self{private_encrypted}{__password} = $params{Password};
103 2         43 for (keys %{$$self{private_encrypted}}) {
  2         10  
104 4         4343 $$self{private}{$_} = Math::BigInt->new("$$self{private_encrypted}{$_}");
105             }
106 2         1602 $self->{Hidden} = 0;
107              
108             }
109              
110              
111             sub check {
112              
113 10     10 1 23 my ($self) = @_;
114              
115 10 100       74 return 1 if $self->{Checked};
116              
117             return $self->error ("Cannot check hidden key - call reveal first.")
118 3 50       14 if $self->{Hidden};
119              
120 3 0 33     22 return $self->error ("Incomplete key.") unless
      0        
      0        
      33        
121             ($self->n && $self->d) || ($self->n && $self->p && $self->q);
122              
123 3 100 66     147 if ($self->p && $self->q) {
124 1 50       39 return $self->error ("n is not a number.") if $self->n =~ /\D/;
125 1 50       26 return $self->error ("p is not a number.") if $self->p =~ /\D/;
126 1 50       30 return $self->error ("q is not a number.") if $self->q =~ /\D/;
127 1 50       24 return $self->error ("n is not p*q." ) unless $self->n == $self->p * $self->q;
128 1 50       93 return $self->error ("p is not prime.") unless is_prime( $self->p );
129 1 50       48 return $self->error ("q is not prime.") unless is_prime( $self->q );
130             }
131              
132 3 100       51 if ($self->e) {
133             # d * e == 1 mod lcm(p-1, q-1)
134 1 50       35 return $self->error ("e is not a number.") if $self->e =~ /\D/;
135 1         24 my $k = Math::BigInt::blcm($self->p-1, $self->q-1);
136 1         415 my $KI = ($self->e)->copy->bmul($self->d)->bmodinv($k);
137 1 50       191 return $self->error ("Bad `d'.") unless $KI == 1;
138             }
139              
140 3 100       106 if ($self->dp) {
141             # dp == d mod (p-1)
142 1 50       28 return $self->error ("Bad `dp'.") unless $self->dp == $self->d % ($self->p - 1);
143             }
144              
145 3 100       273 if ($self->dq) {
146             # dq == d mod (q-1)
147 1 50       27 return $self->error ("Bad `dq'.") unless $self->dq == $self->d % ($self->q - 1);
148             }
149              
150 3 50 66     240 if ($self->u && $self->q && $self->p) {
      66        
151 1         40 my $m = ($self->p)->copy->bmodinv($self->q);
152 1 50       286 return $self->error ("Bad `u'.") unless $self->u == $m;
153             }
154              
155 3         47 $self->Checked(1);
156 3         13 return 1;
157              
158             }
159              
160              
161             sub DESTROY {
162              
163 7     7   2842 my $self = shift;
164 7         28 delete $$self{private_encrypted}{__password};
165 7         71 delete $$self{private_encrypted};
166 7         43 delete $$self{private};
167 7         16 delete $$self{Password};
168 7         105 undef $self;
169              
170             }
171              
172              
173             sub write {
174              
175 1     1 1 4 my ($self, %params) = @_;
176 1         3 $self->hide();
177 1         7 my $string = $self->serialize (%params);
178 1 50       529 open(my $disk, '>', $params{Filename}) or
179             croak "Can't open $params{Filename} for writing.";
180 1         4 binmode $disk;
181 1         23 print $disk $string;
182 1         139 close $disk;
183              
184             }
185              
186              
187             sub read {
188 1     1 1 4 my ($self, %params) = @_;
189 1 50       34 open(my $disk, '<', $params{Filename}) or
190             croak "Can't open $params{Filename} to read.";
191 1         3 binmode $disk;
192 1         26 my @key = <$disk>;
193 1         9 close $disk;
194 1         5 $self = $self->deserialize (String => \@key);
195 1         5 $self->reveal(%params);
196 1         5 return $self;
197             }
198              
199              
200             sub serialize {
201              
202 1     1 1 5 my ($self, %params) = @_;
203 1 50       5 if ($$self{private}) { # this is an unencrypted key
204 0         0 for (keys %{$$self{private}}) {
  0         0  
205 0         0 $$self{private}{$_} = ($$self{private}{$_})->bstr;
206             }
207             }
208 1         7 return Dumper $self;
209              
210             }
211              
212              
213             sub deserialize {
214              
215 1     1 1 4 my ($self, %params) = @_;
216 1         2 my $string = join'', @{$params{String}};
  1         6  
217 1         6 $string =~ s/\$VAR1 =//;
218 1         168 $self = eval $string;
219 1 50       32 if ($$self{private}) { # the key is unencrypted
220 0         0 for (keys %{$$self{private}}) {
  0         0  
221 0         0 $$self{private}{$_} = Math::BigInt->new("$$self{private}{$_}");
222             }
223 0         0 return $self;
224             }
225 1         7 my $private = new Tie::EncryptedHash;
226 1         50 %$private = %{$$self{private_encrypted}};
  1         8  
227 1         85 $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