diff --git a/debian/NEWS b/debian/NEWS index 63f3d7a50..c63e939db 100644 --- a/debian/NEWS +++ b/debian/NEWS @@ -1,3 +1,10 @@ +lemonldap-ng (2.0.5-1) unstable; urgency=medium + + This version adds some improvements in cryptographic functions. To take + advantage of them, you must change the encryption key of LemonLDAP::NG. + + -- Xavier Guimard Thu, 27 Jun 2019 23:19:09 +0200 + lemonldap-ng (2.0.0-1) unstable; urgency=medium 2.0 is a major release, many things have been changed. You must read diff --git a/debian/control b/debian/control index 47899d48f..08536b755 100644 --- a/debian/control +++ b/debian/control @@ -211,7 +211,8 @@ Recommends: libapache-session-browseable-perl, libdbi-perl, libhttp-parser-xs-perl, libjson-xs-perl, - liblwp-protocol-https-perl + liblwp-protocol-https-perl, + libstring-random-perl Suggests: libconvert-base32-perl, libnet-ldap-perl, libsoap-lite-perl, @@ -277,7 +278,6 @@ Recommends: libcrypt-openssl-bignum-perl, libgd-securityimage-perl, libmime-tools-perl, libnet-ldap-perl, - libstring-random-perl, libunicode-string-perl Suggests: libcrypt-u2f-server-perl, libdbi-perl, diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Crypto.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Crypto.pm index 02bb8a821..e4628a3b7 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Crypto.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Crypto.pm @@ -11,26 +11,31 @@ package Lemonldap::NG::Common::Crypto; use strict; use Crypt::Rijndael; use MIME::Base64; -use Digest::MD5 qw(md5); -use String::Random; +use Digest::SHA; use bytes; -our $VERSION = '2.1.0'; -my ( $newIv, $randG ); +our $VERSION = '2.0.0'; +my ( $newIv, $randG, $hash ); +$hash = \&Digest::SHA::sha256; + +use constant HMAC_LENGTH => 32; +use constant IV_LENGTH => 16; BEGIN { - eval { require Crypt::URandom; Crypt::URandom::urandom(16) }; + eval { require Crypt::URandom; Crypt::URandom::urandom(IV_LENGTH) }; if ($@) { - $newIv = sub { return md5( rand() . time . {} ) }; - $randG = sub { - my $a = 256; - $a = unpack( "C", Crypt::URandom::urandom(1) ) while ( $a > $_[0] ); - return $a; + $newIv = sub { + return bytes::substr( Digest::SHA::sha1( rand() . time . {} ), + 0, IV_LENGTH ); }; + $randG = sub { return int( rand( $_[0] ) ) }; } else { - $newIv = sub { return Crypt::URandom::urandom(16) }; - $randG = sub { return int( rand( $_[0] ) ) }; + $newIv = sub { return Crypt::URandom::urandom(IV_LENGTH) }; + $randG = sub { + return + int( unpack( "C", Crypt::URandom::urandom(1) ) * $_[0] / 256 ); + }; } } @@ -61,9 +66,9 @@ sub new { sub _getCipher { my ( $self, $key, $iv ) = @_; $key ||= ""; - my $cipher = - Crypt::Rijndael->new( md5( $self->{key}, $key ), $self->{mode} ); - return $cipher; + $self->{ciphers}->{$key} ||= + Crypt::Rijndael->new( $hash->( $self->{key}, $key ), $self->{mode} ); + return $self->{ciphers}->{$key}; } ## @method string encrypt(string data) @@ -77,8 +82,11 @@ sub encrypt { my $l = bytes::length($data) % 16; $data .= "\0" x ( 16 - $l ) unless ( $l == 0 ); - my $iv = $low ? md5( rand() . time . {} ) : $newIv->(); - my $hmac = md5($data); + my $iv = + $low + ? bytes::substr( Digest::SHA::sha1( rand() . time . {} ), 0, IV_LENGTH ) + : $newIv->(); + my $hmac = $hash->($data); eval { $data = encode_base64( @@ -108,17 +116,17 @@ sub decrypt { $data =~ s/%0A/\n/ig; $data = decode_base64($data); my $iv; - $iv = bytes::substr( $data, 0, 16 ); - $data = bytes::substr( $data, 16 ); + $iv = bytes::substr( $data, 0, IV_LENGTH ); + $data = bytes::substr( $data, IV_LENGTH ); eval { $data = $self->_getCipher->set_iv($iv)->decrypt($data); }; if ($@) { $msg = "Crypt::Rijndael error : $@"; return undef; } - my $hmac = bytes::substr( $data, 0, 16 ); - $data = bytes::substr( $data, 16 ); - if ( md5($data) ne $hmac ) { + my $hmac = bytes::substr( $data, 0, HMAC_LENGTH ); + $data = bytes::substr( $data, HMAC_LENGTH ); + if ( $hash->($data) ne $hmac ) { $msg = "Bad MAC"; return undef; } @@ -183,8 +191,8 @@ sub _cryptHex { } $data = pack "H*", $data; if ( $sub eq 'decrypt' ) { - $iv = bytes::substr( $data, 0, 16 ); - $data = bytes::substr( $data, 16 ); + $iv = bytes::substr( $data, 0, IV_LENGTH ); + $data = bytes::substr( $data, IV_LENGTH ); } eval { $data = $self->_getCipher($key)->set_iv($iv)->$sub($data); }; if ($@) { @@ -200,6 +208,10 @@ sub _cryptHex { } sub srandom { + eval { require String::Random }; + if ($@) { + die 'Missing recommended dependency to String::Random'; + } return String::Random->new( rand_gen => $randG ); } diff --git a/lemonldap-ng-common/scripts/rotateOidcKeys b/lemonldap-ng-common/scripts/rotateOidcKeys index 25d36c38b..8f69ea6a8 100755 --- a/lemonldap-ng-common/scripts/rotateOidcKeys +++ b/lemonldap-ng-common/scripts/rotateOidcKeys @@ -12,7 +12,7 @@ use strict; use Convert::PEM; use Crypt::OpenSSL::RSA; use Lemonldap::NG::Common::Conf; -use String::Random qw(random_string); +use Lemonldap::NG::Common::Crypto; my $debug = 0; @@ -28,9 +28,10 @@ print "Configuration loaded\n" if $debug; #============================================================================= # Generate new key #============================================================================= -my $rsa = Crypt::OpenSSL::RSA->generate_key(2048); -my $key_id = random_string("ssssssssss"); -my $keys = { +my $rsa = Crypt::OpenSSL::RSA->generate_key(2048); +my $key_id = + Lemonldap::NG::Common::Crypto::srandom()->randpattern("ssssssssss"); +my $keys = { 'private' => $rsa->get_private_key_string(), 'public' => $rsa->get_public_key_x509_string(), 'id' => $key_id, diff --git a/lemonldap-ng-portal/MANIFEST b/lemonldap-ng-portal/MANIFEST index f644dbb14..59e5811e3 100644 --- a/lemonldap-ng-portal/MANIFEST +++ b/lemonldap-ng-portal/MANIFEST @@ -532,6 +532,7 @@ t/61-GrantSession.t t/61-Session-ActivityTimeout.t t/61-Session-Timeout.t t/62-SingleSession.t +t/62-UpgradeSession.t t/63-History.t t/64-StayConnected.t t/65-AutoSignin.t @@ -552,7 +553,8 @@ t/68-Impersonation.t t/69-FavApps.t t/70-2F-TOTP-8.t t/70-2F-TOTP-with-History.t -t/70-2F-TOTP-with-TTL-and-msg.t +t/70-2F-TOTP-with-TTL-and-JSON.t +t/70-2F-TOTP-with-TTL-and-XML.t t/70-2F-TOTP-with-TTL.t t/71-2F-U2F-with-History.t t/71-2F-U2F-with-TTL-and-msg.t @@ -571,6 +573,7 @@ t/76-2F-Ext-with-GrantSession.t t/76-2F-Ext-with-History.t t/77-2F-Mail-with-global-storage.t t/77-2F-Mail.t +t/78-2F-Upgrade.t t/90-Translations.t t/99-pod.t t/gpghome/key.asc