File Coverage

lib/Crypt/DRBG/Hash.pm
Criterion Covered Total %
statement 87 105 82.8
branch 6 10 60.0
condition 5 8 62.5
subroutine 13 15 86.6
pod 1 1 100.0
total 112 139 80.5


line stmt bran cond sub pod time code
1             package Crypt::DRBG::Hash;
2             $Crypt::DRBG::Hash::VERSION = '0.001000';
3 13     13   27022 use 5.006;
  13         103  
4 13     13   63 use strict;
  13         16  
  13         238  
5 13     13   47 use warnings;
  13         24  
  13         506  
6              
7 13     13   2731 use parent 'Crypt::DRBG';
  13         3199  
  13         43  
8              
9 13     13   4065 use Digest::SHA ();
  13         26228  
  13         7240  
10              
11             =head1 NAME
12              
13             Crypt::DRBG::Hash - Fast, cryptographically secure PRNG
14              
15             =head1 SYNOPSIS
16              
17             use Crypt::DRBG::Hash;
18              
19             my $drbg = Crypt::DRBG::Hash->new(auto => 1);
20             my $data = $drbg->generate(42);
21             ... # do something with your 42 bytes here
22              
23             my $drbg2 = Crypt::DRBG::Hash->new(seed => "my very secret seed");
24             my $data2 = $drbg->generate(42);
25              
26             =head1 DESCRIPTION
27              
28             Crypt::DRBG::Hash is an implementation of the Hash_DRBG from NIST SP800-90A. It
29             is a fast, cryptographically secure PRNG. By default, it uses SHA-512.
30              
31             However, if provided a seed, it will produce the same sequence of bytes I
32             called the same way each time>. This makes it useful for simulations that
33             require good but repeatable random numbers.
34              
35             Note, however, that due to the way the DRBGs are designed, making a single
36             request and making multiple requests for the same number of bytes will result in
37             different data. For example, two 16-byte requests will not produce the same
38             values as one 32-byte request.
39              
40             This class derives from Crypt::DRBG, which provides several utility functions.
41              
42             =head1 SUBROUTINES/METHODS
43              
44             =head2 Crypt::DRBG::Hash->new(%params)
45              
46             Creates a new Crypt::DRBG::Hash.
47              
48             %params can contain all valid values for Crypt::DRBG::initialize, plus the
49             following.
50              
51             =over 4
52              
53             =item algo
54              
55             The algorithm to use for generating bytes. The default is "512", for
56             SHA-512. This provides optimal performance for 64-bit machines.
57              
58             If Perl (and hence Digest::SHA) was built with a compiler lacking 64-bit integer
59             support, use "256" here. "256" may also provide better performance for 32-bit
60             machines.
61              
62             =item func
63              
64             If you would like to use a different hash function, you can specify a function
65             implemeting your specific algorithm.
66              
67             For example, if you had C installed, you could do the following
68             to use BLAKE2b:
69              
70             my $drbg = Crypt::DRBG::Hash->new(
71             auto => 1,
72             func => \&Digest::BLAKE2::blake2b,
73             algo => 512
74             );
75             my $data = $drbg->generate(42);
76              
77             Note that the algo parameter is still required, in order to know how large a
78             seed to use.
79              
80             =back
81              
82             =back
83              
84             =cut
85              
86             sub new {
87 1355     1355 1 5370095 my ($class, %params) = @_;
88              
89 1355   33     6258 $class = ref($class) || $class;
90 1355         2953 my $self = bless {}, $class;
91              
92 1355   100     4257 my $algo = $self->{algo} = $params{algo} || '512';
93 1355         3130 $algo =~ tr{/}{}d;
94 1355 50 66     10995 $self->{s_func} = ($params{func} || Digest::SHA->can("sha$algo")) or
95             die "Unsupported algorithm '$algo'";
96 1355 100       7709 $self->{seedlen} = $algo =~ /^(384|512)$/ ? 111 : 55;
97 1355         2661 $self->{reseed_interval} = 4294967295; # (2^32)-1
98 1355         2213 $self->{bytes_per_request} = 2 ** 16;
99 1355         4590 $self->{outlen} = substr($algo, -3) / 8;
100 1355         2931 $self->{security_strength} = $self->{outlen} / 2;
101 1355         3186 $self->{min_length} = $self->{security_strength};
102 1355         2110 $self->{max_length} = 4294967295; # (2^32)-1
103              
104             # If we have a 64-bit Perl, make things much faster.
105 1355         2022 my $is_64 = (4294967295 + 2) != 1;
106 1355 50       2804 if ($is_64) {
107 1355         2769 $self->{s_add} = \&_add_64;
108             }
109             else {
110 0         0 require Math::BigInt;
111 0         0 eval { Math::BigInt->import(try => 'GMP') };
  0         0  
112              
113             $self->{s_mask} =
114 0         0 (Math::BigInt->bone << ($self->{seedlen} * 8)) - 1;
115 0         0 $self->{s_add} = \&_add_32;
116             }
117              
118 1355         5885 $self->initialize(%params);
119              
120 1354         4154 return $self;
121             }
122              
123             sub _add {
124 10790     10790   324907 my ($self, @args) = @_;
125 10790         13792 my $func = $self->{s_add};
126 10790         15743 return $self->$func(@args);
127             }
128              
129             sub _derive {
130 2708     2708   4564 my ($self, $hashdata, $len) = @_;
131              
132 2708         4787 my $count = ($len + ($self->{outlen} - 1)) / $self->{outlen};
133 2708         3408 my $data = '';
134 2708         3378 my $func = $self->{s_func};
135 2708         5026 for (1..$count) {
136 5864         33732 $data .= $func->(pack('CN', $_, $len * 8) . $hashdata);
137             }
138 2708         6331 return substr($data, 0, $len);
139             }
140              
141             sub _seed {
142 1354     1354   2596 my ($self, $seed) = @_;
143              
144 1354         3541 my $v = $self->_derive($seed, $self->{seedlen});
145 1354         3772 my $c = $self->_derive("\x00$v", $self->{seedlen});
146 1354         4328 $self->{state} = {c => $c, v => $v};
147 1354         2345 $self->{reseed_counter} = 1;
148 1354         2457 return 1;
149             }
150              
151             sub _reseed {
152 0     0   0 my ($self, $seed) = @_;
153              
154 0         0 return $self->_seed("\x01$self->{state}{v}$seed");
155             }
156              
157             sub _add_32 {
158 0     0   0 my ($self, @args) = @_;
159 0         0 my @items = map { Math::BigInt->new("0x" . unpack("H*", $_)) } @args;
  0         0  
160 0         0 my $final = Math::BigInt->bzero;
161 0         0 foreach my $val (@items) {
162 0         0 $final += $val;
163             }
164 0         0 $final &= $self->{s_mask};
165 0         0 my $data = substr($final->as_hex, 2);
166 0 0       0 $data = "0$data" if length($data) & 1;
167 0         0 $data = pack("H*", $data);
168 0         0 return ("\x00" x ($self->{seedlen} - length($data))) . $data;
169             }
170              
171             sub _add_64 {
172 14828     14828   23651 my ($self, $x, @args) = @_;
173              
174 13     13   91 use integer;
  13         46  
  13         40  
175              
176 14828         19206 my $nbytes = $self->{seedlen} + 1;
177 14828         17924 my $nu32s = $nbytes / 4;
178             # Optimize based on the fact that the first argument is always full-length.
179 14828         39397 my @result = unpack('V*', reverse "\x00$x");
180             my @vals = map {
181 14828         21186 [unpack('V*', reverse(("\x00" x ($nbytes - length($_))) . $_))]
  20216         76428  
182             } @args;
183              
184 14828         26344 foreach my $i (0..($nu32s-1)) {
185 277200         287552 my $total = $result[$i];
186 277200         297805 foreach my $val (@vals) {
187 377888         426657 $total += $val->[$i];
188             }
189 277200         301842 $result[$i+1] += $total >> 32;
190 277200         317395 $result[$i] = $total;
191             }
192 14828         75933 return substr(reverse(pack("V*", @result[0..($nu32s-1)])), 1);
193             }
194              
195             sub _hashgen {
196 2694     2694   4496 my ($self, $v, $len) = @_;
197              
198 2694         3878 my $func = $self->{s_func};
199 2694         7403 my $count = int(($len + ($self->{outlen} - 1)) / $self->{outlen});
200 2694         3640 my $data = '';
201 2694         4690 for (1..$count) {
202 10758         39060 $data .= $func->($v);
203 10758         21185 $v = $self->_add($v, "\x01");
204             }
205 2694         6246 return substr($data, 0, $len);
206             }
207              
208             =head2 $drbg->generate($bytes, $additional_data)
209              
210             Generate and return $bytes bytes. $bytes cannot exceed 2^16.
211              
212             If $additional_data is specified, add this additional data to the DRBG.
213              
214             =cut
215              
216             sub _generate {
217 2694     2694   5453 my ($self, $len, $seed) = @_;
218              
219 2694         7082 $self->_check_reseed($len);
220              
221 2694         3338 my ($func, $add) = @{$self}{qw/s_func s_add/};
  2694         5259  
222 2694         3577 my ($c, $v) = @{$self->{state}}{qw/c v/};
  2694         5738  
223 2694 100       4634 if (defined $seed) {
224 1344         8471 my $w = $func->("\x02$v$seed");
225 1344         2978 $v = $self->$add($v, $w);
226             }
227 2694         5868 my $data = $self->_hashgen($v, $len);
228 2694         14993 my $h = $func->("\x03$v");
229 2694         7809 $v = $self->$add($v, $h, $c, pack("N*", $self->{reseed_counter}));
230 2694         4595 $self->{reseed_counter}++;
231 2694         3791 $self->{state}{v} = $v;
232 2694         9069 return substr($data, 0, $len);
233             }
234              
235             =head1 AUTHOR
236              
237             brian m. carlson, C<< >>
238              
239             =head1 BUGS
240              
241             Please report any bugs or feature requests to C, or through
242             the web interface at L. I will be notified, and then you'll
243             automatically be notified of progress on your bug as I make changes.
244              
245              
246              
247              
248             =head1 SUPPORT
249              
250             You can find documentation for this module with the perldoc command.
251              
252             perldoc Crypt::DRBG::Hash
253              
254              
255             You can also look for information at:
256              
257             =over 4
258              
259             =item * RT: CPAN's request tracker (report bugs here)
260              
261             L
262              
263             =item * AnnoCPAN: Annotated CPAN documentation
264              
265             L
266              
267             =item * CPAN Ratings
268              
269             L
270              
271             =item * Search CPAN
272              
273             L
274              
275             =back
276              
277              
278             =head1 ACKNOWLEDGEMENTS
279              
280              
281             =head1 LICENSE AND COPYRIGHT
282              
283             Copyright 2015 brian m. carlson.
284              
285             This program is distributed under the MIT (X11) License:
286             L
287              
288             Permission is hereby granted, free of charge, to any person
289             obtaining a copy of this software and associated documentation
290             files (the "Software"), to deal in the Software without
291             restriction, including without limitation the rights to use,
292             copy, modify, merge, publish, distribute, sublicense, and/or sell
293             copies of the Software, and to permit persons to whom the
294             Software is furnished to do so, subject to the following
295             conditions:
296              
297             The above copyright notice and this permission notice shall be
298             included in all copies or substantial portions of the Software.
299              
300             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
301             EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
302             OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
303             NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
304             HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
305             WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
306             FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
307             OTHER DEALINGS IN THE SOFTWARE.
308              
309              
310             =cut
311              
312             1; # End of Crypt::DRBG::Hash