| blib/lib/Crypt/DSA/GMP/KeyChain.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % |
| statement | 15 | 17 | 88.2 |
| branch | n/a | ||
| condition | n/a | ||
| subroutine | 6 | 6 | 100.0 |
| pod | n/a | ||
| total | 21 | 23 | 91.3 |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | package Crypt::DSA::GMP::KeyChain; | ||||||
| 2 | 6 | 6 | 34 | use strict; | |||
| 6 | 11 | ||||||
| 6 | 246 | ||||||
| 3 | 6 | 6 | 32 | use warnings; | |||
| 6 | 13 | ||||||
| 6 | 311 | ||||||
| 4 | |||||||
| 5 | BEGIN { | ||||||
| 6 | 6 | 6 | 77 | $Crypt::DSA::GMP::KeyChain::AUTHORITY = 'cpan:DANAJ'; | |||
| 7 | 6 | 110 | $Crypt::DSA::GMP::KeyChain::VERSION = '0.01'; | ||||
| 8 | } | ||||||
| 9 | |||||||
| 10 | 6 | 6 | 31 | use Carp qw( croak ); | |||
| 6 | 11 | ||||||
| 6 | 514 | ||||||
| 11 | 6 | 6 | 35 | use Math::BigInt lib => "GMP"; | |||
| 6 | 9 | ||||||
| 6 | 52 | ||||||
| 12 | 6 | 6 | 15829 | use Math::Prime::Util::GMP qw/is_prob_prime is_provable_prime miller_rabin_random/; | |||
| 0 | |||||||
| 0 | |||||||
| 13 | use Digest::SHA qw( sha1 sha1_hex sha256_hex); | ||||||
| 14 | |||||||
| 15 | use Crypt::DSA::GMP::Key; | ||||||
| 16 | use Crypt::DSA::GMP::Util qw( bin2mp bitsize mod_exp makerandomrange randombytes ); | ||||||
| 17 | |||||||
| 18 | sub new { | ||||||
| 19 | my ($class, @params) = @_; | ||||||
| 20 | return bless { @params }, $class; | ||||||
| 21 | } | ||||||
| 22 | |||||||
| 23 | sub generate_params { | ||||||
| 24 | my ($keygen, %param) = @_; | ||||||
| 25 | croak "Size parameter missing" unless defined $param{Size}; | ||||||
| 26 | my $bits = int($param{Size}); | ||||||
| 27 | my $v = $param{Verbosity}; | ||||||
| 28 | my $proveq = $param{Prove} && $param{Prove} !~ /^p$/i; | ||||||
| 29 | my $provep = $param{Prove} && $param{Prove} !~ /^q$/i; | ||||||
| 30 | croak "Number of bits (Size => $bits) is too small (min 256)" | ||||||
| 31 | unless $bits >= 256; | ||||||
| 32 | |||||||
| 33 | # TODO: | ||||||
| 34 | # - strict FIPS 186-2 compliance requires L to be a multiple | ||||||
| 35 | # of 64 512 <= L <= 1024. | ||||||
| 36 | # - strict FIPS 186-3/4 compliance requires L,N to be one of | ||||||
| 37 | # the pairs: (1024,160) (2048,224) (2048,256) (3072,256) | ||||||
| 38 | # - Can we use new generation method if seed is null? | ||||||
| 39 | |||||||
| 40 | # OpenSSL was removed: | ||||||
| 41 | # 1. It was a portability issue (7 RTs related to it). | ||||||
| 42 | # 2. It removes module dependencies. | ||||||
| 43 | # 2. Security issues with running a program in the path without | ||||||
| 44 | # verifying it is the correct executable. | ||||||
| 45 | # 3. We know the code here follows FIPS 186-4. OpenSSL does not. | ||||||
| 46 | # 4. The behavior of OpenSSL has changed across different versions. | ||||||
| 47 | # 5. This code is faster for key sizes larger than 1024 bits. | ||||||
| 48 | |||||||
| 49 | # Time for key generations (without proofs, average of 1000) | ||||||
| 50 | # 512-bit 47ms Perl 25ms OpenSSL | ||||||
| 51 | # 768-bit 78ms Perl 69ms OpenSSL | ||||||
| 52 | # 1024-bit 139ms Perl 144ms OpenSSL | ||||||
| 53 | # 2048-bit 783ms Perl 1,144ms OpenSSL | ||||||
| 54 | # 4096-bit 7,269ms Perl 12,888ms OpenSSL | ||||||
| 55 | |||||||
| 56 | $param{Standard} = $keygen->{Standard} | ||||||
| 57 | if defined $keygen->{Standard} && !defined $param{Standard}; | ||||||
| 58 | my $standard = (defined $param{Standard} && $param{Standard} =~ /186-[34]/) | ||||||
| 59 | ? 'FIPS 186-4' | ||||||
| 60 | : 'FIPS 186-2'; | ||||||
| 61 | |||||||
| 62 | # $mrseed is just a random number we give to the primality test to give us | ||||||
| 63 | # a unique sequence of bases. It's not that important other than (1) we | ||||||
| 64 | # don't want the same sequence each call, (2) we don't want to leak any | ||||||
| 65 | # information about our state, and (3) we don't want to spend too much | ||||||
| 66 | # time/entropy on it. A truncated hash of our seed should work well. | ||||||
| 67 | |||||||
| 68 | my($counter, $q, $p, $seed, $seedp1, $mrseed); | ||||||
| 69 | |||||||
| 70 | if ($standard eq 'FIPS 186-2') { | ||||||
| 71 | |||||||
| 72 | croak "FIPS 186-2 does not support Q sizes other than 160" | ||||||
| 73 | if defined $param{QSize} && $param{QSize} != 160; | ||||||
| 74 | # See FIPS 186-4 A.1.1.1, non-approved method. | ||||||
| 75 | delete $param{Seed} if defined $param{Seed} && length($param{Seed}) != 20; | ||||||
| 76 | |||||||
| 77 | my $n = int(($bits+159)/160)-1; | ||||||
| 78 | my $b = $bits-1-($n*160); | ||||||
| 79 | my $p_test = Math::BigInt->new(2)->bpow($bits-1); # 2^(L-1) | ||||||
| 80 | |||||||
| 81 | do { | ||||||
| 82 | ## Generate q | ||||||
| 83 | while (1) { | ||||||
| 84 | print STDERR "." if $v; | ||||||
| 85 | $seed = (defined $param{Seed}) ? delete $param{Seed} | ||||||
| 86 | : randombytes(20); | ||||||
| 87 | $seedp1 = _seed_plus_one($seed); | ||||||
| 88 | my $md = sha1($seed) ^ sha1($seedp1); | ||||||
| 89 | vec($md, 0, 8) |= 0x80; | ||||||
| 90 | vec($md, 19, 8) |= 0x01; | ||||||
| 91 | $q = bin2mp($md); | ||||||
| 92 | $mrseed = '0x'.substr(sha256_hex($seed),0,16) unless defined $mrseed; | ||||||
| 93 | last if ( $proveq && is_provable_prime($q)) | ||||||
| 94 | || (!$proveq && is_prob_prime($q) | ||||||
| 95 | && miller_rabin_random($q, 19, $mrseed)); | ||||||
| 96 | } | ||||||
| 97 | print STDERR "*\n" if $v; | ||||||
| 98 | |||||||
| 99 | ## Generate p. | ||||||
| 100 | $counter = 0; | ||||||
| 101 | my $q2 = Math::BigInt->new(2)->bmul($q); | ||||||
| 102 | while ($counter < 4096) { | ||||||
| 103 | print STDERR "." if $v; | ||||||
| 104 | my $Wstr = ''; | ||||||
| 105 | for my $j (0 .. $n) { | ||||||
| 106 | $seedp1 = _seed_plus_one($seedp1); | ||||||
| 107 | $Wstr = sha1_hex($seedp1) . $Wstr; | ||||||
| 108 | } | ||||||
| 109 | my $W = Math::BigInt->from_hex('0x'.$Wstr)->bmod($p_test); | ||||||
| 110 | my $X = $W + $p_test; | ||||||
| 111 | $p = $X - ( ($X % $q2) - 1); | ||||||
| 112 | if ($p >= $p_test) { | ||||||
| 113 | last if ( $provep && is_provable_prime($p)) | ||||||
| 114 | || (!$provep && is_prob_prime($p) | ||||||
| 115 | && miller_rabin_random($p, 3, $mrseed)); | ||||||
| 116 | } | ||||||
| 117 | $counter++; | ||||||
| 118 | } | ||||||
| 119 | } while ($counter >= 4096); | ||||||
| 120 | |||||||
| 121 | # /\ /\ /\ /\ FIPS 186-2 /\ /\ /\ /\ # | ||||||
| 122 | } else { | ||||||
| 123 | # \/ \/ \/ \/ FIPS 186-4 \/ \/ \/ \/ # | ||||||
| 124 | |||||||
| 125 | my $L = $bits; | ||||||
| 126 | my $N = (defined $param{QSize}) ? $param{QSize} | ||||||
| 127 | : ($bits >= 2048) ? 256 : 160; | ||||||
| 128 | croak "Invalid Q size, must be between 1 and 512" if $N < 1 || $N > 512; | ||||||
| 129 | croak "Invalid Q size, must be >= Size+8" if $L < $N+8; | ||||||
| 130 | # See NIST SP 800-57 rev 3, table 3. sha256 is ok for all sizes | ||||||
| 131 | my $outlen = ($N <= 256) ? 256 : ($N <= 384) ? 384 : 512; | ||||||
| 132 | my $sha = Digest::SHA->new($outlen); | ||||||
| 133 | croak "No digest available for Q size $N" unless defined $sha; | ||||||
| 134 | |||||||
| 135 | my $n = int(($L+$outlen-1)/$outlen)-1; | ||||||
| 136 | my $b = $L-1-($n*$outlen); | ||||||
| 137 | my $p_test = Math::BigInt->new(2)->bpow($L-1); # 2^(L-1) | ||||||
| 138 | my $q_test = Math::BigInt->new(2)->bpow($N-1); # 2^(N-1) | ||||||
| 139 | my $seedlen = int( ($N+7)/8 ); | ||||||
| 140 | my $nptests = ($L <= 2048) ? 3 : 2; # See FIPS 186-4 table C.1 | ||||||
| 141 | my $nqtests = ($N <= 160) ? 19 : 27; | ||||||
| 142 | |||||||
| 143 | delete $param{Seed} | ||||||
| 144 | if defined $param{Seed} && length($param{Seed}) < $seedlen; | ||||||
| 145 | $param{Seed} = substr($param{Seed}, 0, $seedlen) if defined $param{Seed}; | ||||||
| 146 | |||||||
| 147 | do { | ||||||
| 148 | ## Generate q | ||||||
| 149 | while (1) { | ||||||
| 150 | print STDERR "." if $v; | ||||||
| 151 | $seed = (defined $param{Seed}) ? delete $param{Seed} | ||||||
| 152 | : randombytes($seedlen); | ||||||
| 153 | my $digest = $sha->reset->add($seed)->hexdigest; | ||||||
| 154 | my $U = Math::BigInt->from_hex('0x'.$digest)->bmod($q_test); | ||||||
| 155 | $q = $q_test + $U + 1 - $U->is_odd(); | ||||||
| 156 | $mrseed = '0x'.substr(sha256_hex($seed),0,16) unless defined $mrseed; | ||||||
| 157 | last if ( $proveq && is_provable_prime($q)) | ||||||
| 158 | || (!$proveq && is_prob_prime($q) | ||||||
| 159 | && miller_rabin_random($q, $nqtests, $mrseed)); | ||||||
| 160 | } | ||||||
| 161 | print STDERR "*\n" if $v; | ||||||
| 162 | $seedp1 = $seed; | ||||||
| 163 | |||||||
| 164 | ## Generate p. | ||||||
| 165 | $counter = 0; | ||||||
| 166 | my $q2 = Math::BigInt->new(2)->bmul($q); | ||||||
| 167 | while ($counter < 4*$L) { | ||||||
| 168 | print STDERR "." if $v; | ||||||
| 169 | my $Wstr = ''; | ||||||
| 170 | for my $j (0 .. $n) { | ||||||
| 171 | $seedp1 = _seed_plus_one($seedp1); | ||||||
| 172 | $Wstr = $sha->reset->add($seedp1)->hexdigest . $Wstr; | ||||||
| 173 | } | ||||||
| 174 | my $W = Math::BigInt->from_hex('0x'.$Wstr)->bmod($p_test); | ||||||
| 175 | my $X = $W + $p_test; | ||||||
| 176 | $p = $X - ( ($X % $q2) - 1); | ||||||
| 177 | if ($p >= $p_test) { | ||||||
| 178 | last if ( $provep && is_provable_prime($p)) | ||||||
| 179 | || (!$provep && is_prob_prime($p) | ||||||
| 180 | && miller_rabin_random($p, $nptests, $mrseed)); | ||||||
| 181 | } | ||||||
| 182 | $counter++; | ||||||
| 183 | } | ||||||
| 184 | } while ($counter >= 4*$L); | ||||||
| 185 | |||||||
| 186 | } | ||||||
| 187 | |||||||
| 188 | print STDERR "*" if $v; | ||||||
| 189 | my $e = ($p - 1) / $q; | ||||||
| 190 | my $h = Math::BigInt->bone; | ||||||
| 191 | my $g; | ||||||
| 192 | do { | ||||||
| 193 | $g = mod_exp(++$h, $e, $p); | ||||||
| 194 | } while $g == 1; | ||||||
| 195 | print STDERR "\n" if $v; | ||||||
| 196 | |||||||
| 197 | my $key = Crypt::DSA::GMP::Key->new; | ||||||
| 198 | $key->p($p); | ||||||
| 199 | $key->q($q); | ||||||
| 200 | $key->g($g); | ||||||
| 201 | |||||||
| 202 | return wantarray ? ($key, $counter, "$h", $seed) : $key; | ||||||
| 203 | } | ||||||
| 204 | |||||||
| 205 | # Using FIPS 186-4 B.1.2 approved method. | ||||||
| 206 | sub generate_keys { | ||||||
| 207 | my ($keygen, $key, $nonblock) = @_; | ||||||
| 208 | my $q = $key->q; | ||||||
| 209 | # Generate private key 0 < x < q, using best randomness source. | ||||||
| 210 | my $priv_key = makerandomrange( Max => $q-2, KeyGen => !$nonblock ) + 1; | ||||||
| 211 | my $pub_key = mod_exp($key->g, $priv_key, $key->p); | ||||||
| 212 | $key->priv_key($priv_key); | ||||||
| 213 | $key->pub_key($pub_key); | ||||||
| 214 | } | ||||||
| 215 | |||||||
| 216 | sub _seed_plus_one { | ||||||
| 217 | my($s) = @_; | ||||||
| 218 | for (my $i = length($s)-1; $i >= 0; $i--) { | ||||||
| 219 | vec($s, $i, 8)++; | ||||||
| 220 | last unless vec($s, $i, 8) == 0; | ||||||
| 221 | } | ||||||
| 222 | return $s; | ||||||
| 223 | } | ||||||
| 224 | |||||||
| 225 | 1; | ||||||
| 226 | |||||||
| 227 | =pod | ||||||
| 228 | |||||||
| 229 | =head1 NAME | ||||||
| 230 | |||||||
| 231 | Crypt::DSA::GMP::KeyChain - DSA key generation system | ||||||
| 232 | |||||||
| 233 | =head1 SYNOPSIS | ||||||
| 234 | |||||||
| 235 | use Crypt::DSA::GMP::KeyChain; | ||||||
| 236 | my $keychain = Crypt::DSA::GMP::KeyChain->new; | ||||||
| 237 | |||||||
| 238 | my $key = $keychain->generate_params( | ||||||
| 239 | Size => 512, | ||||||
| 240 | Seed => $seed, | ||||||
| 241 | Verbosity => 1, | ||||||
| 242 | ); | ||||||
| 243 | |||||||
| 244 | $keychain->generate_keys($key); | ||||||
| 245 | |||||||
| 246 | =head1 DESCRIPTION | ||||||
| 247 | |||||||
| 248 | L |
||||||
| 249 | generation than the L |
||||||
| 250 | It allows you to separately generate the I , I |
||||||
| 251 | and I |
||||||
| 252 | sizes for I and I |
||||||
| 253 | construction. | ||||||
| 254 | |||||||
| 255 | You can then call I |
||||||
| 256 | private portions of the key. | ||||||
| 257 | |||||||
| 258 | =head1 USAGE | ||||||
| 259 | |||||||
| 260 | =head2 $keychain = Crypt::DSA::GMP::KeyChain->new | ||||||
| 261 | |||||||
| 262 | Constructs and returns a new L |
||||||
| 263 | object. At the moment this isn't particularly useful in | ||||||
| 264 | itself, other than being the object you need in order to | ||||||
| 265 | call the other methods. | ||||||
| 266 | |||||||
| 267 | The standard to follow may be given in this call, where it | ||||||
| 268 | will be used in all methods unless overridden. | ||||||
| 269 | |||||||
| 270 | |||||||
| 271 | =head2 $key = $keychain->generate_params(%arg) | ||||||
| 272 | |||||||
| 273 | Generates a set of DSA parameters: the I , I |
||||||
| 274 | values of the key. This involves finding primes, and as such | ||||||
| 275 | it can be a relatively long process. | ||||||
| 276 | |||||||
| 277 | When invoked in scalar context, returns a new | ||||||
| 278 | I |
||||||
| 279 | |||||||
| 280 | In list context, returns the new I |
||||||
| 281 | along with: the value of the internal counter when a suitable | ||||||
| 282 | prime I was found; the value of I |
||||||
| 283 | and the value of the seed (a 20-byte or 32-byte string) when | ||||||
| 284 | Iwas found. These values aren't particularly useful in normal |
||||||
| 285 | circumstances, but they could be useful. | ||||||
| 286 | |||||||
| 287 | I<%arg> can contain: | ||||||
| 288 | |||||||
| 289 | =over 4 | ||||||
| 290 | |||||||
| 291 | =item * Standard | ||||||
| 292 | |||||||
| 293 | Indicates which standard is to be followed. By default, | ||||||
| 294 | FIPS 186-2 is used, which maintains backward compatibility | ||||||
| 295 | with the L |
||||||
| 296 | C |
||||||
| 297 | key generation will be used. | ||||||
| 298 | |||||||
| 299 | The important changes made: | ||||||
| 300 | |||||||
| 301 | - Using SHA-2 rather than SHA-1 for the CSPRNG. This produces | ||||||
| 302 | better quality random data for prime generation. | ||||||
| 303 | - Allows I |
||||||
| 304 | - The default size for I |
||||||
| 305 | 2048 or larger, 160 otherwise. | ||||||
| 306 | - In L |
||||||
| 307 | SHA-2 256 for signing and verification when I |
||||||
| 308 | and SHA-2 512 otherwise. The old standard used SHA-1. | ||||||
| 309 | |||||||
| 310 | where I, and I |
||||||
| 311 | These correspond to the I |
||||||
| 312 | |||||||
| 313 | The recommended primality tests from FIPS 186-4 are always | ||||||
| 314 | performed, since they are more stringent than the older standard | ||||||
| 315 | and have no negative impact on the result. | ||||||
| 316 | |||||||
| 317 | =item * Size | ||||||
| 318 | |||||||
| 319 | The size in bits of the I value to generate. The minimum |
||||||
| 320 | allowable value is 256, and must also be at least 8 bits larger | ||||||
| 321 | than the size of I(defaults to 160, see I |
||||||
| 322 | |||||||
| 323 | For any use where security is a concern, 1024 bits should be | ||||||
| 324 | considered a minimum size. NIST SP800-57 (July 2012) considers | ||||||
| 325 | 1024 bit DSA using SHA-1 to be deprecated, with 2048 or more bits | ||||||
| 326 | using SHA-2 to be acceptable. | ||||||
| 327 | |||||||
| 328 | This argument is mandatory. | ||||||
| 329 | |||||||
| 330 | =item * QSize | ||||||
| 331 | |||||||
| 332 | The size in bits of the Ivalue to generate. For the default |
||||||
| 333 | FIPS 186-2 standard, this must always be 160. If the FIPS 186-4 | ||||||
| 334 | standard is used, then this may be in the range 1 to 512 (values | ||||||
| 335 | less than 160 are strongly discouraged). | ||||||
| 336 | |||||||
| 337 | If not specified, Iwill be 160 bits if either the default |
||||||
| 338 | FIPS 186-2 standard is used or if I |
||||||
| 339 | If FIPS 186-4 is used and I |
||||||
| 340 | will be 256. | ||||||
| 341 | |||||||
| 342 | =item * Seed | ||||||
| 343 | |||||||
| 344 | A seed with which Igeneration will begin. If this seed does |
||||||
| 345 | not lead to a suitable prime, it will be discarded, and a new | ||||||
| 346 | random seed chosen in its place, until a suitable prime can be | ||||||
| 347 | found. | ||||||
| 348 | |||||||
| 349 | A seed that is shorter than the size of Iwill be |
||||||
| 350 | immediately discarded. | ||||||
| 351 | |||||||
| 352 | This is entirely optional, and if not provided a random seed will | ||||||
| 353 | be generated automatically. Do not use this option unless you | ||||||
| 354 | have a specific need for a starting seed. | ||||||
| 355 | |||||||
| 356 | =item * Verbosity | ||||||
| 357 | |||||||
| 358 | Should be either 0 or 1. A value of 1 will give you a progress | ||||||
| 359 | meter during I and I |
||||||
| 360 | the process can be relatively long. | ||||||
| 361 | |||||||
| 362 | The default is 0. | ||||||
| 363 | |||||||
| 364 | =item * Prove | ||||||
| 365 | |||||||
| 366 | Should be 0, 1, I , or I |
||||||
| 367 | the primes for I and I |
||||||
| 368 | the string I or I |
||||||
| 369 | |||||||
| 370 | Using this flag will guarantee the values are prime, which is | ||||||
| 371 | valuable if security is extremely important. The current | ||||||
| 372 | implementation constructs random primes using the method | ||||||
| 373 | A.1.1.1, then ensures they are prime by constructing and | ||||||
| 374 | verifying a primality proof, rather than using a constructive | ||||||
| 375 | method such as the Maurer or Shawe-Taylor algorithms. The | ||||||
| 376 | time for proof will depend on the platform and the Size | ||||||
| 377 | parameter. Proving Ishould take 100 milliseconds or |
||||||
| 378 | less, but I can take a very long time if over 1024 bits. |
||||||
| 379 | |||||||
| 380 | The default is 0, which means the standard FIPS 186-4 probable | ||||||
| 381 | prime tests are done. | ||||||
| 382 | |||||||
| 383 | |||||||
| 384 | =back | ||||||
| 385 | |||||||
| 386 | =head2 $keychain->generate_keys($key) | ||||||
| 387 | |||||||
| 388 | Generates the public and private portions of the key I<$key>, | ||||||
| 389 | a I |
||||||
| 390 | |||||||
| 391 | =head1 AUTHOR & COPYRIGHT | ||||||
| 392 | |||||||
| 393 | See L |
||||||
| 394 | |||||||
| 395 | =cut |