Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Handle low_entropy when generating random data.

We will now gracefully handle the case where
crypto:strong_rand_bytes throws low_entropy
by falling back on crypto:rand_bytes, its
weaker, pseudo-random sibling.

Since meck:ing away the crypto module seems difficult,
I ended up exporting a function strong_rand_bytes_proxy
from oauth2_token, so that it could be meck:ed into
throwing low_entropy for testing reasons.
  • Loading branch information...
commit dc0912bf5af8aa03e480665f096b581c4db7356e 1 parent d8fdc37
@mtornwall mtornwall authored
Showing with 48 additions and 1 deletion.
  1. +26 −1 src/oauth2_token.erl
  2. +22 −0 test/oauth2_token_tests.erl
View
27 src/oauth2_token.erl
@@ -33,6 +33,11 @@
generate/0
]).
+%%% Exported for testability
+-export([
+ strong_rand_bytes_proxy/1
+ ]).
+
%%%===================================================================
%%% API functions
%%%===================================================================
@@ -50,7 +55,7 @@ generate() ->
generate_fragment(0) ->
<<>>;
generate_fragment(N) ->
- Rand = base64:encode(crypto:strong_rand_bytes(N)),
+ Rand = base64:encode(rand_bytes(N)),
Frag = << <<C>> || <<C>> <= <<Rand:N/bytes>>, is_alphanum(C) >>,
<<Frag/binary, (generate_fragment(N - byte_size(Frag)))/binary>>.
@@ -64,3 +69,23 @@ is_alphanum(C) when C >= 16#61 andalso C =< 16#7A ->
true;
is_alphanum(_) ->
false.
+
+%% @doc Generate N random bytes, using the crypto:strong_rand_bytes
+%% function if sufficient entropy exists. If not, use crypto:rand_bytes
+%% as a fallback.
+-spec rand_bytes(N :: non_neg_integer()) -> binary().
+rand_bytes(N) ->
+ try
+ %% NOTE: Apparently we can't meck away the crypto module,
+ %% so we install this proxy to allow for testing the low_entropy
+ %% situation.
+ ?MODULE:strong_rand_bytes_proxy(N)
+ catch
+ throw:low_entropy ->
+ crypto:rand_bytes(N)
+ end.
+
+%% @equiv crypto:strong_rand_bytes(N)
+-spec strong_rand_bytes_proxy(N :: non_neg_integer()) -> binary().
+strong_rand_bytes_proxy(N) ->
+ crypto:strong_rand_bytes(N).
View
22 test/oauth2_token_tests.erl
@@ -38,6 +38,28 @@ generate_test() ->
?assertEqual(byte_size(Token), ?TOKEN_LENGTH),
?assert(lists:all(fun is_alphanum/1, binary_to_list(Token))).
+generate_low_entropy_test_() ->
+ {setup,
+ fun() ->
+ meck:new(oauth2_token, [passthrough]),
+ meck:expect(oauth2_token, strong_rand_bytes_proxy,
+ fun(_) -> throw(low_entropy) end)
+ end,
+ fun(_) ->
+ meck:unload(oauth2_token)
+ end,
+ fun(_) ->
+ [
+ ?_assertEqual(
+ byte_size(oauth2_token:generate()),
+ ?TOKEN_LENGTH),
+ ?_assert(
+ lists:all(fun is_alphanum/1,
+ binary_to_list(
+ oauth2_token:generate())))
+ ]
+ end}.
+
%%%===================================================================
%%% Utility functions
%%%===================================================================
Please sign in to comment.
Something went wrong with that request. Please try again.