Codebase list libcryptx-perl / v0.022 lib / Crypt / PRNG.pm
v0.022

Tree @v0.022 (Download .tar.gz)

PRNG.pm @v0.022

fa7d5df
0debb3d
 
 
 
dc830a6
f8aad67
dc830a6
 
 
0debb3d
d89160b
0debb3d
dc830a6
 
 
 
 
 
 
 
 
 
2777419
618c2e3
dc830a6
 
618c2e3
2777419
618c2e3
 
 
 
 
 
 
2777419
d89160b
f8aad67
2777419
 
 
 
 
dc830a6
 
ce15e24
618c2e3
1e60383
 
ce15e24
dc830a6
1e60383
 
 
dc830a6
ce15e24
dc830a6
 
 
 
1e60383
 
 
dc830a6
1e60383
dc830a6
1e60383
 
dc830a6
 
 
 
 
 
757cd20
dc830a6
 
 
 
 
 
 
 
 
 
618c2e3
dc830a6
ce15e24
2777419
618c2e3
2777419
 
 
f8aad67
dc830a6
2777419
dc830a6
 
d89160b
 
 
 
 
 
 
 
 
 
dc830a6
 
 
 
 
 
 
 
2777419
 
 
f8aad67
 
2777419
 
 
 
f8aad67
2777419
 
 
 
 
 
 
 
 
 
 
 
 
 
ce15e24
2777419
 
 
f8aad67
2777419
 
 
 
 
 
 
 
618c2e3
dc830a6
2777419
dc830a6
 
 
2777419
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dc830a6
f8aad67
 
 
 
 
 
dc830a6
 
2777419
 
 
 
 
 
 
 
 
618c2e3
 
2777419
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dc830a6
 
 
d575413
dc830a6
2777419
 
 
 
 
dc830a6
2777419
 
dc830a6
618c2e3
 
 
dc830a6
618c2e3
 
 
 
 
 
 
ce15e24
dc830a6
 
2777419
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f8aad67
 
 
 
 
 
2777419
 
 
618c2e3
 
2777419
 
dc830a6
 
 
2777419
 
 
 
 
 
 
ce15e24
2777419
 
 
 
 
 
 
 
 
dc830a6
 
 
2777419
package Crypt::PRNG;

use strict;
use warnings;

