From f505644be64cd4844742b361a8ff411d70f4aa88 Mon Sep 17 00:00:00 2001 From: Niclas Eklund Date: Fri, 15 Apr 2011 15:49:42 +0200 Subject: [PATCH 1/3] Adds NIFs for cryptographically strong random number generation. Also adds documentation and unit tests. Thanks to Geoff Cant. --- lib/crypto/c_src/crypto.c | 60 ++++++++++++++++++++++++++ lib/crypto/doc/src/crypto.xml | 36 ++++++++++++++++ lib/crypto/src/crypto.erl | 15 +++++++ lib/crypto/test/crypto_SUITE.erl | 31 ++++++++++++- lib/ssh/src/ssh_bits.erl | 54 +++-------------------- lib/ssh/src/ssh_connection_handler.erl | 2 - 6 files changed, 146 insertions(+), 52 deletions(-) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index b8786f6f9427..d4139f0dfa20 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -134,7 +134,9 @@ static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_T static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rand_bytes_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM strong_rand_uniform_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -204,7 +206,9 @@ static ErlNifFunc nif_funcs[] = { {"aes_ctr_encrypt", 3, aes_ctr_encrypt}, {"aes_ctr_decrypt", 3, aes_ctr_encrypt}, {"rand_bytes", 1, rand_bytes_1}, + {"strong_rand_bytes_nif", 1, strong_rand_bytes_nif}, {"rand_bytes", 3, rand_bytes_3}, + {"strong_rand_uniform", 3, strong_rand_uniform_3}, {"rand_uniform_nif", 2, rand_uniform_nif}, {"mod_exp_nif", 3, mod_exp_nif}, {"dss_verify", 4, dss_verify}, @@ -704,6 +708,22 @@ static ERL_NIF_TERM rand_bytes_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar ERL_VALGRIND_MAKE_MEM_DEFINED(data, bytes); return ret; } +static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Bytes) */ + unsigned bytes; + unsigned char* data; + ERL_NIF_TERM ret; + if (!enif_get_uint(env, argv[0], &bytes)) { + return enif_make_badarg(env); + } + data = enif_make_new_binary(env, bytes, &ret); + if ( RAND_bytes(data, bytes) != 1) { + return atom_false; + } + ERL_VALGRIND_MAKE_MEM_DEFINED(data, bytes); + return ret; +} + static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Bytes, TopMask, BottomMask) */ unsigned bytes; @@ -724,6 +744,46 @@ static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar } return ret; } +static ERL_NIF_TERM strong_rand_uniform_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Bytes, TopMask, BottomMask) */ + unsigned bits; + BIGNUM *bn_rand; + int top, bottom; + unsigned char* data; + unsigned dlen; + ERL_NIF_TERM ret; + if (!enif_get_uint(env, argv[0], &bits) + || !enif_get_int(env, argv[1], &top) + || !enif_get_int(env, argv[2], &bottom)) { + return enif_make_badarg(env); + } + if (! (top == -1 || top == 0 || top == 1) ) { + return enif_make_badarg(env); + } + if (! (bottom == 0 || bottom == 1) ) { + return enif_make_badarg(env); + } + + bn_rand = BN_new(); + if (! bn_rand ) { + return enif_make_badarg(env); + } + + /* Get a (bits) bit random number */ + if (! BN_rand(bn_rand, bits, top, bottom) ) { + return enif_make_badarg(env); + } + + /* Copy the bignum into an erlang mpint binary. */ + dlen = BN_num_bytes(bn_rand); + data = enif_make_new_binary(env, dlen+4, &ret); + put_int32(data, dlen); + BN_bn2bin(bn_rand, data+4); + ERL_VALGRIND_MAKE_MEM_DEFINED(data+4, dlen); + BN_free(bn_rand); + + return ret; +} static int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp) { diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index c407350c4741..087e9ac00cbd 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -614,6 +614,19 @@ Mpint() = >]]> number generator.

+ + strong_rand_bytes(N) -> binary() + Generate a binary of random bytes + + N = integer() + + +

Generates N bytes randomly uniform 0..255, and returns the + result in a binary. Uses a cryptographically secure prng seeded and + periodically mixed with operating system provided entropy. By default + this is the RAND_bytes method from OpenSSL.

