| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Crypt::RSA::Key; | 
| 2 | 12 |  |  | 12 |  | 125700 | use strict; | 
|  | 12 |  |  |  |  | 32 |  | 
|  | 12 |  |  |  |  | 297 |  | 
| 3 | 12 |  |  | 12 |  | 56 | use warnings; | 
|  | 12 |  |  |  |  | 26 |  | 
|  | 12 |  |  |  |  | 314 |  | 
| 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 | 12 |  |  | 12 |  | 59 | use base 'Class::Loader'; | 
|  | 12 |  |  |  |  | 39 |  | 
|  | 12 |  |  |  |  | 4316 |  | 
| 12 | 12 |  |  | 12 |  | 77064 | use base 'Crypt::RSA::Errorhandler'; | 
|  | 12 |  |  |  |  | 29 |  | 
|  | 12 |  |  |  |  | 2849 |  | 
| 13 | 12 |  |  | 12 |  | 8701 | use Math::Prime::Util qw(random_nbit_prime miller_rabin_random is_frobenius_khashin_pseudoprime); | 
|  | 12 |  |  |  |  | 95496 |  | 
|  | 12 |  |  |  |  | 62 |  | 
| 14 | 12 |  |  | 12 |  | 4491 | use Crypt::RSA::DataFormat qw(bitsize); | 
|  | 12 |  |  |  |  | 43 |  | 
|  | 12 |  |  |  |  | 616 |  | 
| 15 | 12 |  |  | 12 |  | 72 | use Math::BigInt try => 'GMP, Pari'; | 
|  | 12 |  |  |  |  | 22 |  | 
|  | 12 |  |  |  |  | 77 |  | 
| 16 | 12 |  |  | 12 |  | 12868 | use Crypt::RSA::Key::Private; | 
|  | 12 |  |  |  |  | 34 |  | 
|  | 12 |  |  |  |  | 351 |  | 
| 17 | 12 |  |  | 12 |  | 4253 | use Crypt::RSA::Key::Public; | 
|  | 12 |  |  |  |  | 30 |  | 
|  | 12 |  |  |  |  | 256 |  | 
| 18 | 12 |  |  | 12 |  | 71 | use Carp; | 
|  | 12 |  |  |  |  | 25 |  | 
|  | 12 |  |  |  |  | 7775 |  | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | $Crypt::RSA::Key::VERSION = '1.99'; | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | my %MODMAP = ( | 
| 23 |  |  |  |  |  |  | Native_PKF => { Module => "Crypt::RSA::Key::Public" }, | 
| 24 |  |  |  |  |  |  | Native_SKF => { Module => "Crypt::RSA::Key::Private" }, | 
| 25 |  |  |  |  |  |  | SSH_PKF => { Module => "Crypt::RSA::Key::Public::SSH"  }, | 
| 26 |  |  |  |  |  |  | SSH_SKF => { Module => "Crypt::RSA::Key::Private::SSH" }, | 
| 27 |  |  |  |  |  |  | ); | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | sub new { | 
| 31 | 11 |  |  | 11 | 1 | 2133 | my $class = shift; | 
| 32 | 11 |  |  |  |  | 32 | my $self = {}; | 
| 33 | 11 |  |  |  |  | 29 | bless $self, $class; | 
| 34 | 11 |  |  |  |  | 185 | $self->_storemap ( %MODMAP ); | 
| 35 | 11 |  |  |  |  | 267 | return $self; | 
| 36 |  |  |  |  |  |  | } | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  | sub generate { | 
| 40 |  |  |  |  |  |  |  | 
| 41 | 15 |  |  | 15 | 1 | 162 | my ($self, %params) = @_; | 
| 42 |  |  |  |  |  |  |  | 
| 43 | 15 |  |  |  |  | 38 | my $key; | 
| 44 | 15 | 50 | 66 |  |  | 89 | unless ($params{q} && $params{p} && $params{e}) { | 
|  |  |  | 33 |  |  |  |  | 
| 45 |  |  |  |  |  |  |  | 
| 46 | 14 | 50 |  |  |  | 70 | return $self->error ("Missing argument.") unless $params{Size}; | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | return $self->error ("Keysize too small.") if | 
| 49 | 14 | 50 |  |  |  | 71 | $params{Size} < 48; | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | return $self->error ("Odd keysize.") if | 
| 52 | 14 | 50 |  |  |  | 57 | $params{Size} % 2; | 
| 53 |  |  |  |  |  |  |  | 
| 54 | 14 |  |  |  |  | 70 | my $size = int($params{Size}/2); | 
| 55 | 14 |  | 100 |  |  | 94 | my $verbosity = $params{Verbosity} || 0; | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | # Switch from Maurer prime to nbit prime, then add some more primality | 
| 58 |  |  |  |  |  |  | # testing.  This is faster and gives us a wider set of possible primes. | 
| 59 |  |  |  |  |  |  |  | 
| 60 |  |  |  |  |  |  | # We really ought to consider the distribution.  See: | 
| 61 |  |  |  |  |  |  | # https://crocs.fi.muni.cz/_media/public/papers/usenixsec16_1mrsakeys_trfimu_201603.pdf | 
| 62 |  |  |  |  |  |  | # for comments on p/q selection. | 
| 63 |  |  |  |  |  |  |  | 
| 64 | 14 |  |  |  |  | 33 | while (1) { | 
| 65 | 29 |  |  |  |  | 2342 | my $p = random_nbit_prime($size); | 
| 66 | 29 |  |  |  |  | 475093182 | my $q = random_nbit_prime($size); | 
| 67 | 29 | 100 |  |  |  | 680530527 | $p = Math::BigInt->new("$p") unless ref($p) eq 'Math::BigInt'; | 
| 68 | 29 | 100 |  |  |  | 663 | $q = Math::BigInt->new("$q") unless ref($q) eq 'Math::BigInt'; | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | # For unbiased rejection sampling, generate both p/q if size too small. | 
| 71 | 29 | 100 |  |  |  | 482 | next unless bitsize($p * $q) == $params{Size}; | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | # Verify primes aren't too close together. | 
| 74 | 14 | 100 |  |  |  | 84 | if ($params{Size} >= 256) { | 
| 75 | 11 |  |  |  |  | 52 | my $threshold = Math::BigInt->new(2)->bpow($params{Size}/2 - 100); | 
| 76 | 11 |  |  |  |  | 5877 | my $diff = $p->copy->bsub($q)->babs; | 
| 77 | 11 | 50 |  |  |  | 2005 | next if $diff <= $threshold; | 
| 78 |  |  |  |  |  |  | } | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | # We could check p-1 and q-1 smoothness. | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | # p and q have passed the strong BPSW test, so it would be shocking | 
| 83 |  |  |  |  |  |  | # if they were not prime.  We'll add a few more tests because they're | 
| 84 |  |  |  |  |  |  | # cheap and we want to be extra careful, but also don't want to spend | 
| 85 |  |  |  |  |  |  | # the time doing a full primality proof. | 
| 86 |  |  |  |  |  |  |  | 
| 87 | 14 | 50 |  |  |  | 687 | do { carp "$p passes BPSW but fails Frobenius test!"; next; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 88 |  |  |  |  |  |  | unless is_frobenius_khashin_pseudoprime($p); | 
| 89 | 14 | 50 |  |  |  | 32104300 | do { carp "$q passes BPSW but fails Frobenius test!"; next; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 90 |  |  |  |  |  |  | unless is_frobenius_khashin_pseudoprime($q); | 
| 91 |  |  |  |  |  |  |  | 
| 92 | 14 | 50 |  |  |  | 32210025 | do { carp "$p fails Miller-Rabin testing!"; next; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 93 |  |  |  |  |  |  | unless miller_rabin_random($p,3); | 
| 94 | 14 | 50 |  |  |  | 18475282 | do { carp "$q fails Miller-Rabin testing!"; next; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 95 |  |  |  |  |  |  | unless miller_rabin_random($q,3); | 
| 96 |  |  |  |  |  |  |  | 
| 97 | 14 |  |  |  |  | 19153359 | $key = { p => $p, q => $q, e => Math::BigInt->new(65537) }; | 
| 98 | 14 |  |  |  |  | 929 | last; | 
| 99 |  |  |  |  |  |  | } | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  |  | 
| 102 | 15 | 100 |  |  |  | 89 | if ($params{KF}) { | 
| 103 | 4 |  |  |  |  | 20 | $params{PKF} = { Name => "$params{KF}_PKF" }; | 
| 104 | 4 |  |  |  |  | 17 | $params{SKF} = { Name => "$params{KF}_SKF" } | 
| 105 |  |  |  |  |  |  | } | 
| 106 |  |  |  |  |  |  |  | 
| 107 | 15 | 100 |  |  |  | 82 | my $pubload = $params{PKF} ? $params{PKF} : { Name => "Native_PKF" }; | 
| 108 | 15 | 100 |  |  |  | 70 | my $priload = $params{SKF} ? $params{SKF} : { Name => "Native_SKF" }; | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 15 |  | 50 |  |  | 209 | my $pubkey = $self->_load (%$pubload) || | 
| 111 |  |  |  |  |  |  | return $self->error ("Couldn't load the public key module: $@"); | 
| 112 | 15 |  | 50 |  |  | 272 | my $prikey = $self->_load ((%$priload), Args => ['Cipher' => $params{Cipher}, 'Password' => $params{Password} ]) || | 
| 113 |  |  |  |  |  |  | return $self->error ("Couldn't load the private key module: $@"); | 
| 114 | 15 |  |  |  |  | 315 | $pubkey->Identity ($params{Identity}); | 
| 115 | 15 |  |  |  |  | 103 | $prikey->Identity ($params{Identity}); | 
| 116 |  |  |  |  |  |  |  | 
| 117 | 15 |  | 66 |  |  | 82 | $pubkey->e ($$key{e} || $params{e}); | 
| 118 | 15 |  | 66 |  |  | 62 | $prikey->e ($$key{e} || $params{e}); | 
| 119 | 15 |  | 66 |  |  | 61 | $prikey->p ($$key{p} || $params{p}); | 
| 120 | 15 |  | 66 |  |  | 67 | $prikey->q ($$key{q} || $params{q}); | 
| 121 |  |  |  |  |  |  |  | 
| 122 | 15 |  |  |  |  | 76 | $prikey->phi ( ($prikey->p - 1) * ($prikey->q - 1) ); | 
| 123 |  |  |  |  |  |  |  | 
| 124 | 15 |  |  |  |  | 114 | $prikey->d ( ($pubkey->e)->copy->bmodinv($prikey->phi) ); | 
| 125 | 15 |  |  |  |  | 80 | $prikey->n ( $prikey->p * $prikey->q ); | 
| 126 | 15 |  |  |  |  | 75 | $pubkey->n ( $prikey->n ); | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 15 |  |  |  |  | 77 | $prikey->dp ($prikey->d % ($prikey->p - 1)); | 
| 129 | 15 |  |  |  |  | 93 | $prikey->dq ($prikey->d % ($prikey->q - 1)); | 
| 130 | 15 |  |  |  |  | 93 | $prikey->u ( ($prikey->p)->copy->bmodinv($prikey->q) ); | 
| 131 |  |  |  |  |  |  |  | 
| 132 | 15 | 50 |  |  |  | 96 | return $self->error ("d is too small. Regenerate.") if | 
| 133 |  |  |  |  |  |  | bitsize($prikey->d) < 0.25 * bitsize($prikey->n); | 
| 134 |  |  |  |  |  |  |  | 
| 135 | 15 |  |  |  |  | 60 | $$key{p} = 0; $$key{q} = 0; $$key{e} = 0; | 
|  | 15 |  |  |  |  | 39 |  | 
|  | 15 |  |  |  |  | 42 |  | 
| 136 |  |  |  |  |  |  |  | 
| 137 | 15 | 50 |  |  |  | 76 | if ($params{Filename}) { | 
| 138 | 0 |  |  |  |  | 0 | $pubkey->write (Filename => "$params{Filename}.public"); | 
| 139 | 0 |  |  |  |  | 0 | $prikey->write (Filename => "$params{Filename}.private"); | 
| 140 |  |  |  |  |  |  | } | 
| 141 |  |  |  |  |  |  |  | 
| 142 | 15 |  |  |  |  | 183 | return ($pubkey, $prikey); | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | } | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | 1; | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | =head1 NAME | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | Crypt::RSA::Key - RSA Key Pair Generator. | 
| 151 |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 153 |  |  |  |  |  |  |  | 
| 154 |  |  |  |  |  |  | my $keychain = new Crypt::RSA::Key; | 
| 155 |  |  |  |  |  |  | my ($public, $private) = $keychain->generate ( | 
| 156 |  |  |  |  |  |  | Identity  => 'Lord Macbeth ', | 
| 157 |  |  |  |  |  |  | Size      => 2048, | 
| 158 |  |  |  |  |  |  | Password  => 'A day so foul & fair', | 
| 159 |  |  |  |  |  |  | Verbosity => 1, | 
| 160 |  |  |  |  |  |  | ) or die $keychain->errstr(); | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | This module provides a method to generate an RSA key pair. | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | =head1 METHODS | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | =head2 new() | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | Constructor. | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | =head2 generate() | 
| 173 |  |  |  |  |  |  |  | 
| 174 |  |  |  |  |  |  | generate() generates an RSA key of specified bitsize. It returns a list of | 
| 175 |  |  |  |  |  |  | two elements, a Crypt::RSA::Key::Public object that holds the public part | 
| 176 |  |  |  |  |  |  | of the key pair and a Crypt::RSA::Key::Private object that holds that | 
| 177 |  |  |  |  |  |  | private part. On failure, it returns undef and sets $self->errstr to | 
| 178 |  |  |  |  |  |  | appropriate error string. generate() takes a hash argument with the | 
| 179 |  |  |  |  |  |  | following keys: | 
| 180 |  |  |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | =over 4 | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | =item B | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | Bitsize of the key to be generated. This should be an even integer > 48. | 
| 186 |  |  |  |  |  |  | Bitsize is a mandatory argument. | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | =item B | 
| 189 |  |  |  |  |  |  |  | 
| 190 |  |  |  |  |  |  | String with which the private key will be encrypted. If Password is not | 
| 191 |  |  |  |  |  |  | provided the key will be stored unencrypted. | 
| 192 |  |  |  |  |  |  |  | 
| 193 |  |  |  |  |  |  | =item B | 
| 194 |  |  |  |  |  |  |  | 
| 195 |  |  |  |  |  |  | A string that identifies the owner of the key. This string usually takes | 
| 196 |  |  |  |  |  |  | the form of a name and an email address. The identity is not bound to the | 
| 197 |  |  |  |  |  |  | key with a signature. However, a future release or another module will | 
| 198 |  |  |  |  |  |  | provide this facility. | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | =item B | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | The block cipher which is used for encrypting the private key. Defaults to | 
| 203 |  |  |  |  |  |  | `Blowfish'. Cipher could be set to any value that works with Crypt::CBC(3) | 
| 204 |  |  |  |  |  |  | and Tie::EncryptedHash(3). | 
| 205 |  |  |  |  |  |  |  | 
| 206 |  |  |  |  |  |  | =item B | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | When set to 1, generate() will draw a progress display on STDOUT. | 
| 209 |  |  |  |  |  |  |  | 
| 210 |  |  |  |  |  |  | =item B | 
| 211 |  |  |  |  |  |  |  | 
| 212 |  |  |  |  |  |  | The generated key pair will be written to disk, in $Filename.public and | 
| 213 |  |  |  |  |  |  | $Filename.private files, if this argument is provided. Disk writes can be | 
| 214 |  |  |  |  |  |  | deferred by skipping this argument and achieved later with the write() | 
| 215 |  |  |  |  |  |  | method of Crypt::RSA::Key::Public(3) and Crypt::RSA::Key::Private(3). | 
| 216 |  |  |  |  |  |  |  | 
| 217 |  |  |  |  |  |  | =item B | 
| 218 |  |  |  |  |  |  |  | 
| 219 |  |  |  |  |  |  | A string that specifies the key format. As of this writing, two key | 
| 220 |  |  |  |  |  |  | formats, `Native' and `SSH', are supported. KF defaults to `Native'. | 
| 221 |  |  |  |  |  |  |  | 
| 222 |  |  |  |  |  |  | =item B | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | Secret (Private) Key Format. Instead of specifying KF, the user could | 
| 225 |  |  |  |  |  |  | choose to specify secret and public key formats separately. The value for | 
| 226 |  |  |  |  |  |  | SKF can be a string ("Native" or "SSH") or a hash reference that specifies | 
| 227 |  |  |  |  |  |  | a module name, its constructor and constructor arguments. The specified | 
| 228 |  |  |  |  |  |  | module is loaded with Class::Loader(3) and must be interface compatible | 
| 229 |  |  |  |  |  |  | with Crypt::RSA::Key::Private(3). | 
| 230 |  |  |  |  |  |  |  | 
| 231 |  |  |  |  |  |  | =item B | 
| 232 |  |  |  |  |  |  |  | 
| 233 |  |  |  |  |  |  | Public Key Format. This option is like SKF but for the public key. | 
| 234 |  |  |  |  |  |  |  | 
| 235 |  |  |  |  |  |  | =back | 
| 236 |  |  |  |  |  |  |  | 
| 237 |  |  |  |  |  |  | =head1 ERROR HANDLING | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | See B in Crypt::RSA(3) manpage. | 
| 240 |  |  |  |  |  |  |  | 
| 241 |  |  |  |  |  |  | =head1 BUGS | 
| 242 |  |  |  |  |  |  |  | 
| 243 |  |  |  |  |  |  | There's an inefficiency in the way generate() ensures the key pair is | 
| 244 |  |  |  |  |  |  | exactly Size bits long. This will be fixed in a future release. | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | =head1 AUTHOR | 
| 247 |  |  |  |  |  |  |  | 
| 248 |  |  |  |  |  |  | Vipul Ved Prakash, Email@vipul.netE | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | Crypt::RSA(3), Crypt::RSA::Key::Public(3), Crypt::RSA::Key::Private(3), | 
| 253 |  |  |  |  |  |  | Tie::EncryptedHash(3), Class::Loader(3), | 
| 254 |  |  |  |  |  |  | Math::Prime::Util(3) | 
| 255 |  |  |  |  |  |  |  | 
| 256 |  |  |  |  |  |  | =cut | 
| 257 |  |  |  |  |  |  |  | 
| 258 |  |  |  |  |  |  |  |