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 |