Is it possible to seed the Erlang :crypto
module? I expected this to be reproducible:
iex(1)> :crypto.rand_seed("42")
:ok
iex(2)> :crypto.strong_rand_bytes(2)
<<255, 203>>
iex(3)> :crypto.rand_seed("42")
:ok
iex(4)> :crypto.strong_rand_bytes(2)
<<81, 186>>
I expected both calls to :crypto.strong_rand_bytes(2)
to return the same binary but that is obviously not the case. Is there some other way to seed the :crypto
module?
From what I can see this is not possible. crypto
uses OpenSSL under the hood and OpenSSL mixes the seed with unpredictable data.
It seems the the underlying RAND_seed
function in OpenSSL actually calls RAND_add
. (see man RAND_seed
). According to :crypto.rand_seed
documentation it is only meant to be used when you get :low_entropy
back from the strong_rand_bytes
function.
If this is for testing another way to structure your code is to pass a “random” function to you code and replace that function with a dummy during testing.
I’ve been working on a system that auto-generates parts of our docs, primarily requests and responses. Since the responses contain new ID’s generated with Ecto.UUID.generate/0
the contents of the responses change each time I generate the docs.
Since it is not possible/straightforward to seed the :crypto
module I may need to to stub/mock out how the UUID’s are generated. For any UUID’s generated within the tests that would be relatively easy (since I have a uuid/0
function that just delegates to Ecto.UUID.generate/0
but I’d prefer not to have to change the actual implementation if possible. I also have to double-check if the UUID’s are being generated by Ecto or by Postgres.
As I recall strong random from :crypto
pulls from OpenSSL, which pulls from local system entropy, which is definitely not reproduceable in such a way, you’d be looking at the normal random modules instead for reproduceability.
1 Like