+
+
rand_uniform(Lo, Hi) -> N Generate a random number @@ -628,6 +641,29 @@ Mpint() = >]]> multi-precision integers.

+ + strong_rand_uniform(N, Top, Bottom) -> Mpint + Generate an N bit random number + + N = non_neg_integer() + Top = -1 | 0 | 1 + Bottom = 0 | 1 + Mpint = binary() + + +

Generate an N bit random number using OpenSSL's + cryptographically strong pseudo random number generator + BN_rand.

+

The parameter Top places constraints on the most + significant bits of the generated number. If Top is 1, then the + two most significant bits will be set to 1, if Top is 0, the + most significant bit will be 1, and if Top is -1 then no + constraints are applied and thus the generated number may be less than + N bits long.

+

If Bottom is 1, then the generated number is + constrained to be odd.

+
+
mod_exp(N, P, M) -> Result Perform N ^ P mod M diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index d6e2e033c088..153c7833a911 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -46,6 +46,7 @@ -export([rsa_private_encrypt/3, rsa_public_decrypt/3]). -export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]). -export([rand_bytes/1, rand_bytes/3, rand_uniform/2]). +-export([strong_rand_bytes/1, strong_rand_uniform/3]). -export([mod_exp/3, mpint/1, erlint/1]). %% -export([idea_cbc_encrypt/3, idea_cbc_decrypt/3]). -export([aes_cbc_128_encrypt/3, aes_cbc_128_decrypt/3]). @@ -68,6 +69,8 @@ des_ede3_cbc_encrypt, des_ede3_cbc_decrypt, aes_cfb_128_encrypt, aes_cfb_128_decrypt, rand_bytes, + strong_rand_bytes, + strong_rand_uniform, rand_uniform, mod_exp, dss_verify,dss_sign, @@ -361,11 +364,23 @@ aes_cfb_128_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. %% RAND - pseudo random numbers using RN_ functions in crypto lib %% -spec rand_bytes(non_neg_integer()) -> binary(). +-spec strong_rand_bytes(non_neg_integer()) -> binary(). -spec rand_uniform(crypto_integer(), crypto_integer()) -> crypto_integer(). +-spec strong_rand_uniform(Bits::non_neg_integer(), + Top::-1..1, + Bottom::0..1) -> binary(). rand_bytes(_Bytes) -> ?nif_stub. +strong_rand_bytes(Bytes) -> + case strong_rand_bytes_nif(Bytes) of + false -> erlang:error(low_entropy); + Bin -> Bin + end. +strong_rand_bytes_nif(_Bytes) -> ?nif_stub. + rand_bytes(_Bytes, _Topmask, _Bottommask) -> ?nif_stub. +strong_rand_uniform(_Bytes, _Topmask, _Bottommask) -> ?nif_stub. rand_uniform(From,To) when is_binary(From), is_binary(To) -> case rand_uniform_nif(From,To) of diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index fe8f8e69a0b6..1946d0148968 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -46,6 +46,7 @@ aes_ctr/1, mod_exp_test/1, rand_uniform_test/1, + strong_rand_uniform_test/1, rsa_verify_test/1, dsa_verify_test/1, rsa_sign_test/1, @@ -68,7 +69,8 @@ all() -> md5_mac_io, sha, sha_update, %% sha256, sha256_update, sha512,sha512_update, des_cbc, aes_cfb, aes_cbc, - aes_cbc_iter, aes_ctr, des_cbc_iter, des_ecb, rand_uniform_test, + aes_cbc_iter, aes_ctr, des_cbc_iter, des_ecb, + rand_uniform_test, strong_rand_uniform_test, rsa_verify_test, dsa_verify_test, rsa_sign_test, dsa_sign_test, rsa_encrypt_decrypt, dh, exor_test, rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64, @@ -708,6 +710,33 @@ rand_uniform_aux_test(N) -> ?line t(R1 < H), ?line rand_uniform_aux_test(N-1). +%% +%% +strong_rand_uniform_test(doc) -> + "strong_rand_uniform and strong_random_bytes testing"; +strong_rand_uniform_test(suite) -> + []; +strong_rand_uniform_test(Config) when is_list(Config) -> + strong_rand_uniform_aux_test(180), + ?line 10 = byte_size(crypto:strong_rand_bytes(10)). + +strong_rand_uniform_aux_test(0) -> + ?line t(crypto:strong_rand_uniform(0,0,0) =:= <<0,0,0,0>>), + ok; +strong_rand_uniform_aux_test(1) -> + ?line t(crypto:erlint(crypto:strong_rand_uniform(1,0,1)) =:= 1), + ?line rand_uniform_aux_test(0); +strong_rand_uniform_aux_test(N) -> + ?line t(sru_length(crypto:strong_rand_uniform(N,-1,0)) =< N), + ?line t(sru_length(crypto:strong_rand_uniform(N,0,0)) =:= N), + ?line t(crypto:erlint(crypto:strong_rand_uniform(N,0,1)) band 1 =:= 1), + ?line t(crypto:erlint(crypto:strong_rand_uniform(N,1,0)) bsr (N - 2) =:= 2#11), + ?line rand_uniform_aux_test(N-1). + +sru_length(Mpint) -> + I = crypto:erlint(Mpint), + length(erlang:integer_to_list(I, 2)). + %% %% %% diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl index 399581a0fd15..50bde83cdb89 100755 --- a/lib/ssh/src/ssh_bits.erl +++ b/lib/ssh/src/ssh_bits.erl @@ -34,7 +34,7 @@ %% integer utils -export([isize/1]). -export([irandom/1, irandom/3]). --export([random/1, random/3]). +-export([random/1]). -export([xor_bits/2, fill_bits/2]). -export([i2bin/2, bin2i/1]). @@ -401,9 +401,6 @@ xor_bits(XBits, YBits) -> irandom(Bits) -> irandom(Bits, 1, 0). -%% irandom_odd(Bits) -> -%% irandom(Bits, 1, 1). - %% %% irandom(N, Top, Bottom) %% @@ -414,57 +411,16 @@ irandom(Bits) -> %% Bot = 0 - do not set the least signifcant bit %% Bot = 1 - set the least signifcant bit (i.e always odd) %% -irandom(0, _Top, _Bottom) -> - 0; -irandom(Bits, Top, Bottom) -> - Bytes = (Bits+7) div 8, - Skip = (8-(Bits rem 8)) rem 8, - TMask = case Top of - 0 -> 0; - 1 -> 16#80; - 2 -> 16#c0 - end, - BMask = case Bottom of - 0 -> 0; - 1 -> (1 bsl Skip) - end, - <> = random(Bytes, TMask, BMask), - X. +irandom(Bits, Top, Bottom) when is_integer(Top), + 0 =< Top, Top =< 2 -> + crypto:erlint(crypto:strong_rand_uniform(Bits, Top - 1, Bottom)). %% %% random/1 %% Generate N random bytes %% random(N) -> - random(N, 0, 0). - -random(N, TMask, BMask) -> - list_to_binary(rnd(N, TMask, BMask)). - -%% random/3 -%% random(Bytes, TopMask, BotMask) -%% where -%% Bytes is the number of bytes to generate -%% TopMask is bitwised or'ed to the first byte -%% BotMask is bitwised or'ed to the last byte -%% -rnd(0, _TMask, _BMask) -> - []; -rnd(1, TMask, BMask) -> - [(rand8() bor TMask) bor BMask]; -rnd(N, TMask, BMask) -> - [(rand8() bor TMask) | rnd_n(N-1, BMask)]. - -rnd_n(1, BMask) -> - [rand8() bor BMask]; -rnd_n(I, BMask) -> - [rand8() | rnd_n(I-1, BMask)]. - -rand8() -> - (rand32() bsr 8) band 16#ff. - -rand32() -> - random:uniform(16#100000000) -1. + crypto:strong_rand_bytes(N). %% %% Base 64 encode/decode diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index 0ba11b0a26ce..a7340b280cac 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -106,8 +106,6 @@ peer_address(ConnectionHandler) -> %% initialize. %%-------------------------------------------------------------------- init([Role, Manager, Socket, SshOpts]) -> - {A,B,C} = erlang:now(), - random:seed(A, B, C), {NumVsn, StrVsn} = ssh_transport:versions(Role, SshOpts), ssh_bits:install_messages(ssh_transport:transport_messages(NumVsn)), {Protocol, Callback, CloseTag} = From c31065c750e37d5368398e9e2a741a1d4ec0588c Mon Sep 17 00:00:00 2001 From: Niclas Eklund Date: Mon, 18 Apr 2011 14:58:18 +0200 Subject: [PATCH 2/3] Fixed SSH appup, copyright headers SSH vsn and SSH release note. --- lib/crypto/src/crypto.erl | 2 +- lib/ssh/doc/src/notes.xml | 13 +++++++++++++ lib/ssh/src/ssh.appup.src | 26 ++++++++++++++++++-------- lib/ssh/src/ssh_bits.erl | 2 +- lib/ssh/src/ssh_connection_handler.erl | 2 +- lib/ssh/vsn.mk | 2 +- 6 files changed, 35 insertions(+), 12 deletions(-) diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 153c7833a911..99b683fce244 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml index af667b1a71e9..224b9d4af772 100644 --- a/lib/ssh/doc/src/notes.xml +++ b/lib/ssh/doc/src/notes.xml @@ -29,6 +29,19 @@ notes.xml +
Ssh 2.0.5 +
Improvements and New Features + + +

+ Strengthened random number generation. (Thanks to Geoff Cant)

+

+ Own Id: OTP-9225

+
+
+
+
+
Ssh 2.0.4
Fixed Bugs and Malfunctions diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src index 501da8ceb921..9be8c3c7d53a 100644 --- a/lib/ssh/src/ssh.appup.src +++ b/lib/ssh/src/ssh.appup.src @@ -19,34 +19,44 @@ {"%VSN%", [ - {"2.0.3", [{load_module, ssh_file, soft_purge, soft_purge, []}, + {"2.0.4", [{load_module, ssh_bits, soft_purge, soft_purge, []}, + {load_module, ssh_connection_handler, soft_purge, soft_purge, []}]}, + {"2.0.3", [{load_module, ssh_bits, soft_purge, soft_purge, []}, + {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, + {load_module, ssh_file, soft_purge, soft_purge, []}, {load_module, ssh, soft_purge, soft_purge, []}, {load_module, ssh_rsa, soft_purge, soft_purge, []}, {load_module, ssh_acceptor, soft_purge, soft_purge, []}, {load_module, ssh_transport, soft_purge, soft_purge, []}, {load_module, ssh_connection_manager, soft_purge, soft_purge, []}]}, - {"2.0.2", [{load_module, ssh_file, soft_purge, soft_purge, []}, + {"2.0.2", [{load_module, ssh_bits, soft_purge, soft_purge, []}, + {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, + {load_module, ssh_file, soft_purge, soft_purge, []}, {load_module, ssh, soft_purge, soft_purge, []}, {load_module, ssh_rsa, soft_purge, soft_purge, []}, {load_module, ssh_acceptor, soft_purge, soft_purge, []}, {load_module, ssh_transport, soft_purge, soft_purge, []}, - {load_module, ssh_connection_manager, soft_purge, soft_purge, []}]}, - {"2.0.1", [{restart_application, ssh}]} + {load_module, ssh_connection_manager, soft_purge, soft_purge, []}]} ], [ - {"2.0.3", [{load_module, ssh_file, soft_purge, soft_purge, []}, + {"2.0.4", [{load_module, ssh_bits, soft_purge, soft_purge, []}, + {load_module, ssh_connection_handler, soft_purge, soft_purge, []}]}, + {"2.0.3", [{load_module, ssh_bits, soft_purge, soft_purge, []}, + {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, + {load_module, ssh_file, soft_purge, soft_purge, []}, {load_module, ssh, soft_purge, soft_purge, []}, {load_module, ssh_rsa, soft_purge, soft_purge, []}, {load_module, ssh_acceptor, soft_purge, soft_purge, []}, {load_module, ssh_transport, soft_purge, soft_purge, []}, {load_module, ssh_connection_manager, soft_purge, soft_purge, []}]}, - {"2.0.2", [{load_module, ssh_file, soft_purge, soft_purge, []}, + {"2.0.2", [{load_module, ssh_bits, soft_purge, soft_purge, []}, + {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, + {load_module, ssh_file, soft_purge, soft_purge, []}, {load_module, ssh, soft_purge, soft_purge, []}, {load_module, ssh_rsa, soft_purge, soft_purge, []}, {load_module, ssh_acceptor, soft_purge, soft_purge, []}, {load_module, ssh_transport, soft_purge, soft_purge, []}, - {load_module, ssh_connection_manager, soft_purge, soft_purge, []}]}, - {"2.0.1", [{restart_application, ssh}]} + {load_module, ssh_connection_manager, soft_purge, soft_purge, []}]} ] }. diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl index 50bde83cdb89..ae89f3135569 100755 --- a/lib/ssh/src/ssh_bits.erl +++ b/lib/ssh/src/ssh_bits.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index a7340b280cac..2d82e6d77dc5 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index 51f9f4744651..8c9f671fd5d6 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,5 +1,5 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 2.0.4 +SSH_VSN = 2.0.5 APP_VSN = "ssh-$(SSH_VSN)" From afe36b58bb77012f94b19213ed9602c2eb9fd420 Mon Sep 17 00:00:00 2001 From: Niclas Eklund Date: Tue, 19 Apr 2011 13:35:29 +0200 Subject: [PATCH 3/3] Renamed the function strong_rand_uniform to strong_rand_mpint. Added some checks in crypto.erl and crypto.c. Changed ssh_bits to use strong_rand_mpint. --- lib/crypto/c_src/crypto.c | 25 +++++++++++---------- lib/crypto/doc/src/crypto.xml | 8 +++++-- lib/crypto/doc/src/notes.xml | 17 +++++++++++++- lib/crypto/src/crypto.erl | 20 ++++++++++++----- lib/crypto/test/crypto_SUITE.erl | 38 ++++++++++++++++---------------- lib/crypto/vsn.mk | 2 +- lib/ssh/src/ssh_bits.erl | 2 +- 7 files changed, 70 insertions(+), 42 deletions(-) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index d4139f0dfa20..3ebf62d87c12 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -136,7 +136,7 @@ static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM static ERL_NIF_TERM rand_bytes_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM strong_rand_uniform_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM strong_rand_mpint_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -208,7 +208,7 @@ static ErlNifFunc nif_funcs[] = { {"rand_bytes", 1, rand_bytes_1}, {"strong_rand_bytes_nif", 1, strong_rand_bytes_nif}, {"rand_bytes", 3, rand_bytes_3}, - {"strong_rand_uniform", 3, strong_rand_uniform_3}, + {"strong_rand_mpint_nif", 3, strong_rand_mpint_nif}, {"rand_uniform_nif", 2, rand_uniform_nif}, {"mod_exp_nif", 3, mod_exp_nif}, {"dss_verify", 4, dss_verify}, @@ -744,7 +744,7 @@ static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar } return ret; } -static ERL_NIF_TERM strong_rand_uniform_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM strong_rand_mpint_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Bytes, TopMask, BottomMask) */ unsigned bits; BIGNUM *bn_rand; @@ -770,16 +770,17 @@ static ERL_NIF_TERM strong_rand_uniform_3(ErlNifEnv* env, int argc, const ERL_NI } /* Get a (bits) bit random number */ - if (! BN_rand(bn_rand, bits, top, bottom) ) { - return enif_make_badarg(env); + if (!BN_rand(bn_rand, bits, top, bottom)) { + ret = atom_false; + } + else { + /* Copy the bignum into an erlang mpint binary. */ + dlen = BN_num_bytes(bn_rand); + data = enif_make_new_binary(env, dlen+4, &ret); + put_int32(data, dlen); + BN_bn2bin(bn_rand, data+4); + ERL_VALGRIND_MAKE_MEM_DEFINED(data+4, dlen); } - - /* Copy the bignum into an erlang mpint binary. */ - dlen = BN_num_bytes(bn_rand); - data = enif_make_new_binary(env, dlen+4, &ret); - put_int32(data, dlen); - BN_bn2bin(bn_rand, data+4); - ERL_VALGRIND_MAKE_MEM_DEFINED(data+4, dlen); BN_free(bn_rand); return ret; diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 087e9ac00cbd..dd40378f297b 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -4,7 +4,7 @@
- 19992010 + 19992011 Ericsson AB. All Rights Reserved. @@ -625,6 +625,8 @@ Mpint() = >]]> result in a binary. Uses a cryptographically secure prng seeded and periodically mixed with operating system provided entropy. By default this is the RAND_bytes method from OpenSSL.

+

May throw exception low_entropy in case the random generator + failed due to lack of secure "randomness".

@@ -642,7 +644,7 @@ Mpint() = >]]> - strong_rand_uniform(N, Top, Bottom) -> Mpint + strong_rand_mpint(N, Top, Bottom) -> Mpint Generate an N bit random number N = non_neg_integer() @@ -662,6 +664,8 @@ Mpint() = >]]> N bits long.

If Bottom is 1, then the generated number is constrained to be odd.

+

May throw exception low_entropy in case the random generator + failed due to lack of secure "randomness".

diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml index 5e9bda3920c4..ab1ffa9e5c83 100644 --- a/lib/crypto/doc/src/notes.xml +++ b/lib/crypto/doc/src/notes.xml @@ -4,7 +4,7 @@
- 19992010 + 19992011 Ericsson AB. All Rights Reserved. @@ -30,6 +30,21 @@

This document describes the changes made to the Crypto application.

+
Crypto 2.0.2.2 + +
Improvements and New Features + + +

+ Strengthened random number generation. (Thanks to Geoff Cant)

+

+ Own Id: OTP-9225

+
+
+
+ +
+
Crypto 2.0.2.1
Improvements and New Features diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 99b683fce244..cc7b3acc9c52 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -46,7 +46,7 @@ -export([rsa_private_encrypt/3, rsa_public_decrypt/3]). -export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]). -export([rand_bytes/1, rand_bytes/3, rand_uniform/2]). --export([strong_rand_bytes/1, strong_rand_uniform/3]). +-export([strong_rand_bytes/1, strong_rand_mpint/3]). -export([mod_exp/3, mpint/1, erlint/1]). %% -export([idea_cbc_encrypt/3, idea_cbc_decrypt/3]). -export([aes_cbc_128_encrypt/3, aes_cbc_128_decrypt/3]). @@ -70,7 +70,7 @@ aes_cfb_128_encrypt, aes_cfb_128_decrypt, rand_bytes, strong_rand_bytes, - strong_rand_uniform, + strong_rand_mpint, rand_uniform, mod_exp, dss_verify,dss_sign, @@ -367,11 +367,12 @@ aes_cfb_128_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. -spec strong_rand_bytes(non_neg_integer()) -> binary(). -spec rand_uniform(crypto_integer(), crypto_integer()) -> crypto_integer(). --spec strong_rand_uniform(Bits::non_neg_integer(), - Top::-1..1, - Bottom::0..1) -> binary(). +-spec strong_rand_mpint(Bits::non_neg_integer(), + Top::-1..1, + Bottom::0..1) -> binary(). rand_bytes(_Bytes) -> ?nif_stub. + strong_rand_bytes(Bytes) -> case strong_rand_bytes_nif(Bytes) of false -> erlang:error(low_entropy); @@ -380,7 +381,14 @@ strong_rand_bytes(Bytes) -> strong_rand_bytes_nif(_Bytes) -> ?nif_stub. rand_bytes(_Bytes, _Topmask, _Bottommask) -> ?nif_stub. -strong_rand_uniform(_Bytes, _Topmask, _Bottommask) -> ?nif_stub. + +strong_rand_mpint(Bits, Top, Bottom) -> + case strong_rand_mpint_nif(Bits,Top,Bottom) of + false -> erlang:error(low_entropy); + Bin -> Bin + end. +strong_rand_mpint_nif(_Bits, _Top, _Bottom) -> ?nif_stub. + rand_uniform(From,To) when is_binary(From), is_binary(To) -> case rand_uniform_nif(From,To) of diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 1946d0148968..854a8b4485c9 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -46,7 +46,7 @@ aes_ctr/1, mod_exp_test/1, rand_uniform_test/1, - strong_rand_uniform_test/1, + strong_rand_test/1, rsa_verify_test/1, dsa_verify_test/1, rsa_sign_test/1, @@ -70,7 +70,7 @@ all() -> %% sha256, sha256_update, sha512,sha512_update, des_cbc, aes_cfb, aes_cbc, aes_cbc_iter, aes_ctr, des_cbc_iter, des_ecb, - rand_uniform_test, strong_rand_uniform_test, + rand_uniform_test, strong_rand_test, rsa_verify_test, dsa_verify_test, rsa_sign_test, dsa_sign_test, rsa_encrypt_decrypt, dh, exor_test, rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64, @@ -712,26 +712,26 @@ rand_uniform_aux_test(N) -> %% %% -strong_rand_uniform_test(doc) -> - "strong_rand_uniform and strong_random_bytes testing"; -strong_rand_uniform_test(suite) -> +strong_rand_test(doc) -> + "strong_rand_mpint and strong_random_bytes testing"; +strong_rand_test(suite) -> []; -strong_rand_uniform_test(Config) when is_list(Config) -> - strong_rand_uniform_aux_test(180), +strong_rand_test(Config) when is_list(Config) -> + strong_rand_aux_test(180), ?line 10 = byte_size(crypto:strong_rand_bytes(10)). -strong_rand_uniform_aux_test(0) -> - ?line t(crypto:strong_rand_uniform(0,0,0) =:= <<0,0,0,0>>), +strong_rand_aux_test(0) -> + ?line t(crypto:strong_rand_mpint(0,0,0) =:= <<0,0,0,0>>), ok; -strong_rand_uniform_aux_test(1) -> - ?line t(crypto:erlint(crypto:strong_rand_uniform(1,0,1)) =:= 1), - ?line rand_uniform_aux_test(0); -strong_rand_uniform_aux_test(N) -> - ?line t(sru_length(crypto:strong_rand_uniform(N,-1,0)) =< N), - ?line t(sru_length(crypto:strong_rand_uniform(N,0,0)) =:= N), - ?line t(crypto:erlint(crypto:strong_rand_uniform(N,0,1)) band 1 =:= 1), - ?line t(crypto:erlint(crypto:strong_rand_uniform(N,1,0)) bsr (N - 2) =:= 2#11), - ?line rand_uniform_aux_test(N-1). +strong_rand_aux_test(1) -> + ?line t(crypto:erlint(crypto:strong_rand_mpint(1,0,1)) =:= 1), + ?line strong_rand_aux_test(0); +strong_rand_aux_test(N) -> + ?line t(sru_length(crypto:strong_rand_mpint(N,-1,0)) =< N), + ?line t(sru_length(crypto:strong_rand_mpint(N,0,0)) =:= N), + ?line t(crypto:erlint(crypto:strong_rand_mpint(N,0,1)) band 1 =:= 1), + ?line t(crypto:erlint(crypto:strong_rand_mpint(N,1,0)) bsr (N - 2) =:= 2#11), + ?line strong_rand_aux_test(N-1). sru_length(Mpint) -> I = crypto:erlint(Mpint), @@ -1126,7 +1126,7 @@ worker_loop(0, _) -> ok; worker_loop(N, Config) -> Funcs = { md5, md5_update, md5_mac, md5_mac_io, sha, sha_update, des_cbc, - aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, + aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, strong_rand_test, rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test }, F = element(random:uniform(size(Funcs)),Funcs), diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk index e2d6fd0b37a5..740c68d8fa8e 100644 --- a/lib/crypto/vsn.mk +++ b/lib/crypto/vsn.mk @@ -1 +1 @@ -CRYPTO_VSN = 2.0.2.1 +CRYPTO_VSN = 2.0.2.2 diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl index ae89f3135569..3f0a06575c91 100755 --- a/lib/ssh/src/ssh_bits.erl +++ b/lib/ssh/src/ssh_bits.erl @@ -413,7 +413,7 @@ irandom(Bits) -> %% irandom(Bits, Top, Bottom) when is_integer(Top), 0 =< Top, Top =< 2 -> - crypto:erlint(crypto:strong_rand_uniform(Bits, Top - 1, Bottom)). + crypto:erlint(crypto:strong_rand_mpint(Bits, Top - 1, Bottom)). %% %% random/1