File Coverage

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 is a lower-level interface to key
249             generation than the L method.
250             It allows you to separately generate the I

, I,

251             and I key parameters, given an optional starting seed, bit
252             sizes for I

and I, and which standard to follow for

253             construction.
254              
255             You can then call I to generate the public and
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, and 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 object.
279              
280             In list context, returns the new I object
281             along with: the value of the internal counter when a suitable
282             prime I

was found; the value of I when I was derived;

283             and the value of the seed (a 20-byte or 32-byte string) when
284             I was 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 Perl code and old OpenSSL versions. If
296             C or C is given, then the FIPS 186-4
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 to vary between 1 and 512 rather than fixed at 160.
304             - The default size for I when not specified is 256 if I is
305             2048 or larger, 160 otherwise.
306             - In L, the signing and verification will use
307             SHA-2 256 for signing and verification when I E= 256,
308             and SHA-2 512 otherwise. The old standard used SHA-1.
309              
310             where I is the bit size of I, and I is the bit size of I

.

311             These correspond to the I and I arguments.
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 I value 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, I will be 160 bits if either the default
338             FIPS 186-2 standard is used or if I is less than 2048.
339             If FIPS 186-4 is used and I is 2048 or larger, then I
340             will be 256.
341              
342             =item * Seed
343              
344             A seed with which I generation 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 I will 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 generation -- this can be useful, since

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. If defined and true, then both

367             the primes for I

and I will be proven primes. Setting to

368             the string I

or I will result in just that prime being proven.

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 I should 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 object.
390              
391             =head1 AUTHOR & COPYRIGHT
392              
393             See L for author, copyright, and license information.
394              
395             =cut