diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Crypto.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Crypto.pm index 9d6c4b443..e21ad0977 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Crypto.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Crypto.pm @@ -15,6 +15,17 @@ use Digest::MD5 qw(md5); use bytes; our $VERSION = '2.0.0'; +my $newIv; + +BEGIN { + eval { require Crypt::URandom; Crypt::URandom::urandom(16) }; + if ($@) { + $newIv = sub { return md5( rand() . time . {} ) }; + } + else { + $newIv = sub { return Crypt::URandom::urandom(16) }; + } +} our $msg; @@ -41,11 +52,11 @@ sub new { # @param key that secondary key # @return Crypt::Rijndael object sub _getCipher { - my ( $self, $key ) = @_; + my ( $self, $key, $iv ) = @_; $key ||= ""; - $self->{ciphers}->{$key} ||= + my $cipher = Crypt::Rijndael->new( md5( $self->{key}, $key ), $self->{mode} ); - return $self->{ciphers}->{$key}; + return $cipher; } ## @method string encrypt(string data) @@ -59,7 +70,12 @@ sub encrypt { my $l = bytes::length($data) % 16; $data .= "\0" x ( 16 - $l ) unless ( $l == 0 ); - eval { $data = encode_base64( $self->_getCipher->encrypt($data), '' ); }; + my $iv = $newIv->(); + eval { + $data = + encode_base64( $iv . $self->_getCipher->set_iv($iv)->encrypt($data), + '' ); + }; if ($@) { $msg = "Crypt::Rijndael error : $@"; return undef; @@ -81,7 +97,11 @@ sub decrypt { $data =~ s/%2F/\//ig; $data =~ s/%3D/=/ig; $data =~ s/%0A/\n/ig; - eval { $data = $self->_getCipher->decrypt( decode_base64($data) ); }; + $data = decode_base64($data); + my $iv; + $iv = bytes::substr( $data, 0, 16 ); + $data = bytes::substr( $data, 16 ); + eval { $data = $self->_getCipher->set_iv($iv)->decrypt($data); }; if ($@) { $msg = "Crypt::Rijndael error : $@"; return undef; diff --git a/lemonldap-ng-common/t/35-Common-Crypto.t b/lemonldap-ng-common/t/35-Common-Crypto.t index f926a55b7..d0edd23dc 100644 --- a/lemonldap-ng-common/t/35-Common-Crypto.t +++ b/lemonldap-ng-common/t/35-Common-Crypto.t @@ -30,7 +30,7 @@ foreach my $i ( 1 .. 17 ) { my $s = ''; $s = join( '', map { chr( int( rand(94) ) + 33 ) } ( 1 .. $i ) ); ok( $c->decrypt( $c->encrypt($s) ) eq $s, - "Test of base64 encrypting with $i characters string" ); + "Test of base64 encrypting with $i characters string" ) or diag "Source: $s\nCypher: ".$c->encrypt($s)."\nUncipher:".$c->decrypt( $c->encrypt($s)); } my $data = md5_hex(rand); @@ -42,6 +42,4 @@ ok( # Test a long value, and replace carriage return by %0A my $long = "f5a1f72e7ab2f7712855a068af0066f36bfcf2c87e6feb9cf4200da1868e1dfe"; -my $cryptedlong = -"Da6sYxp9NCXv8+8TirqHmPWwTQHyEGmkCBGCLCX/81dPSMwIQVQNV7X9KG3RrKZfyRmzJR6DZYdU%0Ab75+VH3+CA=="; -ok( $c->decrypt($cryptedlong) eq $long, "Test of long value encrypting" ); +ok( $c->decrypt($c->encrypt($long)) eq $long, "Test of long value encrypting" );