From 2181428bcad2abb3265e796e0b84b10830c74a76 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Wed, 6 Sep 2017 21:56:22 +0200
Subject: Implement crypto rand cache
---
lib/crypto/src/crypto.erl | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
(limited to 'lib')
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index d111525214..69c98c651f 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -30,11 +30,12 @@
-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([rand_seed/0]).
--export([rand_seed_s/0]).
+-export([rand_seed/0, rand_seed_alg/1]).
+-export([rand_seed_s/0, rand_seed_alg_s/1]).
-export([rand_plugin_next/1]).
-export([rand_plugin_uniform/1]).
-export([rand_plugin_uniform/2]).
+-export([rand_cache_plugin_next/1]).
-export([rand_uniform/2]).
-export([block_encrypt/3, block_decrypt/3, block_encrypt/4, block_decrypt/4]).
-export([next_iv/2, next_iv/3]).
@@ -299,6 +300,8 @@ stream_decrypt(State, Data0) ->
-spec strong_rand_bytes(non_neg_integer()) -> binary().
-spec rand_seed() -> rand:state().
-spec rand_seed_s() -> rand:state().
+-spec rand_seed_alg(Alg :: atom()) -> rand:state().
+-spec rand_seed_alg_s(Alg :: atom()) -> rand:state().
-spec rand_uniform(crypto_integer(), crypto_integer()) ->
crypto_integer().
@@ -314,12 +317,24 @@ rand_seed() ->
rand:seed(rand_seed_s()).
rand_seed_s() ->
+ rand_seed_alg_s(?MODULE).
+
+rand_seed_alg(Alg) ->
+ rand:seed(rand_seed_alg_s(Alg)).
+
+-define(CRYPTO_CACHE_BITS, 56).
+rand_seed_alg_s(?MODULE) ->
{#{ type => ?MODULE,
bits => 64,
next => fun ?MODULE:rand_plugin_next/1,
uniform => fun ?MODULE:rand_plugin_uniform/1,
uniform_n => fun ?MODULE:rand_plugin_uniform/2},
- no_seed}.
+ no_seed};
+rand_seed_alg_s(crypto_cache) ->
+ {#{ type => crypto_cache,
+ bits => ?CRYPTO_CACHE_BITS,
+ next => fun ?MODULE:rand_cache_plugin_next/1},
+ <<>>}.
rand_plugin_next(Seed) ->
{bytes_to_integer(strong_rand_range(1 bsl 64)), Seed}.
@@ -330,6 +345,11 @@ rand_plugin_uniform(State) ->
rand_plugin_uniform(Max, State) ->
{bytes_to_integer(strong_rand_range(Max)) + 1, State}.
+rand_cache_plugin_next(<<>>) ->
+ rand_cache_plugin_next(
+ strong_rand_bytes(?CRYPTO_CACHE_BITS * 16)); % Cache 16 * 8 words
+rand_cache_plugin_next(<>) ->
+ {I, Cache}.
strong_rand_range(Range) when is_integer(Range), Range > 0 ->
BinRange = int_to_bin(Range),
@@ -377,7 +397,7 @@ rand_uniform_nif(_From,_To) -> ?nif_stub.
-spec rand_seed(binary()) -> ok.
-rand_seed(Seed) ->
+rand_seed(Seed) when is_binary(Seed) ->
rand_seed_nif(Seed).
rand_seed_nif(_Seed) -> ?nif_stub.
--
cgit v1.2.3
From 32e3459206940ebfe6364f6936d7feb43bd27704 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Wed, 6 Sep 2017 23:43:33 +0200
Subject: Test crypto rand cache
Restructure measure test case
---
lib/stdlib/test/rand_SUITE.erl | 367 +++++++++++++++++++++--------------------
1 file changed, 186 insertions(+), 181 deletions(-)
(limited to 'lib')
diff --git a/lib/stdlib/test/rand_SUITE.erl b/lib/stdlib/test/rand_SUITE.erl
index 432293b656..f69d42551e 100644
--- a/lib/stdlib/test/rand_SUITE.erl
+++ b/lib/stdlib/test/rand_SUITE.erl
@@ -80,7 +80,7 @@ test() ->
end, Tests).
algs() ->
- [exs64, exsplus, exsp, exrop, exs1024, exs1024s].
+ [exrop, exsp, exs1024s, exs64, exsplus, exs1024].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -459,213 +459,233 @@ measure(Config) ->
{skip,{will_not_run_in_scaled_time,Scale}}
end.
+-define(CHECK_UNIFORM_RANGE(Gen, Range, X, St),
+ case (Gen) of
+ {(X), (St)} when is_integer(X), 1 =< (X), (X) =< (Range) ->
+ St
+ end).
+-define(CHECK_UNIFORM(Gen, X, St),
+ case (Gen) of
+ {(X), (St)} when is_float(X), 0.0 =< (X), (X) < 1.0 ->
+ St
+ end).
+-define(CHECK_UNIFORM_NZ(Gen, X, St),
+ case (Gen) of
+ {(X), (St)} when is_float(X), 0.0 < (X), (X) =< 1.0 ->
+ St
+ end).
+-define(CHECK_NORMAL(Gen, X, St),
+ case (Gen) of
+ {(X), (St)} when is_float(X) ->
+ St
+ end).
+
do_measure(_Config) ->
- Algos =
+ Algs =
+ algs() ++
try crypto:strong_rand_bytes(1) of
- <<_>> -> [crypto64, crypto]
+ <<_>> -> [crypto64, crypto_cache, crypto]
catch
error:low_entropy -> [];
error:undef -> []
- end ++ algs(),
+ end,
%%
- ct:pal("RNG uniform integer performance~n",[]),
- TMark1 =
+ ct:pal("~nRNG uniform integer range 10000 performance~n",[]),
+ _ =
measure_1(
- random,
fun (_) -> 10000 end,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
- _ =
- [measure_1(
- Algo,
- fun (_) -> 10000 end,
- TMark1,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
%%
- ct:pal("~nRNG uniform integer half range performance~n",[]),
- HalfRangeFun = fun (State) -> half_range(State) end,
- TMark2 =
- measure_1(
- random,
- HalfRangeFun,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
+ ct:pal("~nRNG uniform integer 32 bit performance~n",[]),
_ =
- [measure_1(
- Algo,
- HalfRangeFun,
- TMark2,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
- %%
- ct:pal("~nRNG uniform integer half range + 1 performance~n",[]),
- HalfRangePlus1Fun = fun (State) -> half_range(State) + 1 end,
- TMark3 =
measure_1(
- random,
- HalfRangePlus1Fun,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
+ fun (_) -> 1 bsl 32 end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
+ %%
+ ct:pal("~nRNG uniform integer half range + 1 performance~n",[]),
_ =
- [measure_1(
- Algo,
- HalfRangePlus1Fun,
- TMark3,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
+ measure_1(
+ fun (State) -> half_range(State) + 1 end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG uniform integer full range - 1 performance~n",[]),
- FullRangeMinus1Fun = fun (State) -> (half_range(State) bsl 1) - 1 end,
- TMark4 =
- measure_1(
- random,
- FullRangeMinus1Fun,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
_ =
- [measure_1(
- Algo,
- FullRangeMinus1Fun,
- TMark4,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
+ measure_1(
+ fun (State) -> (half_range(State) bsl 1) - 1 end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG uniform integer full range performance~n",[]),
- FullRangeFun = fun (State) -> half_range(State) bsl 1 end,
- TMark5 =
- measure_1(
- random,
- FullRangeFun,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
_ =
- [measure_1(
- Algo,
- FullRangeFun,
- TMark5,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
+ measure_1(
+ fun (State) -> half_range(State) bsl 1 end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG uniform integer full range + 1 performance~n",[]),
- FullRangePlus1Fun = fun (State) -> (half_range(State) bsl 1) + 1 end,
- TMark6 =
- measure_1(
- random,
- FullRangePlus1Fun,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
_ =
- [measure_1(
- Algo,
- FullRangePlus1Fun,
- TMark6,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
+ measure_1(
+ fun (State) -> (half_range(State) bsl 1) + 1 end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG uniform integer double range performance~n",[]),
- DoubleRangeFun = fun (State) -> half_range(State) bsl 2 end,
- TMark7 =
- measure_1(
- random,
- DoubleRangeFun,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
_ =
- [measure_1(
- Algo,
- DoubleRangeFun,
- TMark7,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
+ measure_1(
+ fun (State) ->
+ half_range(State) bsl 2
+ end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG uniform integer double range + 1 performance~n",[]),
- DoubleRangePlus1Fun = fun (State) -> (half_range(State) bsl 2) + 1 end,
- TMark8 =
+ _ =
measure_1(
- random,
- DoubleRangePlus1Fun,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
+ fun (State) ->
+ (half_range(State) bsl 2) + 1
+ end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
+ %%
+ ct:pal("~nRNG uniform integer 64 bit performance~n",[]),
_ =
- [measure_1(
- Algo,
- DoubleRangePlus1Fun,
- TMark8,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
+ measure_1(
+ fun (_) -> 1 bsl 64 end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG uniform float performance~n",[]),
- TMark9 =
- measure_1(
- random,
+ _ = measure_1(
fun (_) -> 0 end,
- undefined,
- fun (_, State) ->
- {uniform, random:uniform_s(State)}
- end),
- _ =
- [measure_1(
- Algo,
- fun (_) -> 0 end,
- TMark9,
- fun (_, State) ->
- {uniform, rand:uniform_s(State)}
- end) || Algo <- Algos],
+ fun (State, _, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM(Mod:uniform_s(St0), X, St)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG normal float performance~n",[]),
- io:format("~.12w: not implemented (too few bits)~n", [random]),
- _ = [measure_1(
- Algo,
- fun (_) -> 0 end,
- TMark9,
- fun (_, State) ->
- {normal, rand:normal_s(State)}
- end) || Algo <- Algos],
+ _ = measure_1(
+ fun (_) -> 0 end,
+ fun (State, _, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_NORMAL(Mod:normal_s(St0), X, St1)
+ end,
+ State)
+ end,
+ Algs),
ok.
-measure_1(Algo, RangeFun, TMark, Gen) ->
+measure_loop(Fun, State) ->
+ measure_loop(Fun, State, ?LOOP).
+%%
+measure_loop(Fun, State, N) when 0 < N ->
+ measure_loop(Fun, Fun(State), N-1);
+measure_loop(_, _, _) ->
+ ok.
+
+measure_1(RangeFun, Fun, Algs) ->
+ TMark = measure_1(RangeFun, Fun, hd(Algs), undefined),
+ [TMark] ++
+ [measure_1(RangeFun, Fun, Alg, TMark) || Alg <- tl(Algs)].
+
+measure_1(RangeFun, Fun, Alg, TMark) ->
Parent = self(),
- Seed =
- case Algo of
+ {Mod, State} =
+ case Alg of
crypto64 ->
- crypto64_seed();
+ {rand, crypto64_seed()};
+ crypto_cache ->
+ {rand, crypto:rand_seed_alg(crypto_cache)};
crypto ->
- crypto:rand_seed_s();
+ {rand, crypto:rand_seed_s()};
random ->
- random:seed(os:timestamp()), get(random_seed);
+ {random, random:seed(os:timestamp()), get(random_seed)};
_ ->
- rand:seed_s(Algo)
+ {rand, rand:seed_s(Alg)}
end,
- Range = RangeFun(Seed),
+ Range = RangeFun(State),
Pid = spawn_link(
fun() ->
- Fun = fun() -> measure_2(?LOOP, Range, Seed, Gen) end,
- {Time, ok} = timer:tc(Fun),
+ {Time, ok} = timer:tc(fun () -> Fun(State, Range, Mod) end),
Percent =
case TMark of
undefined -> 100;
@@ -673,7 +693,7 @@ measure_1(Algo, RangeFun, TMark, Gen) ->
end,
io:format(
"~.12w: ~p ns ~p% [16#~.16b]~n",
- [Algo, (Time * 1000 + 500) div ?LOOP, Percent, Range]),
+ [Alg, (Time * 1000 + 500) div ?LOOP, Percent, Range]),
Parent ! {self(), Time},
normal
end),
@@ -681,21 +701,6 @@ measure_1(Algo, RangeFun, TMark, Gen) ->
{Pid, Msg} -> Msg
end.
-measure_2(N, Range, State0, Fun) when N > 0 ->
- case Fun(Range, State0) of
- {int, {Random, State}}
- when is_integer(Random), Random >= 1, Random =< Range ->
- measure_2(N-1, Range, State, Fun);
- {uniform, {Random, State}}
- when is_float(Random), 0.0 =< Random, Random < 1.0 ->
- measure_2(N-1, Range, State, Fun);
- {normal, {Random, State}} when is_float(Random) ->
- measure_2(N-1, Range, State, Fun);
- Res ->
- exit({error, Res, State0})
- end;
-measure_2(0, _, _, _) -> ok.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% The jump sequence tests has two parts
%% for those with the functional API (jump/1)
--
cgit v1.2.3
From 29222f06f38e321e5a2ac8dae67ced92b6544bde Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Tue, 19 Sep 2017 15:33:53 +0200
Subject: Document crypto rand cache
---
lib/crypto/doc/src/crypto.xml | 111 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 109 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 89ef529c5d..5afab632cd 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -739,9 +739,16 @@
random number generation,
in order to generate cryptographically strong random numbers
(based on OpenSSL's BN_rand_range),
- and saves it on process dictionary before returning it as well.
+ and saves it in the process dictionary before returning it as well.
See also
- rand:seed/1.
+ rand:seed/1 and
+ rand_seed_s/0.
+
+
+ When using the state object from this function the
+ rand functions using it
+ may throw exception low_entropy in case the random generator
+ failed due to lack of secure "randomness".
Example
@@ -763,6 +770,106 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[
See also
rand:seed_s/1.
+
+ When using the state object from this function the
+ rand functions using it
+ may throw exception low_entropy in case the random generator
+ failed due to lack of secure "randomness".
+
+
+
+ The state returned from this function can not be used
+ to get a reproducable random sequence as from
+ the other
+ rand
+ functions,
+ since reproducability does not match cryptographically safe.
+
+
+ The only supported usage is to generate one distinct
+ random sequence from this start state.
+
+
+
+
+
+
+ rand_seed_alg(Alg) -> rand:state()
+ Strong random number generation plugin state
+
+ Alg = crypto | crypto_cache
+
+
+
+ Creates state object for
+ random number generation,
+ in order to generate cryptographically strong random numbers.
+ See also
+ rand:seed/1 and
+ rand_seed_alg_s/1.
+
+
+ When using the state object from this function the
+ rand functions using it
+ may throw exception low_entropy in case the random generator
+ failed due to lack of secure "randomness".
+
+ Example
+
+_ = crypto:rand_seed_alg(crypto_cache),
+_IntegerValue = rand:uniform(42), % [1; 42]
+_FloatValue = rand:uniform(). % [0.0; 1.0[
+
+
+
+
+ rand_seed_alg_s(Alg) -> rand:state()
+ Strong random number generation plugin state
+
+ Alg = crypto | crypto_cache
+
+
+
+ Creates state object for
+ random number generation,
+ in order to generate cryptographically strongly random numbers.
+ See also
+ rand:seed_s/1.
+
+
+ If Alg is crypto this function behaves exactly like
+ rand_seed_s/0.
+
+
+ If Alg is crypto_cache this function
+ fetches random data with OpenSSL's RAND_bytes
+ and caches it for speed using an internal word size
+ of 56 bits that makes calculations fast on 64 bit machines.
+
+
+ When using the state object from this function the
+ rand functions using it
+ may throw exception low_entropy in case the random generator
+ failed due to lack of secure "randomness".
+
+
+
+ The state returned from this function can not be used
+ to get a reproducable random sequence as from
+ the other
+ rand
+ functions,
+ since reproducability does not match cryptographically safe.
+
+
+ In fact since random data is cached some numbers may
+ get reproduced if you try, but this is unpredictable.
+
+
+ The only supported usage is to generate one distinct
+ random sequence from this start state.
+
+
--
cgit v1.2.3
From 7710c0d681a4b5f17253945dde0726de0e27cdcf Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Thu, 28 Sep 2017 14:48:44 +0200
Subject: Make cache size configurable
---
lib/crypto/doc/src/crypto.xml | 14 ++++++++++++++
lib/crypto/doc/src/crypto_app.xml | 18 ++++++++++++++++++
lib/crypto/src/crypto.app.src | 2 +-
lib/crypto/src/crypto.erl | 38 +++++++++++++++++++++++++++++---------
4 files changed, 62 insertions(+), 10 deletions(-)
(limited to 'lib')
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 5afab632cd..c32e3430ab 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -800,6 +800,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[
Alg = crypto | crypto_cache
+
Creates state object for
random number generation,
@@ -814,6 +815,12 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[
may throw exception low_entropy in case the random generator
failed due to lack of secure "randomness".
+
+ The cache size can be changed from its default value using the
+
+ crypto app's
+ configuration parameter rand_cache_size.
+
Example
_ = crypto:rand_seed_alg(crypto_cache),
@@ -829,6 +836,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[
Alg = crypto | crypto_cache
+
Creates state object for
random number generation,
@@ -852,6 +860,12 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[
may throw exception low_entropy in case the random generator
failed due to lack of secure "randomness".
+
+ The cache size can be changed from its default value using the
+
+ crypto app's
+ configuration parameter rand_cache_size.
+
The state returned from this function can not be used
diff --git a/lib/crypto/doc/src/crypto_app.xml b/lib/crypto/doc/src/crypto_app.xml
index ba22557480..8296b1bc77 100644
--- a/lib/crypto/doc/src/crypto_app.xml
+++ b/lib/crypto/doc/src/crypto_app.xml
@@ -68,6 +68,24 @@
thus the crypto module will fail to load. This mechanism
prevents the accidental use of non-validated algorithms.
+ rand_cache_size = integer()
+ -
+
+ Sets the cache size in bytes to use by
+
+ crypto:rand_seed_alg(crypto_cache)
+ and
+
+ crypto:rand_seed_alg_s(crypto_cache)
+ .
+ This parameter is read when a seed function is called,
+ and then kept in generators state object. It has a rather
+ small default value that causes reads of strong random bytes
+ about once per hundred calls for a random value.
+ The set value is rounded up to an integral number of words
+ of the size these seed functions use.
+
+
diff --git a/lib/crypto/src/crypto.app.src b/lib/crypto/src/crypto.app.src
index 1d3f35e465..492aa10e51 100644
--- a/lib/crypto/src/crypto.app.src
+++ b/lib/crypto/src/crypto.app.src
@@ -24,7 +24,7 @@
crypto_ec_curves]},
{registered, []},
{applications, [kernel, stdlib]},
- {env, [{fips_mode, false}]},
+ {env, [{fips_mode, false}, {rand_cache_size, 896}]},
{runtime_dependencies, ["erts-9.0","stdlib-3.4","kernel-5.3"]}]}.
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 69c98c651f..69ca884471 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -297,11 +297,17 @@ stream_decrypt(State, Data0) ->
%%
%% RAND - pseudo random numbers using RN_ and BN_ functions in crypto lib
%%
+-type rand_cache_seed() ::
+ nonempty_improper_list(non_neg_integer(), binary()).
-spec strong_rand_bytes(non_neg_integer()) -> binary().
-spec rand_seed() -> rand:state().
-spec rand_seed_s() -> rand:state().
--spec rand_seed_alg(Alg :: atom()) -> rand:state().
--spec rand_seed_alg_s(Alg :: atom()) -> rand:state().
+-spec rand_seed_alg(Alg :: atom()) ->
+ {rand:alg_handler(),
+ atom() | rand_cache_seed()}.
+-spec rand_seed_alg_s(Alg :: atom()) ->
+ {rand:alg_handler(),
+ atom() | rand_cache_seed()}.
-spec rand_uniform(crypto_integer(), crypto_integer()) ->
crypto_integer().
@@ -319,10 +325,12 @@ rand_seed() ->
rand_seed_s() ->
rand_seed_alg_s(?MODULE).
+-dialyzer({no_improper_lists, rand_seed_alg/1}).
rand_seed_alg(Alg) ->
rand:seed(rand_seed_alg_s(Alg)).
-
+
-define(CRYPTO_CACHE_BITS, 56).
+-dialyzer({no_improper_lists, rand_seed_alg_s/1}).
rand_seed_alg_s(?MODULE) ->
{#{ type => ?MODULE,
bits => 64,
@@ -331,10 +339,22 @@ rand_seed_alg_s(?MODULE) ->
uniform_n => fun ?MODULE:rand_plugin_uniform/2},
no_seed};
rand_seed_alg_s(crypto_cache) ->
+ EnvCacheSize =
+ application:get_env(
+ crypto, rand_cache_size,
+ ?CRYPTO_CACHE_BITS * 16), % Cache 16 * 8 words
+ Bytes = (?CRYPTO_CACHE_BITS + 7) div 8,
+ CacheSize =
+ case ((EnvCacheSize + (Bytes - 1)) div Bytes) * Bytes of
+ Sz when is_integer(Sz), Bytes =< Sz ->
+ Sz;
+ _ ->
+ Bytes
+ end,
{#{ type => crypto_cache,
bits => ?CRYPTO_CACHE_BITS,
next => fun ?MODULE:rand_cache_plugin_next/1},
- <<>>}.
+ [CacheSize|<<>>]}.
rand_plugin_next(Seed) ->
{bytes_to_integer(strong_rand_range(1 bsl 64)), Seed}.
@@ -345,11 +365,11 @@ rand_plugin_uniform(State) ->
rand_plugin_uniform(Max, State) ->
{bytes_to_integer(strong_rand_range(Max)) + 1, State}.
-rand_cache_plugin_next(<<>>) ->
- rand_cache_plugin_next(
- strong_rand_bytes(?CRYPTO_CACHE_BITS * 16)); % Cache 16 * 8 words
-rand_cache_plugin_next(<>) ->
- {I, Cache}.
+-dialyzer({no_improper_lists, rand_cache_plugin_next/1}).
+rand_cache_plugin_next([CacheSize|<<>>]) ->
+ rand_cache_plugin_next([CacheSize|strong_rand_bytes(CacheSize)]);
+rand_cache_plugin_next([CacheSize|<>]) ->
+ {I, [CacheSize|Cache]}.
strong_rand_range(Range) when is_integer(Range), Range > 0 ->
BinRange = int_to_bin(Range),
--
cgit v1.2.3
From a89405725c623d489643c2bd4a07ce626dccdcc3 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Mon, 2 Oct 2017 16:32:14 +0200
Subject: Future proof cache word size
---
lib/crypto/src/crypto.erl | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
(limited to 'lib')
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 69ca884471..2ca5e4db9e 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -325,12 +325,10 @@ rand_seed() ->
rand_seed_s() ->
rand_seed_alg_s(?MODULE).
--dialyzer({no_improper_lists, rand_seed_alg/1}).
rand_seed_alg(Alg) ->
rand:seed(rand_seed_alg_s(Alg)).
-define(CRYPTO_CACHE_BITS, 56).
--dialyzer({no_improper_lists, rand_seed_alg_s/1}).
rand_seed_alg_s(?MODULE) ->
{#{ type => ?MODULE,
bits => 64,
@@ -339,11 +337,11 @@ rand_seed_alg_s(?MODULE) ->
uniform_n => fun ?MODULE:rand_plugin_uniform/2},
no_seed};
rand_seed_alg_s(crypto_cache) ->
+ CacheBits = ?CRYPTO_CACHE_BITS,
EnvCacheSize =
application:get_env(
- crypto, rand_cache_size,
- ?CRYPTO_CACHE_BITS * 16), % Cache 16 * 8 words
- Bytes = (?CRYPTO_CACHE_BITS + 7) div 8,
+ crypto, rand_cache_size, CacheBits * 16), % Cache 16 * 8 words
+ Bytes = (CacheBits + 7) div 8,
CacheSize =
case ((EnvCacheSize + (Bytes - 1)) div Bytes) * Bytes of
Sz when is_integer(Sz), Bytes =< Sz ->
@@ -352,9 +350,9 @@ rand_seed_alg_s(crypto_cache) ->
Bytes
end,
{#{ type => crypto_cache,
- bits => ?CRYPTO_CACHE_BITS,
+ bits => CacheBits,
next => fun ?MODULE:rand_cache_plugin_next/1},
- [CacheSize|<<>>]}.
+ {CacheBits, CacheSize, <<>>}}.
rand_plugin_next(Seed) ->
{bytes_to_integer(strong_rand_range(1 bsl 64)), Seed}.
@@ -365,11 +363,12 @@ rand_plugin_uniform(State) ->
rand_plugin_uniform(Max, State) ->
{bytes_to_integer(strong_rand_range(Max)) + 1, State}.
--dialyzer({no_improper_lists, rand_cache_plugin_next/1}).
-rand_cache_plugin_next([CacheSize|<<>>]) ->
- rand_cache_plugin_next([CacheSize|strong_rand_bytes(CacheSize)]);
-rand_cache_plugin_next([CacheSize|<>]) ->
- {I, [CacheSize|Cache]}.
+rand_cache_plugin_next({CacheBits, CacheSize, <<>>}) ->
+ rand_cache_plugin_next(
+ {CacheBits, CacheSize, strong_rand_bytes(CacheSize)});
+rand_cache_plugin_next({CacheBits, CacheSize, Cache}) ->
+ <> = Cache,
+ {I, {CacheBits, CacheSize, NewCache}}.
strong_rand_range(Range) when is_integer(Range), Range > 0 ->
BinRange = int_to_bin(Range),
--
cgit v1.2.3