From fa32c27baa8e806b99f467aa161dea9a2ca3fca8 Mon Sep 17 00:00:00 2001 From: Chris Hall Date: Thu, 28 Mar 2013 14:25:30 +1300 Subject: [PATCH] bug 9611: removing external dependency for password salt generator To address packaging issues with Crypt::Random::Source, this patch replaces the salt generation with a wrapper for /dev/urandom and /dev/random. The test plan for this patch is the same as that for the base patch for bug 9611. Signed-off-by: Galen Charlton --- C4/Auth.pm | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/C4/Auth.pm b/C4/Auth.pm index d0b17fd..267f4dc 100644 --- a/C4/Auth.pm +++ b/C4/Auth.pm @@ -24,7 +24,7 @@ use JSON qw/encode_json decode_json/; use URI::Escape; use CGI::Session; use Crypt::Eksblowfish::Bcrypt qw(bcrypt en_base64); -use Crypt::Random::Source; +use Fcntl qw/O_RDONLY/; # O_RDONLY is used in generate_salt require Exporter; use C4::Context; @@ -1474,23 +1474,83 @@ sub hash_password { my $settings = shift; unless( defined $settings ){ # if there are no settings, we need to create a salt and append settings # Set the cost to 8 and append a NULL - $settings = '$2a$08$'.en_base64(generate_salt('strong')); + $settings = '$2a$08$'.en_base64(generate_salt('weak', 16)); } # Encrypt it return bcrypt($password, $settings); } -# Return a random salt +=head2 generate_salt + + use C4::Auth; + my $salt = C4::Auth::generate_salt($strength, $length); + +=item strength + +For general password salting a C<$strength> of C is recommend, +For generating a server-salt a C<$strength> of C is recommended + +'strong' uses /dev/random which may block until sufficient entropy is acheived. +'weak' uses /dev/urandom and is non-blocking. + +=back + +=item length + +C<$length> is a positive integer which specifies the desired length of the returned string + +=back + +=cut + + +# the implementation of generate_salt is loosely based on Crypt::Random::Provider::File sub generate_salt { - my ($type) = @_; + # strength is 'strong' or 'weak' + # length is number of bytes to read, positive integer + my ($strength, $length) = @_; - if ($type eq 'strong') { - return Crypt::Random::Source::get_strong(16); - } else { - return Crypt::Random::Source::get_weak(16); + my $source; + + if( $length < 1 ){ + die "non-positive strength of '$strength' passed to C4::Auth::generate_salt\n"; + } + + if( $strength eq "strong" ){ + $source = '/dev/random'; # blocking + } else { + unless( $strength eq 'weak' ){ + warn "unsuppored strength of '$strength' passed to C4::Auth::generate_salt, defaulting to 'weak'\n"; + } + $source = '/dev/urandom'; # non-blocking + } + + sysopen SOURCE, $source, O_RDONLY + or die "failed to open source '$source' in C4::Auth::generate_salt\n"; + + # $bytes is the bytes just read + # $string is the concatenation of all the bytes read so far + my( $bytes, $string ) = ("", ""); + + # keep reading until we have $length bytes in $strength + while( length($string) < $length ){ + # return the number of bytes read, 0 (EOF), or -1 (ERROR) + my $return = sysread SOURCE, $bytes, $length - length($string); + + # if no bytes were read, keep reading (if using /dev/random it is possible there was insufficient entropy so this may block) + next unless $return; + if( $return == -1 ){ + die "error while reading from $source in C4::Auth::generate_salt\n"; } + + $string .= $bytes; + } + + close SOURCE; + return $string; } + sub checkpw { my ( $dbh, $userid, $password, $query ) = @_; -- 1.7.10.4