File Coverage

blib/lib/Crypt/DRBG.pm
Criterion Covered Total %
statement 129 138 93.4
branch 51 64 79.6
condition 22 27 81.4
subroutine 16 16 100.0
pod 5 5 100.0
total 223 250 89.2


line stmt bran cond sub pod time code
1             package Crypt::DRBG;
2             $Crypt::DRBG::VERSION = '0.001000';
3 15     15   48855 use 5.006;
  15         46  
4 15     15   77 use strict;
  15         21  
  15         267  
5 15     15   57 use warnings;
  15         28  
  15         313  
6              
7 15     15   3753 use IO::File ();
  15         86643  
  15         17304  
8              
9             =head1 NAME
10              
11             Crypt::DRBG - Base class for fast, cryptographically-secure PRNGs
12              
13             =head1 SYNOPSIS
14              
15             use Crypt::DRBG::HMAC;
16              
17             my $drbg = Crypt::DRBG::HMAC->new(auto => 1);
18             my $data = $drbg->generate(42);
19             ... # do something with your 42 bytes here
20              
21             my $drbg2 = Crypt::DRBG::HMAC->new(seed => "my very secret seed");
22             my @randdigits = $drbg->randitems(20, [0..9]);
23             ... # do something with your 20 random digits here
24              
25             =head1 DESCRIPTION
26              
27             Crypt::DRBG is a collection of fast, cryptographically-secure PRNGs
28             (pseudo-random number generators). It can be useful for a variety of
29             situations:
30              
31             =over 4
32              
33             =item *
34              
35             Cryptographically secure random numbers are needed in production, but for
36             testing reproducibility is needed
37              
38             =item *
39              
40             A large number of random values are needed, but using /dev/urandom (or the
41             equivalent) frequently or persistently is unsuitable
42              
43             =item *
44              
45             Selection of random values in a range (e.g. digits, letters, identifiers) is
46             required and biasing the results is unacceptable
47              
48             =back
49              
50             Crypt::DRBG::HMAC is the recommended class to use, as it's currently the
51             fastest. All algorithms are assumed to provide equivalent security.
52              
53             =head1 SUBROUTINES/METHODS
54              
55             =head2 initialize(%params)
56              
57             %params can contain the following:
58              
59             =over 4
60              
61             =item auto
62              
63             If true, use a safe, cryptographically-secure set of defaults.
64             Equivalent to specifying autoseed, autononce, autopersonalize, and
65             fork_safe.
66              
67             =item autoseed
68              
69             If true, derive a seed from Crypt::URandom, if available,
70             or from /dev/urandom, /dev/arandom, or /dev/random, in that order.
71             Windows support requires Crypt::URandom to function properly.
72              
73             =item seed
74              
75             If a string, use this value as the seed. If a coderef, call this coderef with a
76             single argument (the number of bytes) to obtain an entropy input. Note that if
77             a string is used, an exception will be thrown if a reseed is required.
78              
79             =item autononce
80              
81             If true, derive a nonce automatically.
82              
83             =item nonce
84              
85             If a string, use this value as the nonce. If a coderef, call this coderef with
86             a single argument (the number of bytes) to obtain a nonce.
87              
88             =item autopersonalize
89              
90             If true, derive a personalization string automatically.
91              
92             =item personalize
93              
94             If a string, use this value as the personalization string. If a coderef, call
95             this coderef to obtain a personalization string.
96              
97             =item fork_safe
98              
99             If true, reseed on fork. If false, the parent and child processes will produce
100             the same sequence of bytes (not recommended).
101              
102             =item cache
103              
104             If enabled, keep a cache of this many bytes and use it to satisfy requests
105             before generating more.
106              
107             =back
108              
109             =cut
110              
111             # Not a method call.
112             sub _rand_bytes {
113 20     20   65 my ($len) = @_;
114              
115 20         56 my $data = eval {
116 20         3417 require Crypt::URandom;
117 20         19072 Crypt::URandom::urandom($len);
118             };
119              
120 20 50       15818 return $data if defined $data;
121              
122 0         0 $data = '';
123              
124 0         0 my @sources = qw{/dev/urandom /dev/arandom /dev/random};
125 0         0 foreach my $source (@sources) {
126 0 0       0 my $fh = IO::File->new($source, 'r') or next;
127 0         0 while ($fh->read(my $buf, $len - length($data))) {
128 0         0 $data .= $buf;
129             }
130 0 0       0 die "Insufficient random data" if length($data) != $len;
131 0         0 return $data;
132             }
133 0         0 die "No random source for autoseed";
134             }
135              
136             sub _get_seed {
137 5490     5490   12330 my ($self, $name, $len, $params, $optional) = @_;
138 5490         8993 my $autoname = "auto$name";
139              
140 5490         6592 my $seed;
141 5490 100 100     18295 if (defined $params->{$name} && !ref $params->{$name}) {
142 5402         8985 $seed = $params->{$name};
143             }
144             else {
145 88         105 my $seedfunc;
146 88 100       201 $seedfunc = $params->{$name} if ref $params->{$name} eq 'CODE';
147 88 100 66     423 $seedfunc = \&_rand_bytes if $params->{$autoname} || $params->{auto};
148 88 100       186 unless ($seedfunc) {
149 43 100       111 die "No seed source" unless $optional;
150 41         105 return '';
151             }
152 45         117 $self->{"${name}func"} = $seedfunc;
153 45         115 $seed = $seedfunc->($len);
154             }
155              
156 5447         10011 return $seed;
157             }
158              
159             sub _get_personalization {
160 2744     2744   5183 my ($self, $params) = @_;
161 2744         4054 my $name = 'personalize';
162 2744         4692 my $autoname = "auto$name";
163              
164 2744         3550 my $seed;
165 2744 100 100     8974 if (defined $params->{$name} && !ref $params->{$name}) {
166 2688         5051 $seed = $params->{$name};
167             }
168             else {
169 56         90 my $seedfunc;
170 56 100       132 $seedfunc = $params->{$name} if ref $params->{$name} eq 'CODE';
171 56 100 100     211 if ($params->{$autoname} || $params->{auto}) {
172             die "Invalid version"
173 11 0 33     39 if defined $params->{version} && $params->{version};
174 11         20 my $version = 0;
175             $seedfunc = sub {
176 11     11   65 my @nums = ($$, $<, $>, time);
177 11         137 my @strings = ($0, $(, $));
178              
179 11         168 return join('',
180             "$version\0",
181             pack("N" x @nums, @nums),
182             pack("Z" x @strings, @strings),
183             );
184 11         94 };
185             }
186             # Personalization strings are recommended, but optional.
187 56 100       186 return '' unless $seedfunc;
188 13         31 $seed = $seedfunc->();
189             }
190              
191 2701         5238 return $seed;
192             }
193              
194             sub _check_reseed {
195 5559     5559   9044 my ($self) = @_;
196              
197 5559         7387 my $reseed = 0;
198 5559         7681 my $pid = $self->{pid};
199 5559 100 100     12669 $reseed = 1 if defined $pid && $pid != $$;
200 5559 50       11364 $reseed = 1 if $self->{reseed_counter} >= $self->{reseed_interval};
201              
202 5559 100       9498 if ($reseed) {
203 8 50       298 die "No seed source" if !$self->{seedfunc};
204 8         650 $self->_reseed($self->{seedfunc}->($self->{seedlen}));
205 8 50       122 $self->{pid} = $$ if $self->{fork_safe};
206 8 100       53 $self->{cache} = '' if defined $self->{cache};
207             }
208              
209 5559         9041 return 1;
210             }
211              
212             sub initialize {
213 2746     2746 1 9154 my ($self, %params) = @_;
214              
215 2746         10053 my $seed = $self->_get_seed('seed', $self->{seedlen}, \%params);
216 2744         9275 my $nonce = $self->_get_seed('nonce', int(($self->{seedlen} / 2) + 1),
217             \%params, 1);
218 2744         7561 my $personal = $self->_get_personalization(\%params);
219              
220 2744         11214 $self->_seed("$seed$nonce$personal");
221              
222 2744 100       6516 if ($params{cache}) {
223 5         25 $self->{cache} = '';
224 5         116 $self->{cache_size} = $params{cache};
225             }
226              
227 2744 100 66     14345 if ($params{fork_safe} || (!exists $params{fork_safe} && $params{auto})) {
      100        
228 26         49 $self->{fork_safe} = 1;
229 26         68 $self->{pid} = $$;
230             }
231              
232 2744         6792 return 1;
233             }
234              
235             =head2 $drbg->generate($bytes, $additional_data)
236              
237             Generate and return $bytes bytes. There is a limit per algorithm on the number of bytes that can be requested at once, which is at least 2^10.
238              
239             If $additional_data is specified, add this additional data to the DRBG.
240              
241             If the cache flag was specified on instantiation, bytes will be satisfied from
242             the cache first, unless $additional_data was specified.
243              
244             =cut
245              
246             sub generate {
247 5548     5548 1 19452849 my ($self, $len, $seed) = @_;
248              
249             return $self->_generate($len, $seed)
250 5548 100 66     28767 if !defined $self->{cache} || defined $seed;
251              
252 82         209 $self->_check_reseed;
253              
254 82         124 my $data = '';
255 82         99 my $left = $len;
256 82         155 my $cache = \$self->{cache};
257 82 100       193 $$cache = $self->_generate($self->{cache_size}) if !length($$cache);
258 82         150 while ($left > 0) {
259 86 100       157 my $chunk_size = $left > length($$cache) ? length($$cache) : $left;
260 86         311 $data .= substr($$cache, 0, $chunk_size, '');
261 86         149 $left = $len - length($data);
262 86 100       211 $$cache = $self->_generate($self->{cache_size}) if !length($$cache);
263             }
264              
265 82         331 return $data;
266             }
267              
268             =head2 $drbg->rand([$n], [$num])
269              
270             Like Perl's rand, but cryptographically secure. Uses 32-bit values.
271              
272             Accepts an additional argument, $num, which is the number of values to return.
273             Defaults to 1 (obviously).
274              
275             Note that just as with Perl's rand, there may be a slight bias with this
276             function. Use randitems if that matters to you.
277              
278             Returns an array if $num is specified and a single item if it is not.
279              
280             =cut
281              
282             sub rand {
283 3     3 1 574 my ($self, $n, $num) = @_;
284              
285 3         7 my $single = !defined $num;
286              
287 3 100       9 $n = 1 unless defined $n;
288 3 100       6 $num = 1 unless defined $num;
289              
290 3         9 my $bytes = $self->generate($num * 4);
291 3         19 my @data = map { $_ / 2.0 / (2 ** 31) * $n } unpack("N[$num]", $bytes);
  102         132  
292 3 100       17 return $single ? $data[0] : @data;
293             }
294              
295             =head2 $drbg->randitems($n, $items)
296              
297             Select randomly and uniformly from the arrayref $items $n times.
298              
299             =cut
300              
301             sub randitems {
302 6     6 1 39 my ($self, $n, $items) = @_;
303              
304 6         11 my $len = scalar @$items;
305 6         9 my @results;
306 6         40 my $values = [
307             {bytes => 1, pack => 'C', max => 256},
308             {bytes => 2, pack => 'n', max => 65536},
309             {bytes => 4, pack => 'N', max => 2 ** 31},
310             ];
311 6 0       29 my $params = $values->[$len <= 256 ? 0 : $len <= 65536 ? 1 : 2];
    50          
312              
313             # Getting this computation right is important so as not to bias the
314             # data. $len & $len - 1 is true iff $len is not a power of two.
315 6         9 my $max = $params->{max};
316 6         10 my $mask = $max - 1;
317 6 100       21 if ($len & ($len - 1)) {
318 4         8 $max = $max - ($max % $len);
319             }
320             else {
321 2         2 $mask = $len - 1;
322             }
323              
324 6         18 my $pack = "$params->{pack}\[$n\]";
325 6         16 while (@results < $n) {
326 8         31 my $bytes = $self->generate($params->{bytes} * $n);
327              
328 8         76 my @data = map { $_ & $mask } grep { $_ < $max } unpack($pack, $bytes);
  1136         1200  
  1240         1461  
329 8         36 push @results, map { $items->[$_ % $len] } @data;
  1136         1541  
330             }
331              
332 6         61 return splice(@results, 0, $n);
333             }
334              
335             =head2 $drbg->randbytes($n, $items)
336              
337             Select randomly and uniformly from the characters in arrayref $items $n times.
338             Returns a byte string.
339              
340             This function works just like randitems, but is more efficient if generating a
341             sequence of bytes as a string instead of an array.
342              
343             =cut
344              
345             sub randbytes {
346 3     3 1 21 my ($self, $n, $items) = @_;
347              
348 3         5 my $len = scalar @$items;
349 3         5 my $results = '';
350              
351             # Getting this computation right is important so as not to bias the
352             # data. $len & $len - 1 is true iff $len is not a power of two.
353 3         4 my $max = 256;
354 3     1   10 my $filter = sub { return $_[0]; };
  1         3  
355 3 100       8 if ($len & ($len - 1)) {
356 2         4 $max = $max - ($max % $len);
357 2         8 my $esc = sprintf '\x%02x', $max + 1;
358             $filter = sub {
359 3     3   6 my $s = shift;
360 3         154 eval "\$s =~ tr/$esc-\\xff//d"; ## no critic(ProhibitStringyEval)
361 3         16 return $s;
362 2         11 };
363             }
364              
365 3         8 while (length $results < $n) {
366 4         10 my $bytes = $filter->($self->generate($n));
367 4         13 $results .= join '', map { $items->[$_ % $len] } unpack('C*', $bytes);
  37         65  
368             }
369              
370 3         14 return substr($results, 0, $n);
371             }
372              
373             =head1 AUTHOR
374              
375             brian m. carlson, C<< >>
376              
377             =head1 BUGS
378              
379             Please report any bugs or feature requests to C, or through
380             the web interface at L. I will be notified, and then you'll
381             automatically be notified of progress on your bug as I make changes.
382              
383              
384              
385              
386             =head1 SUPPORT
387              
388             You can find documentation for this module with the perldoc command.
389              
390             perldoc Crypt::DRBG
391              
392              
393             You can also look for information at:
394              
395             =over 4
396              
397             =item * RT: CPAN's request tracker (report bugs here)
398              
399             L
400              
401             =item * AnnoCPAN: Annotated CPAN documentation
402              
403             L
404              
405             =item * CPAN Ratings
406              
407             L
408              
409             =item * Search CPAN
410              
411             L
412              
413             =back
414              
415              
416             =head1 ACKNOWLEDGEMENTS
417              
418              
419             =head1 LICENSE AND COPYRIGHT
420              
421             Copyright 2015 brian m. carlson.
422              
423             This program is distributed under the MIT (X11) License:
424             L
425              
426             Permission is hereby granted, free of charge, to any person
427             obtaining a copy of this software and associated documentation
428             files (the "Software"), to deal in the Software without
429             restriction, including without limitation the rights to use,
430             copy, modify, merge, publish, distribute, sublicense, and/or sell
431             copies of the Software, and to permit persons to whom the
432             Software is furnished to do so, subject to the following
433             conditions:
434              
435             The above copyright notice and this permission notice shall be
436             included in all copies or substantial portions of the Software.
437              
438             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
439             EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
440             OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
441             NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
442             HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
443             WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
444             FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
445             OTHER DEALINGS IN THE SOFTWARE.
446              
447              
448             =cut
449              
450             1; # End of Crypt::DRBG