1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
|
package Math::Random::Secure;
$Math::Random::Secure::VERSION = '0.080001';
# ABSTRACT: Cryptographically-secure, cross-platform replacement for rand()
use strict;
use 5.008;
use base qw(Exporter);
use Math::Random::Secure::RNG;
# ISAAC, a 32-bit generator, should only be capable of generating numbers
# between 0 and 2^32 - 1. We want _to_float to generate numbers possibly
# including 0, but always less than 1.0. Dividing the integer produced
# by irand() by this number should do that exactly.
use constant DIVIDE_BY => 2**32;
our $RNG;
our @EXPORT_OK = qw(rand srand irand);
sub rand (;$) {
my ($limit) = @_;
my $int = irand();
return _to_float($int, $limit);
}
sub irand (;$) {
my ($limit) = @_;
Math::Random::Secure::srand() if !defined $RNG;
my $int = $RNG->irand();
if (defined $limit) {
# We can't just use the mod operator because it will bias
# our output. Search for "modulo bias" on the Internet for
# details. This is slower than mod(), but does not have a bias,
# as demonstrated by our uniform.t test.
return int(_to_float($int, $limit));
}
return $int;
}
sub srand (;$) {
my ($value) = @_;
if (defined $RNG) {
if (defined $value) {
$RNG->seed($value);
}
else {
$RNG->clear_seed;
}
$RNG->clear_rng;
}
else {
my %args;
if (defined $value) {
$args{seed} = $value;
}
$RNG = Math::Random::Secure::RNG->new(%args);
}
# This makes srand return the seed and also makes sure that we
# get the seed right now, if no $value was passed.
return $RNG->seed;
}
sub _to_float {
my ($integer, $limit) = @_;
$limit = 1 if !$limit;
return ($integer / DIVIDE_BY) * $limit;
}
__PACKAGE__
__END__
=pod
=encoding UTF-8
=head1 NAME
Math::Random::Secure - Cryptographically-secure, cross-platform replacement for rand()
=head1 VERSION
version 0.080001
=head1 SYNOPSIS
# Replace rand().
use Math::Random::Secure qw(rand);
# Get a random number between 0 and 1
my $float = rand();
# Get a random integer (faster than int(rand))
use Math::Random::Secure qw(irand);
my $int = irand();
# Random integer between 0 and 9 inclusive.
$int = irand(10);
# Random floating-point number greater than or equal to 0.0 and
# less than 10.0.
$float = rand(10);
=head1 DESCRIPTION
This module is intended to provide a cryptographically-secure replacement
for Perl's built-in C<rand> function. "Crytographically secure", in this
case, means:
=over
=item *
No matter how many numbers you see generated by the random number generator,
you cannot guess the future numbers, and you cannot guess the seed.
=item *
There are so many possible seeds that it would take decades, centuries,
or millenia for an attacker to try them all.
=item *
The seed comes from a source that generates relatively strong random data
on your platform, so the seed itself will be as random as possible.
See L</IMPLEMENTATION DETAILS> for more information about the underlying
systems used to implement all of these guarantees, and some important
caveats if you're going to use this module for some very-high-security
purpose.
=back
=head1 METHODS
=head2 rand
Should work exactly like Perl's built-in C<rand>. Will automatically
call C<srand> if C<srand> has never been called in this process or
thread.
There is one limitation--Math::Random::Secure is backed by a 32-bit
random number generator. So if you are on a 64-bit platform and you
specify a limit that is greater than 2^32, you are likely to get
less-random data.
=head2 srand
B<Note:> Under normal circumstances, you should B<not> call this function,
as C<rand> and C<irand> will automatically call it for you the first time
they are used in a thread or process.
Seeds the random number generator, much like Perl's built-in C<srand>,
except that it uses a much larger and more secure seed. The seed should
be passed as a string of bytes, at least 8 bytes in length, and more
ideally between 32 and 64 bytes. (See L<Math::Random::Secure::RNG/seed>
for more info.)
If you do not pass a seed, a seed will be generated automatically using
a secure mechanism. See L</IMPLEMENTATION DETAILS> for more information.
This function returns the seed that generated (or the seed that was passed
in, if you passed one in).
=head2 irand
Works somewhat like L</rand>, except that it returns a 32-bit integer
between 0 and 2^32. Should be faster than doing C<int(rand)>.
Note that because it returns 32-bit integers, specifying a limit
greater than 2^32 will have no effect.
=head1 IMPLEMENTATION DETAILS
Currently, Math::Random::Secure is backed by L<Math::Random::ISAAC>, a
cryptographically-strong random number generator with no known serious
weaknesses. If there are significant weaknesses found in ISAAC, we will
change our backend to a more-secure random number generator. The goal is
for Math::Random::Secure to be cryptographically strong, not to represent
some specific random number generator.
Math::Random::Secure seeds itself using L<Crypt::Random::Source>. The
underlying implementation uses F</dev/urandom> on Unix-like platforms, and the
C<RtlGenRandom> or C<CryptGenRandom> functions on Windows 2000 and
above. (There is no support for versions of Windows before Windows 2000.)
If any of these seeding sources are not available and you have other
L<Crypt::Random::Source> modules installed, Math::Random::Secure will use
those other sources to seed itself.
=head2 Making Math::Random::Secure Even More Secure
We use F</dev/urandom> on Unix-like systems, because one of the requirements
of duplicating C<rand> is that we never block waiting for seed data,
and F</dev/random> could do that. However, it's possible that F</dev/urandom>
could run out of "truly random" data and start to use its built-in
pseudo-random number generator to generate data. On most systems, this should
still provide a very good seed for nearly all uses, but it may not be suitable
for very high-security cryptographic circumstances.
For Windows, there are known issues with C<CryptGenRandom> on Windows 2000
and versions of Windows XP before Service Pack 3. However, there is no
other built-in method of getting secure random data on Windows, and I suspect
that these issues will not be significant for most applications of
Math::Random::Secure.
If either of these situations are a problem for your use, you can create
your own L<Math::Random::Secure::RNG> object with a different "seeder"
argument, and set C<$Math::Random::Secure::RNG> to your own instance of
L<Math::Random::Secure::RNG>. The "seeder" is an instance of
L<Crypt::Random::Source::Base>, which should allow you to use most
random-data sources in existence for your seeder, should you wish.
=head2 Seed Exhaustion
Perl's built-in C<srand> reads 32 bits from F</dev/urandom>. By default,
we read 512 bits. This means that we are more likely to exhaust available
truly-random data than the built-in C<srand> is, and cause F</dev/urandom>
to fall back on its psuedo-random number generator. Normally this is not
a problem, since L</srand> is only called once per Perl process or thread,
but it is something that you should be aware of if you are going to
be in a situation where you have many new Perl processes or threads
and you have very high security requirements (on the order of generating
private SSH or GPG keypairs, SSL private keys, etc.).
=head1 SEE ALSO
=over
=item L<http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator>
Describes the requirements and nature of a cryptographically-secure
random number generator.
=item L<http://en.wikipedia.org/wiki/CryptGenRandom>,
More information about the Windows functions we use to seed ourselves. The
article also has some information about the weaknesses in Windows 2000's
C<CryptGenRandom> implementation.
=item L<http://www.computerworld.com/s/article/9048438/Microsoft_confirms_that_XP_contains_random_number_generator_bug>
A news article about the Windows 2000/XP CryptGenRandom weakness, fixed
in Vista and XP Service Pack 3.
=item L<http://en.wikipedia.org/wiki/Random_number_generator_attack>
A description of ways to attack a random number generator, which can
help in understanding why such a generator needs to be secure.
=item L<Math::Random::Secure::RNG>
The underlying random-number generator and seeding code for
Math::Random::Secure.
=item L<Crypt::Source::Random>
=item L<Crypt::Random>
=item L<Math::TrulyRandom>
All of these modules contain generators for "truly random" data, but they
don't contain a simple C<rand> replacement and they can be very slow.
=back
=head1 SUPPORT
Right now, the best way to get support for Math::Random::Secure is to email
the author using the email address in the L</AUTHORS> section below.
=head1 BUGS
Math::Random::Secure is relatively new, as of December 2010, but the
modules that underlie it are very well-tested and have a long history.
However, the author still welcomes all feedback and bug reports, particularly
those having to do with the security assurances provided by this module.
You can report a bug by emailing C<bug-Math-Random-Secure@rt.cpan.org> or
by using the RT web interface at
L<https://rt.cpan.org/Ticket/Display.html?Queue=Math-Random-Secure>. If
your bug report is security-sensitive, you may also email it directly to the
author using the email address in the L</AUTHORS> section below.
=head1 AUTHORS
=over 4
=item *
Max Kanat-Alexander <mkanat@cpan.org>
=item *
Arthur Axel "fREW" Schmidt <math-random-secure@afoolishmanifesto.com>
=back
=head1 COPYRIGHT AND LICENSE
This software is Copyright (c) 2010 by BugzillaSource, Inc.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)
=cut
|