| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Crypt::Random::TESHA2; |
|
2
|
6
|
|
|
6
|
|
23443
|
use strict; |
|
|
6
|
|
|
|
|
13
|
|
|
|
6
|
|
|
|
|
210
|
|
|
3
|
6
|
|
|
6
|
|
29
|
use warnings; |
|
|
6
|
|
|
|
|
12
|
|
|
|
6
|
|
|
|
|
190
|
|
|
4
|
6
|
|
|
6
|
|
39
|
use Carp qw/croak confess carp/; |
|
|
6
|
|
|
|
|
11
|
|
|
|
6
|
|
|
|
|
515
|
|
|
5
|
6
|
|
|
6
|
|
6463
|
use Time::HiRes qw/gettimeofday usleep/; |
|
|
6
|
|
|
|
|
11751
|
|
|
|
6
|
|
|
|
|
31
|
|
|
6
|
6
|
|
|
6
|
|
9963
|
use Digest::SHA qw/sha256 sha512/; |
|
|
6
|
|
|
|
|
29492
|
|
|
|
6
|
|
|
|
|
560
|
|
|
7
|
6
|
|
|
6
|
|
4146
|
use Crypt::Random::TESHA2::Config; |
|
|
6
|
|
|
|
|
15
|
|
|
|
6
|
|
|
|
|
511
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
BEGIN { |
|
10
|
6
|
|
|
6
|
|
13
|
$Crypt::Random::TESHA2::AUTHORITY = 'cpan:DANAJ'; |
|
11
|
6
|
|
|
|
|
109
|
$Crypt::Random::TESHA2::VERSION = '0.01'; |
|
12
|
|
|
|
|
|
|
} |
|
13
|
|
|
|
|
|
|
|
|
14
|
6
|
|
|
6
|
|
34
|
use base qw( Exporter ); |
|
|
6
|
|
|
|
|
11
|
|
|
|
6
|
|
|
|
|
7001
|
|
|
15
|
|
|
|
|
|
|
our @EXPORT_OK = qw( random_bytes random_values irand rand is_strong ); |
|
16
|
|
|
|
|
|
|
our %EXPORT_TAGS = (all => [ @EXPORT_OK ]); |
|
17
|
|
|
|
|
|
|
our @EXPORT = qw( ); # nothing by default |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $_opt_need_strong = 0; |
|
20
|
|
|
|
|
|
|
my $_opt_weak_ok = 0; |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
my $_entropy_per_raw_byte = Crypt::Random::TESHA2::Config::entropy(); |
|
23
|
|
|
|
|
|
|
# Protect against possible abuse / misconfiguration |
|
24
|
|
|
|
|
|
|
$_entropy_per_raw_byte = 1 if $_entropy_per_raw_byte < 1; |
|
25
|
|
|
|
|
|
|
$_entropy_per_raw_byte = 7 if $_entropy_per_raw_byte > 7; |
|
26
|
|
|
|
|
|
|
my $_hashalg = \&sha512; |
|
27
|
|
|
|
|
|
|
my $_pool_size = 512; |
|
28
|
|
|
|
|
|
|
my $_nehi = 0; # A 64-bit counter |
|
29
|
|
|
|
|
|
|
my $_nelo = 0; |
|
30
|
|
|
|
|
|
|
my $_pool; |
|
31
|
|
|
|
|
|
|
my $_C; # bits of entropy that we think are in the pool |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# Make sure SHA512 is supported, back off to 256 if not. |
|
34
|
|
|
|
|
|
|
if (!defined sha512("test")) { |
|
35
|
|
|
|
|
|
|
$_pool_size = 256; |
|
36
|
|
|
|
|
|
|
$_hashalg = \&sha256; |
|
37
|
|
|
|
|
|
|
} |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub import { |
|
40
|
5
|
|
|
5
|
|
32
|
my @options; |
|
41
|
|
|
|
|
|
|
|
|
42
|
5
|
|
|
|
|
14
|
@options = grep { $_ !~ /^[-:]?weak$/i } @_; |
|
|
11
|
|
|
|
|
46
|
|
|
43
|
5
|
50
|
|
|
|
20
|
$_opt_weak_ok = 1 if @options != @_; |
|
44
|
5
|
|
|
|
|
15
|
@_ = @options; |
|
45
|
|
|
|
|
|
|
|
|
46
|
5
|
|
|
|
|
12
|
@options = grep { $_ !~ /^[-:]?strong$/i } @_; |
|
|
11
|
|
|
|
|
33
|
|
|
47
|
5
|
50
|
|
|
|
19
|
$_opt_need_strong = 1 if @options != @_; |
|
48
|
5
|
|
|
|
|
15
|
@_ = @options; |
|
49
|
|
|
|
|
|
|
|
|
50
|
5
|
50
|
33
|
|
|
21
|
croak "TESHA2 is not a strong randomness source on this platform" |
|
51
|
|
|
|
|
|
|
if $_opt_need_strong && !is_strong(); |
|
52
|
|
|
|
|
|
|
|
|
53
|
5
|
|
|
|
|
322
|
goto &Exporter::import; |
|
54
|
|
|
|
|
|
|
} |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# Returns 1 if our installtion-time entropy measurements indicated we could |
|
57
|
|
|
|
|
|
|
# get enough entropy to make this method work on this platform. |
|
58
|
|
|
|
|
|
|
sub is_strong { |
|
59
|
3
|
50
|
|
3
|
1
|
7166
|
return ($_entropy_per_raw_byte > 1.0) ? 1 : 0; |
|
60
|
|
|
|
|
|
|
} |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# Return $n random 32-bit values |
|
63
|
|
|
|
|
|
|
sub random_values { |
|
64
|
1
|
|
|
1
|
1
|
756
|
return map { unpack("L", random_bytes(4)) } 1 .. shift; |
|
|
10
|
|
|
|
|
33
|
|
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
# Note, only 32 bits. |
|
67
|
|
|
|
|
|
|
# TODO: Figure out a portable non-64-bit way to make 52-bit doubles. |
|
68
|
|
|
|
|
|
|
sub rand { |
|
69
|
2
|
|
100
|
2
|
1
|
1766
|
return ($_[0]||1) * (unpack("L", random_bytes(4))/4294967296.0); |
|
70
|
|
|
|
|
|
|
} |
|
71
|
|
|
|
|
|
|
sub irand { |
|
72
|
1
|
|
|
1
|
1
|
953
|
return unpack("L", random_bytes(4)); |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# This uses an entropy pool (see Encyclopedia of Cryptography and Security, |
|
76
|
|
|
|
|
|
|
# volume 2, "Entropy Sources"). We use SHA-512 to handle a 512-bit pool. |
|
77
|
|
|
|
|
|
|
# One this this will do is ensure the input from any one byte is nicely |
|
78
|
|
|
|
|
|
|
# spread out among the 64 bytes of the pool. |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
sub random_bytes { |
|
81
|
2523
|
|
|
2523
|
1
|
45210
|
my $n = shift; |
|
82
|
2523
|
50
|
|
|
|
11668
|
return '' unless defined $n; |
|
83
|
2523
|
100
|
|
|
|
8256
|
if (!defined $_pool) { |
|
84
|
|
|
|
|
|
|
# Initialize pool with 64 bits of entropy. |
|
85
|
2
|
|
|
|
|
3
|
$_C = 64; |
|
86
|
|
|
|
|
|
|
# Get some extra bytes at the start. |
|
87
|
2
|
|
|
|
|
9
|
my $nbytes = 4 + int($_C/$_entropy_per_raw_byte) + 1; |
|
88
|
2
|
|
|
|
|
8
|
my $S = join("", map { _get_random_byte() } 1 .. $nbytes); |
|
|
28
|
|
|
|
|
61
|
|
|
89
|
2
|
|
|
|
|
31
|
$_pool = $_hashalg->($S); |
|
90
|
|
|
|
|
|
|
|
|
91
|
2
|
50
|
33
|
|
|
33
|
carp "TESHA2 is not a strong randomness source on this platform" |
|
92
|
|
|
|
|
|
|
if !$_opt_weak_ok && !is_strong(); |
|
93
|
|
|
|
|
|
|
} |
|
94
|
2523
|
|
|
|
|
6417
|
my $X = ''; |
|
95
|
2523
|
|
|
|
|
9744
|
while (length($X) < $n) { |
|
96
|
2522
|
|
|
|
|
11398
|
my $K = 8 * $n; |
|
97
|
2522
|
50
|
|
|
|
8527
|
$K = $_pool_size if $K > $_pool_size; |
|
98
|
|
|
|
|
|
|
# Add more entropy to pool if needed. |
|
99
|
2522
|
|
|
|
|
7588
|
while ($_C < $K) { |
|
100
|
2512
|
|
|
|
|
7415
|
my $nbytes = int( ($K - $_C) / $_entropy_per_raw_byte ) + 1; |
|
101
|
|
|
|
|
|
|
#warn "want $K bits, pool has $_C bits. Adding $nbytes bytes\n"; |
|
102
|
2512
|
|
|
|
|
11505
|
my $S = join("", map { _get_random_byte() } 1 .. $nbytes); |
|
|
2960
|
|
|
|
|
12334
|
|
|
103
|
2512
|
|
|
|
|
28752
|
$_pool = $_hashalg->($_pool . $S); |
|
104
|
2512
|
|
|
|
|
7311
|
$_C += $_entropy_per_raw_byte * $nbytes; |
|
105
|
2512
|
50
|
|
|
|
20272
|
$_C = $_pool_size if $_C > $_pool_size; |
|
106
|
|
|
|
|
|
|
} |
|
107
|
|
|
|
|
|
|
# Extract K bits from the pool. |
|
108
|
2522
|
|
|
|
|
5471
|
$_C -= $K; |
|
109
|
2522
|
|
|
|
|
31283
|
my $V = $_hashalg->( 'te' . pack("LL", $_nehi, $_nelo) . $_pool ); |
|
110
|
2522
|
50
|
|
|
|
10167
|
if ($_nelo < 4294967295) { $_nelo++; } else { $_nehi++; $_nelo = 0; } |
|
|
2522
|
|
|
|
|
6966
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
111
|
2522
|
|
|
|
|
17220
|
$X .= substr($V, 0, int($K/8)); |
|
112
|
|
|
|
|
|
|
} |
|
113
|
2523
|
|
|
|
|
36400
|
return $X; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# The heart of the system, where we gather entropy from timer jitter |
|
117
|
|
|
|
|
|
|
# (technically this is scheduler jitter). This is a similar idea to |
|
118
|
|
|
|
|
|
|
# timer_entropyd, TrueRand, or the old Math::TrulyRandom module. |
|
119
|
|
|
|
|
|
|
# |
|
120
|
|
|
|
|
|
|
# *) Cryptographically, there are numerous issues here. This is, at best, |
|
121
|
|
|
|
|
|
|
# one source to feed to a well designed entropy pool system. |
|
122
|
|
|
|
|
|
|
# |
|
123
|
|
|
|
|
|
|
# *) The output of this function passes ENT and TestU01 Rabbit on all systems |
|
124
|
|
|
|
|
|
|
# I've run it on. timer_entropyd does not, even when von Neumann debiased. |
|
125
|
|
|
|
|
|
|
# However, even a counter run through SHA256 will pass these tests, which |
|
126
|
|
|
|
|
|
|
# just indicates the stream data is uncorrelated. |
|
127
|
|
|
|
|
|
|
# |
|
128
|
|
|
|
|
|
|
# *) The entropy tests mentioned above are only one part. If a system |
|
129
|
|
|
|
|
|
|
# returned the same sequence every time, it may pass all the tests but |
|
130
|
|
|
|
|
|
|
# still be a horrible generator. That's especially not what one wants |
|
131
|
|
|
|
|
|
|
# from this module. |
|
132
|
|
|
|
|
|
|
# |
|
133
|
|
|
|
|
|
|
# *) I discovered Matt Blaze's truerand after I wrote this -- no ideas or |
|
134
|
|
|
|
|
|
|
# code were used. However, I got the idea from timer_entropyd, which |
|
135
|
|
|
|
|
|
|
# probably in turn got the idea from truerand. Version 2.1 (1996) of |
|
136
|
|
|
|
|
|
|
# Matt Blaze's truerand is _far_ more conservative than the old design |
|
137
|
|
|
|
|
|
|
# in Math::TrulyRandom. First he replaces the old-school byte mixing |
|
138
|
|
|
|
|
|
|
# with a SHA (very similar to my solution here). Next, he does another |
|
139
|
|
|
|
|
|
|
# mixing to generate the actual bytes, while the old code would use the |
|
140
|
|
|
|
|
|
|
# raw results. I use a different method above, but the end result is |
|
141
|
|
|
|
|
|
|
# somewhat similar -- we take these raw results and stir them further. |
|
142
|
|
|
|
|
|
|
# |
|
143
|
|
|
|
|
|
|
# *) My tests using the raw timer data are showing 1.5 - 4 bits per xor. |
|
144
|
|
|
|
|
|
|
# The truerand 2.1 documentation indicates 0.67 to 1.33 bits per call, |
|
145
|
|
|
|
|
|
|
# then conservatively halves the number. |
|
146
|
|
|
|
|
|
|
# |
|
147
|
|
|
|
|
|
|
# *) Expanding on the above, assume the worst and absolutely no entropy is |
|
148
|
|
|
|
|
|
|
# gathered. Then each byte will be a sha256 related to the current hires |
|
149
|
|
|
|
|
|
|
# time, where each byte is mixed in the pool. We get a fine PRNG, just |
|
150
|
|
|
|
|
|
|
# not seeded well (from a crypto point of view, this is awful). |
|
151
|
|
|
|
|
|
|
# |
|
152
|
|
|
|
|
|
|
# *) For each bit, the two microsecond values are xor'd and packed into |
|
153
|
|
|
|
|
|
|
# 32-bit words. Eight of these are concatenated and a SHA-256 hash is |
|
154
|
|
|
|
|
|
|
# performed. As long as the sum of entropy gathered from all eight xors |
|
155
|
|
|
|
|
|
|
# is at least 8, we're good. The sha256 takes care of shuffling bits so |
|
156
|
|
|
|
|
|
|
# there aren't biases. This generates a much better result than using |
|
157
|
|
|
|
|
|
|
# boolean differences like timer_entropyd (even if the differences are |
|
158
|
|
|
|
|
|
|
# sent through von Neumann debiasing). |
|
159
|
|
|
|
|
|
|
# |
|
160
|
|
|
|
|
|
|
sub _get_random_byte { |
|
161
|
2988
|
|
|
2988
|
|
12853
|
my ($start, $t1, $t2) = gettimeofday(); |
|
162
|
|
|
|
|
|
|
# This basically gives us a counter, so every call is unique. We can |
|
163
|
|
|
|
|
|
|
# assume it adds no entropy. |
|
164
|
2988
|
|
|
|
|
11608
|
my $str = pack("LL", $start, $t1); |
|
165
|
|
|
|
|
|
|
# A hash we will use for a little bit of CPU processing inside the loop. |
|
166
|
2988
|
|
|
|
|
6892
|
my %dummy; |
|
167
|
2988
|
|
|
|
|
10415
|
foreach my $bit (1 .. 8) { |
|
168
|
|
|
|
|
|
|
# Sleep some period of time. Differ the times so we don't hit a |
|
169
|
|
|
|
|
|
|
# particular beat of the scheduler. |
|
170
|
23904
|
|
|
|
|
4571861
|
usleep(2+3*$bit); |
|
171
|
23904
|
|
|
|
|
145797
|
(undef, $t2) = gettimeofday(); |
|
172
|
|
|
|
|
|
|
# xor the two. The entropy is in the variation between what we got |
|
173
|
|
|
|
|
|
|
# (t2 - t1) and what we expected (2+3*bit + c). |
|
174
|
23904
|
|
|
|
|
115462
|
$str .= pack("L", $t1 ^ $t2); |
|
175
|
|
|
|
|
|
|
# A little hash processing to further perturb the times. |
|
176
|
23904
|
|
|
|
|
504730
|
$dummy{$str . $_}++ for 1..8; |
|
177
|
23904
|
|
|
|
|
76664
|
$t1 = $t2; |
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
# To truly return a byte: return substr( sha256($str), 0, 1 ); |
|
180
|
|
|
|
|
|
|
# Return the entire string -- let the pool figure it out. |
|
181
|
2988
|
|
|
|
|
104921
|
return sha256($str); |
|
182
|
|
|
|
|
|
|
} |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
1; |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
__END__ |