aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilherme Andrade <[email protected]>2017-03-18 12:57:19 +0000
committerGuilherme Andrade <[email protected]>2017-03-18 13:03:41 +0000
commite50f63fbb2c974b4b8ad50095ca0b16a846fc161 (patch)
treeb1bc8bc0c335ab4eff625843c49f1d89479de7cb
parentd07008a0562d1f83dcab144fdec9fd920deb2b96 (diff)
downloadotp-e50f63fbb2c974b4b8ad50095ca0b16a846fc161.tar.gz
otp-e50f63fbb2c974b4b8ad50095ca0b16a846fc161.tar.bz2
otp-e50f63fbb2c974b4b8ad50095ca0b16a846fc161.zip
Restyle crypto strong numeric generators
for usage in rand
-rw-r--r--lib/crypto/c_src/crypto.c33
-rw-r--r--lib/crypto/doc/src/crypto.xml28
-rw-r--r--lib/crypto/src/crypto.erl52
-rw-r--r--lib/crypto/test/crypto_SUITE.erl46
4 files changed, 70 insertions, 89 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 0e17279e62..b8ef08410c 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -429,7 +429,7 @@ static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
static ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_ctr_stream_encrypt(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 strong_rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM strong_rand_range_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_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -502,7 +502,7 @@ static ErlNifFunc nif_funcs[] = {
{"aes_ctr_stream_encrypt", 2, aes_ctr_stream_encrypt},
{"aes_ctr_stream_decrypt", 2, aes_ctr_stream_encrypt},
{"strong_rand_bytes_nif", 1, strong_rand_bytes_nif},
- {"strong_rand_uniform_nif", 2, strong_rand_uniform_nif},
+ {"strong_rand_range_nif", 1, strong_rand_range_nif},
{"rand_uniform_nif", 2, rand_uniform_nif},
{"mod_exp_nif", 4, mod_exp_nif},
{"dss_verify_nif", 4, dss_verify_nif},
@@ -2333,35 +2333,24 @@ static ERL_NIF_TERM bin_from_bn(ErlNifEnv* env, const BIGNUM *bn)
return term;
}
-static ERL_NIF_TERM strong_rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Lo,Hi) */
- BIGNUM *bn_from = NULL, *bn_to, *bn_rand;
- unsigned char* data;
- unsigned dlen;
+static ERL_NIF_TERM strong_rand_range_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Range) */
+ BIGNUM *bn_range, *bn_rand;
ERL_NIF_TERM ret;
- if (!get_bn_from_mpint(env, argv[0], &bn_from)
- || !get_bn_from_mpint(env, argv[1], &bn_rand)) {
- if (bn_from) BN_free(bn_from);
- return enif_make_badarg(env);
+ if(!get_bn_from_bin(env, argv[0], &bn_range)) {
+ return enif_make_badarg(env);
}
- bn_to = BN_new();
- BN_sub(bn_to, bn_rand, bn_from);
- if (BN_rand_range(bn_rand, bn_to) != 1) {
+ bn_rand = BN_new();
+ if (BN_rand_range(bn_rand, bn_range) != 1) {
ret = atom_false;
}
else {
- BN_add(bn_rand, bn_rand, bn_from);
- 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);
+ ret = bin_from_bn(env, bn_rand);
}
BN_free(bn_rand);
- BN_free(bn_from);
- BN_free(bn_to);
+ BN_free(bn_range);
return ret;
}
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 0697f6a202..dc725a41be 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -662,8 +662,8 @@
you are running on does not have enough "randomness" built in.
Normally this is when either
<seealso marker="#strong_rand_bytes/1">strong_rand_bytes/1</seealso>,
- <seealso marker="#strong_rand_uniform/0">strong_rand_uniform/0</seealso> or
- <seealso marker="#strong_rand_uniform/1">strong_rand_uniform/1</seealso>
+ <seealso marker="#strong_rand_range/1">strong_rand_range/1</seealso> or
+ <seealso marker="#strong_rand_float/0">strong_rand_float/0</seealso>
throws <c>low_entropy</c></p>
</desc>
</func>
@@ -733,36 +733,36 @@
</func>
<func>
- <name>strong_rand_uniform() -> X</name>
- <fsummary>Generate a random floating point number between 0.0 and 1.0</fsummary>
+ <name>strong_rand_range(N) -> binary()</name>
+ <fsummary>Generate a random non-negative integer between 0 and N</fsummary>
<type>
- <v>X = float()</v>
+ <v>N = pos_integer() | binary()</v>
</type>
<desc>
- <p>Generates a random floating pointer number uniformly distributed
- in the value range <c><![CDATA[X, 0.0 < X < 1.0.]]></c>
+ <p>Generates a random non-negative integer uniformly distributed
+ in the value range <c><![CDATA[X, 0 =< X < N.]]></c>
Uses a cryptographically secure prng seeded and periodically mixed with operating system
provided entropy. By default this is the <c>BN_rand_range</c> method from OpenSSL.</p>
+ <p>Returns binary representation.</p>
<p>May throw exception <c>low_entropy</c> in case the random generator
failed due to lack of secure "randomness".</p>
- <note><p>The generated values shall present no more than 51 bits of effective entropy.</p></note>
</desc>
</func>
<func>
- <name>strong_rand_uniform(N) -> X</name>
- <fsummary>Generate a random positive integer between 1 and N</fsummary>
+ <name>strong_rand_float() -> X</name>
+ <fsummary>Generate a random floating point number between 0.0 and 1.0</fsummary>
<type>
- <v>N = pos_integer()</v>
- <v>X = 1..N</v>
+ <v>X = float()</v>
</type>
<desc>
- <p>Generates a a random positive integer uniformly distributed
- in the value range <c><![CDATA[X, 1 =< X =< N.]]></c>
+ <p>Generates a random floating pointer number uniformly distributed
+ in the value range <c><![CDATA[X, 0.0 =< X < 1.0.]]></c>
Uses a cryptographically secure prng seeded and periodically mixed with operating system
provided entropy. By default this is the <c>BN_rand_range</c> method from OpenSSL.</p>
<p>May throw exception <c>low_entropy</c> in case the random generator
failed due to lack of secure "randomness".</p>
+ <note><p>The generated values shall present no more than 51 bits of effective entropy.</p></note>
</desc>
</func>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 4b386924cb..2c3208a3d5 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -30,8 +30,8 @@
-export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
-export([cmac/3, cmac/4]).
-export([exor/2, strong_rand_bytes/1, mod_pow/3]).
--export([strong_rand_uniform/0]).
--export([strong_rand_uniform/1]).
+-export([strong_rand_range/1]).
+-export([strong_rand_float/0]).
-export([rand_uniform/2]).
-export([block_encrypt/3, block_decrypt/3, block_encrypt/4, block_decrypt/4]).
-export([next_iv/2, next_iv/3]).
@@ -288,8 +288,8 @@ stream_decrypt(State, Data0) ->
%% RAND - pseudo random numbers using RN_ and BN_ functions in crypto lib
%%
-spec strong_rand_bytes(non_neg_integer()) -> binary().
--spec strong_rand_uniform() -> float().
--spec strong_rand_uniform(pos_integer()) -> pos_integer().
+-spec strong_rand_range(pos_integer() | binary()) -> binary().
+-spec strong_rand_float() -> float().
-spec rand_uniform(crypto_integer(), crypto_integer()) ->
crypto_integer().
@@ -301,36 +301,28 @@ strong_rand_bytes(Bytes) ->
strong_rand_bytes_nif(_Bytes) -> ?nif_stub.
-strong_rand_uniform() ->
- Sign = 0, % positive
- Exponent = 1023, % on the interval [1.0, 2.0[
- Fraction = strong_rand_uniform(1, 1 bsl 52), % the whole interval above (except 1.0)
- <<Value:64/big-float>> = <<Sign:1, Exponent:11, Fraction:52>>,
- Value - 1.0.
-
-strong_rand_uniform(N) when is_integer(N), N >= 1 ->
- 1 + strong_rand_uniform(0, N).
-
-strong_rand_uniform(From, To) when is_binary(From), is_binary(To) ->
- case strong_rand_uniform_nif(From,To) of
+strong_rand_range(Range) when is_integer(Range), Range > 0 ->
+ BinRange = int_to_bin(Range),
+ strong_rand_range(BinRange);
+strong_rand_range(BinRange) when is_binary(BinRange) ->
+ case strong_rand_range_nif(BinRange) of
false ->
erlang:error(low_entropy);
- <<Len:32/integer, MSB, Rest/binary>> when MSB > 127 ->
- <<(Len + 1):32/integer, 0, MSB, Rest/binary>>;
- Whatever ->
- Whatever
- end;
-strong_rand_uniform(From, To) when is_integer(From), is_integer(To), From < To ->
- BinFrom = mpint(From),
- BinTo = mpint(To),
- case strong_rand_uniform(BinFrom, BinTo) of
- Result when is_binary(Result) ->
- erlint(Result);
- Other ->
- Other
+ <<BinResult/binary>> ->
+ BinResult
end.
-strong_rand_uniform_nif(_From, _To) -> ?nif_stub.
+strong_rand_range_nif(_BinRange) -> ?nif_stub.
+
+
+strong_rand_float() ->
+ % This could be optimized by having its own NIF
+ Sign = 0, % positive
+ Exponent = 1023, % on the interval [1.0, 2.0[
+ BinFraction = strong_rand_range(1 bsl 52), % the whole interval above
+ Fraction = bin_to_int(BinFraction),
+ <<Value:64/big-float>> = <<Sign:1, Exponent:11, Fraction:52>>,
+ Value - 1.0.
rand_uniform(From,To) when is_binary(From), is_binary(To) ->
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 6e3a3879c4..0d80786fbc 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -37,8 +37,8 @@ all() ->
mod_pow,
exor,
rand_uniform,
- strong_rand_uniform_float,
- strong_rand_uniform_integer
+ strong_rand_range,
+ strong_rand_float
].
groups() ->
@@ -488,43 +488,43 @@ rand_uniform(Config) when is_list(Config) ->
10 = byte_size(crypto:strong_rand_bytes(10)).
%%--------------------------------------------------------------------
-strong_rand_uniform_float() ->
- [{doc, "strong_rand_uniform float testing"}].
-strong_rand_uniform_float(Config) when is_list(Config) ->
- Samples = [crypto:strong_rand_uniform() || _ <- lists:seq(1, 10000)],
- allmap(
- fun (V) ->
- (V >= 0.0 andalso V < 1.0)
- orelse {false, ct:fail({"Not in interval", V, 0.0, 1.0})}
- end,
- Samples).
-
-strong_rand_uniform_integer() ->
- [{doc, "strong_rand_uniform integer testing"}].
-strong_rand_uniform_integer(Config) when is_list(Config) ->
+strong_rand_range() ->
+ [{doc, "strong_rand_range testing"}].
+strong_rand_range(Config) when is_list(Config) ->
MaxCeiling = 1 bsl 32,
- Ceilings = [1 | % edge case where the ceiling equals the floor
- [crypto:strong_rand_uniform(MaxCeiling)
+ Ceilings = [1 | % edge case where only 0 can be generated
+ [binary:decode_unsigned(crypto:strong_rand_range(MaxCeiling), big)
|| _ <- lists:seq(1, 99)]],
allmap(
fun (Ceiling) ->
- case Ceiling >= 1 andalso Ceiling =< MaxCeiling of
+ case Ceiling >= 0 andalso Ceiling < MaxCeiling of
false ->
- {false, ct:fail({"Ceiling not in interval", Ceiling, 1, MaxCeiling})};
+ {false, ct:fail({"Ceiling not in interval", Ceiling, 0, MaxCeiling})};
true ->
- Samples = [crypto:strong_rand_uniform(Ceiling)
+ Samples = [binary:decode_unsigned(crypto:strong_rand_range(Ceiling), big)
|| _ <- lists:seq(1, 100)],
allmap(
fun (V) ->
- (V >= 1 andalso V =< Ceiling)
- orelse {false, ct:fail({"Sample not in interval", V, 1, Ceiling})}
+ (V >= 0 andalso V < Ceiling)
+ orelse {false, ct:fail({"Sample not in interval", V, 0, Ceiling})}
end,
Samples)
end
end,
Ceilings).
+strong_rand_float() ->
+ [{doc, "strong_rand_float testing"}].
+strong_rand_float(Config) when is_list(Config) ->
+ Samples = [crypto:strong_rand_float() || _ <- lists:seq(1, 10000)],
+ allmap(
+ fun (V) ->
+ (V >= 0.0 andalso V < 1.0)
+ orelse {false, ct:fail({"Not in interval", V, 0.0, 1.0})}
+ end,
+ Samples).
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------