Secure Password Generator in Perl

A secure and very random password generator module written in Perl.
It can be used to generate passwords or unique strings which can be used in sorts of operations.

The default character set is alpha-numerical based, but can be set to any kind of character list.

The complete handling and generating is implemented in a module, which exports one function: ‘generate_password’.
This function can take (optional) as arguments:

  • a length
  • a character list

The entropy is generated with Bytes::Random::Secure and random numbers are generated with Math::Random::ISAAC.

package MORETRIX::Password;
#===============================================================================
#  DESCRIPTION: A password generator module
#     REVISION: $Id: Password.pm 71 2013-07-02 12:28:42Z jmorano $
#===============================================================================

use strict;
use warnings;
use Digest;
use Exporter qw/import/;
use Time::HiRes qw/time/;
use Bytes::Random::Secure;
use Math::Random::ISAAC;

our @EXPORT    = qw/generate_password/;
our @EXPORT_OK = qw/generate_password/;

my $random_state;
my $CHARLIST = q{abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ!"$%&/\()=?{}[]*+#;:.,-_<>|^~'};

# Generate a cryptographic safe random password
# default length: 12
#
sub generate_password {
    my ($length, $charlist) = @_;
    $length   //= 12;
    $charlist //= $CHARLIST;

    my @temp_passwords;
    foreach my $loop ( 0 .. int(random_number(100)) ){
        my $password = '';
        while (length($password) < $length) {
            $password .= substr($charlist, (int(myrand(length($charlist)))), 1);
        }
        push @temp_passwords, $password;
    }

    return $temp_passwords[int(random_number(length(scalar @temp_passwords)))];
}

sub random_number {
    my ($seed) = @_;

    my $r = Math::Random::ISAAC->new($seed);
    return $r->rand();
}

sub mysrand{
    my $seed = shift || (time ^ $$ ^ int(random_number(time)) ^ int(random_number(2048 ^ 128)));
    $random_state = {
        digest => new Digest ("SHA-512"),
        counter => 0,
        waiting => [],
        prev    => $seed
    };
}

sub myrand{
    my $range = shift || 1.0;
    mysrand() unless defined $random_state;

    if (! @{$random_state->{waiting}}){
        $random_state->{digest}->reset();
        $random_state->{digest}->add( generate_entropy(4096) .
                                     $random_state->{counter}++ .
                                     $random_state->{prev});
        $random_state->{prev} = $random_state->{digest}->digest();
        my @ints = unpack("L*", $random_state->{prev}); # 32 bit unsigned integers
        $random_state->{waiting} = \@ints;
    }
    my $int = shift @{$random_state->{waiting}};
    return $range * $int / 2**32;
}

sub generate_entropy {
    my ($length) = @_;

    $length //= 1024;

    my $random = Bytes::Random::Secure->new( NonBlocking => 1, Bits => 4096 );
    return $random->string_from($CHARLIST, $length);
}

1;

Example script:

#!/usr/bin/env perl 

use strict;
use warnings;
use utf8;
use MORETIX::Password;

my $length = shift @ARGV;
$length //= 32;

print generate_password($length) . "\n";
print generate_password($length) . "\n";
print generate_password($length) . "\n";
print generate_password($length) . "\n";
print generate_password($length) . "\n";

References:

  • http://wellington.pm.org/archive/200704/randomness/#slide0

Comments

Secure Password Generator in Perl — 1 Comment

  1. Uses a homebrown random function which in turn uses rand() which is not cryptographically secure. Are you a cryptographer? Why reinvent the wheel?
    Why not use a known good function, one of those recommended in the documentation of the rand() function?
    Alternatively, use /dev/urandom.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.