use Exporter 'import';
our %EXPORT_TAGS = ( all => [qw(random_bytes random_bytes_hex random_bytes_b64 random_bytes_b64u random_string random_string_from rand irand)] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw();

use CryptX;
use MIME::Base64 qw(encode_base64);

sub _trans_prng_name {
  my $name = shift;
  $name =~ s/^Crypt::PRNG:://;
  return lc($name);
}

### METHODS

sub new {
  my $pkg = shift;
  my $prng_name = $pkg eq __PACKAGE__ ? _trans_prng_name(shift||'Fortuna') : _trans_prng_name($pkg);
  return _new($$, $prng_name, @_);
}

sub bytes  { return shift->_bytes($$, shift) }

sub int32  { return shift->_int32($$) }

sub double { return shift->_double($$, shift) }

sub bytes_hex { return unpack("H*", shift->bytes(shift)) }

sub bytes_b64 { return encode_base64(shift->bytes(shift), "") }

sub bytes_b64u { return _base64url_enc(shift->bytes(shift), "") }

sub string {
  my ($self, $len) = @_;
  return $self->string_from("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", $len);
}

sub string_from {
  my ($self, $chars, $len) = @_;

  $len = 20 unless defined $len;
  return unless $len > 0;
  return unless length($chars) > 0;

  my @ch = split(//, $chars);
  my $max_index = $#ch;
  return if $max_index > 65535;
  
  my $mask;
  for my $n (1..31) {
    $mask = (1<<$n) - 1;
    last if $mask >= $max_index;
  }

  my $upck = ($max_index > 255) ? "n*" : "C*";
  my $l = $len * 2;

  my $rv = '';
  my @r;
  while (length $rv < $len) {
    @r = unpack($upck, $self->bytes($l)) if scalar @r == 0;
    my $i = (shift @r) & $mask;
    next if $i > $max_index;
    $rv .= $ch[$i];
  }
  return $rv;
}

sub CLONE_SKIP { 1 } # prevent cloning

### FUNCTIONS

{
  ### stolen from Bytes::Random::Secure
  #
  # Instantiate our random number generator(s) inside of a lexical closure,
  # limiting the scope of the RNG object so it can't be tampered with.
  my $RNG_object = undef;
  my $fetch_RNG = sub { # Lazily, instantiate the RNG object, but only once.
    $RNG_object = Crypt::PRNG->new unless defined $RNG_object && ref($RNG_object) ne 'SCALAR';
    return $RNG_object;
  };
  sub rand               { return $fetch_RNG->()->double(@_) }
  sub irand              { return $fetch_RNG->()->int32() }
  sub random_bytes       { return $fetch_RNG->()->bytes(@_) }
  sub random_bytes_hex   { return $fetch_RNG->()->bytes_hex(@_) }
  sub random_bytes_b64   { return $fetch_RNG->()->bytes_b64(@_) }
  sub random_bytes_b64u  { return $fetch_RNG->()->bytes_b64u(@_) }
  sub random_string_from { return $fetch_RNG->()->string_from(@_) }
  sub random_string      { return $fetch_RNG->()->string(@_) }
}

# Base64 URL Safe hack as encode_base64url requires MIME::Base64 3.11+
sub _base64url_enc {
    # RFC 4648 Base64 URL Safe - https://tools.ietf.org/html/rfc4648#page-7
    my $data = shift;
    my $b64 = encode_base64($data, '');
    $b64 =~ s/=+\z//;
    $b64 =~ tr[+/][-_];
    return $b64;
}

1;

=pod

=head1 NAME

Crypt::PRNG - Cryptographically secure random number generator

=head1 SYNOPSIS

   ### Functional interface:
   use Crypt::PRNG qw(random_bytes random_bytes_hex random_bytes_b64 random_bytes_b64u
                      random_string random_string_from rand irand);

   $octets = random_bytes(45);
   $hex_string = random_bytes_hex(45);
   $base64_string = random_bytes_b64(45);
   $base64url_string = random_bytes_b64u(45);
   $alphanumeric_string = random_string(30);
   $string = random_string_from('ACGT', 64);
   $floating_point_number_0_to_1 = rand;
   $floating_point_number_0_to_88 = rand(88);
   $unsigned_32bit_int = irand;

   ### OO interface:
   use Crypt::PRNG;

   $prng = Crypt::PRNG->new;
   #or
   $prng = Crypt::PRNG->new("RC4");
   #or
   $prng = Crypt::PRNG->new("RC4", "some data used for seeding PRNG");

   $octets = $prng->bytes(45);
   $hex_string = $prng->bytes_hex(45);
   $base64_string = $prng->bytes_b64(45);
   $base64url_string = $prng->bytes_b64u(45);
   $alphanumeric_string = $prng->string(30);
   $string = $prng->string_from('ACGT', 64);
   $floating_point_number_0_to_1 = $prng->double;
   $floating_point_number_0_to_88 = $prng->double(88);
   $unsigned_32bit_int = $prng->int32;

=head1 DESCRIPTION

Provides an interface to the Fortuna based pseudo random number generator (thread-safe and fork-safe).

=head1 FUNCTIONS

=head2 random_bytes

   $octets = random_bytes($length);

Returns C<$length> random octects.

=head2 random_bytes_hex

   $hex_string = random_bytes_hex($length);

Returns C<$length> random octects encoded as hexadecimal string.

=head2 random_bytes_b64

   $base64_string = random_bytes_b64($length);

Returns C<$length> random octects Base64 encoded.

=head2 random_bytes_b64u

   $base64url_string = random_bytes_b64u($length);

Returns C<$length> random octects Base64 URL Safe (RFC 4648 section 5) encoded.

=head2 random_string_from

   $string = random_string_from($range, $length);
   #e.g.
   $string = random_string_from("ABCD", 10);

Returns a random string made of C<$length> chars randomly chosen from C<$range> string.

=head2 random_string

   $alphanumeric_string = random_string($length);
   #or
   $alphanumeric_string = random_string;  # default length = 20

Similar to random_string_from, only C<$range> is fixed to C<'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'>.

=head2 rand

   $n = rand;
   #or
   $n = rand($limit);

Returns a random floating point number from range C<[0,1)> (if called without param) or C<[0,$limit)>.

=head2 irand

   $i = irand;

Returns a random unsigned 32bit integer - range 0 .. 0xFFFFFFFF.

=head1 METHODS

=head2 new

   $prng = Crypt::PRNG->new;
   #or
   $prng = Crypt::PRNG->new($alg);
   #or
   $prng = Crypt::PRNG->new($alg, $seed);

   # $alg  ... algorithm name 'Frotuna' (DEFAULT), 'RC4', 'Sober128' or 'Yarrow'
   # $seed ... will be used as an initial entropy for seeding PRNG

If C<$seed> is not specified the PRNG is automatically seeded with 32bytes random data taken from C</dev/random> (UNIX) or C<CryptGenRandom> (Win32)

=head2 add_entropy

  $prng->add_entropy($random_data);
  #or
  $prng->add_entropy();

If called without parameter it uses 32bytes random data taken from C</dev/random> (UNIX) or C<CryptGenRandom> (Win32).

B<BEWARE:> you probably do not need this function at all as the module does automatic seeding on initialization as well as reseeding after fork and thread creation.

=head2 bytes

   $octets = $prng->bytes($length);

See L<random_bytes|/random_bytes>

=head2 bytes_hex

   $hex_string = $prng->bytes_hex($length);

See L<random_bytes_hex|/random_bytes_hex>

=head2 bytes_b64

   $base64_string = $prng->bytes_b64($length);

See L<random_bytes_b64|/random_bytes_b64>

=head2 bytes_b64u

   $base64url_string = $prng->bytes_b64u($length);

See L<random_bytes_b64u|/random_bytes_b64u>

=head2 string

   $alphanumeric_string = $prng->string($length);
   #or
   $alphanumeric_string = $prng->string;

See L<random_string|/random_string>

=head2 string_from

   $string = $prng->string_from($range, $length);

See L<random_string_from|/random_string_from>

=head2 double

   $n = $prng->double;
   #or
   $n = $prng->double($limit);

See L<rand|/rand>

=head2 int32

   $i = $prng->int32;

See L<irand|/irand>

=head1 SEE ALSO

L<Crypt::PRNG::Fortuna>, L<Crypt::PRNG::RC4>, L<Crypt::PRNG::Sober128>, L<Crypt::PRNG::Yarrow>