aboutsummaryrefslogtreecommitdiffstats
path: root/lib/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'lib/crypto')
-rw-r--r--lib/crypto/c_src/crypto.c26
-rw-r--r--lib/crypto/doc/src/crypto.xml125
-rw-r--r--lib/crypto/doc/src/crypto_app.xml18
-rw-r--r--lib/crypto/src/crypto.app.src2
-rw-r--r--lib/crypto/src/crypto.erl47
5 files changed, 208 insertions, 10 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 6957d25774..9a3ea07c97 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -179,6 +179,12 @@
# define HAVE_ECB_IVEC_BUG
#endif
+#define HAVE_RSA_SSLV23_PADDING
+#if defined(HAS_LIBRESSL) \
+ && LIBRESSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(2,6,1)
+# undef HAVE_RSA_SSLV23_PADDING
+#endif
+
#if defined(HAVE_CMAC)
#include <openssl/cmac.h>
#endif
@@ -659,7 +665,9 @@ static ERL_NIF_TERM atom_rsa_oaep_md;
static ERL_NIF_TERM atom_rsa_pad; /* backwards compatibility */
static ERL_NIF_TERM atom_rsa_padding;
static ERL_NIF_TERM atom_rsa_pkcs1_pss_padding;
+#ifdef HAVE_RSA_SSLV23_PADDING
static ERL_NIF_TERM atom_rsa_sslv23_padding;
+#endif
static ERL_NIF_TERM atom_rsa_x931_padding;
static ERL_NIF_TERM atom_rsa_pss_saltlen;
static ERL_NIF_TERM atom_sha224;
@@ -1064,7 +1072,9 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_rsa_pad = enif_make_atom(env,"rsa_pad"); /* backwards compatibility */
atom_rsa_padding = enif_make_atom(env,"rsa_padding");
atom_rsa_pkcs1_pss_padding = enif_make_atom(env,"rsa_pkcs1_pss_padding");
+#ifdef HAVE_RSA_SSLV23_PADDING
atom_rsa_sslv23_padding = enif_make_atom(env,"rsa_sslv23_padding");
+#endif
atom_rsa_x931_padding = enif_make_atom(env,"rsa_x931_padding");
atom_rsa_pss_saltlen = enif_make_atom(env,"rsa_pss_saltlen");
atom_sha224 = enif_make_atom(env,"sha224");
@@ -4449,8 +4459,10 @@ static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NI
opt->rsa_padding = RSA_PKCS1_PADDING;
} else if (tpl_terms[1] == atom_rsa_pkcs1_oaep_padding) {
opt->rsa_padding = RSA_PKCS1_OAEP_PADDING;
+#ifdef HAVE_RSA_SSLV23_PADDING
} else if (tpl_terms[1] == atom_rsa_sslv23_padding) {
opt->rsa_padding = RSA_SSLV23_PADDING;
+#endif
} else if (tpl_terms[1] == atom_rsa_x931_padding) {
opt->rsa_padding = RSA_X931_PADDING;
} else if (tpl_terms[1] == atom_rsa_no_padding) {
@@ -4516,7 +4528,10 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
#endif
PKeyCryptOptions crypt_opt;
ErlNifBinary in_bin, out_bin, tmp_bin;
- size_t outlen, tmplen;
+ size_t outlen;
+#ifdef HAVE_RSA_SSLV23_PADDING
+ size_t tmplen;
+#endif
int is_private = (argv[4] == atom_true),
is_encrypt = (argv[5] == atom_true);
int algo_init = 0;
@@ -4596,6 +4611,7 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
if (crypt_opt.signature_md != NULL
&& EVP_PKEY_CTX_set_signature_md(ctx, crypt_opt.signature_md) <= 0)
goto badarg;
+#ifdef HAVE_RSA_SSLV23_PADDING
if (crypt_opt.rsa_padding == RSA_SSLV23_PADDING) {
if (is_encrypt) {
RSA *rsa = EVP_PKEY_get1_RSA(pkey);
@@ -4607,9 +4623,11 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
in_bin = tmp_bin;
}
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0) goto badarg;
- } else {
+ } else
+#endif
+ {
if (EVP_PKEY_CTX_set_rsa_padding(ctx, crypt_opt.rsa_padding) <= 0) goto badarg;
- }
+ }
#ifdef HAVE_RSA_OAEP_MD
if (crypt_opt.rsa_padding == RSA_PKCS1_OAEP_PADDING) {
if (crypt_opt.rsa_oaep_md != NULL
@@ -4728,6 +4746,7 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
#endif
if ((i > 0) && argv[0] == atom_rsa && !is_encrypt) {
+#ifdef HAVE_RSA_SSLV23_PADDING
if (crypt_opt.rsa_padding == RSA_SSLV23_PADDING) {
RSA *rsa = EVP_PKEY_get1_RSA(pkey);
unsigned char *p;
@@ -4745,6 +4764,7 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
i = 1;
}
}
+#endif
}
if (tmp_bin.data != NULL) {
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 464799b320..3a5efd0bea 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -790,9 +790,16 @@
<seealso marker="stdlib:rand">random number generation</seealso>,
in order to generate cryptographically strong random numbers
(based on OpenSSL's <c>BN_rand_range</c>),
- 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
- <seealso marker="stdlib:rand#seed-1">rand:seed/1</seealso>.
+ <seealso marker="stdlib:rand#seed-1">rand:seed/1</seealso> and
+ <seealso marker="#rand_seed_s-0">rand_seed_s/0</seealso>.
+ </p>
+ <p>
+ When using the state object from this function the
+ <seealso marker="stdlib:rand">rand</seealso> functions using it
+ may throw exception <c>low_entropy</c> in case the random generator
+ failed due to lack of secure "randomness".
</p>
<p><em>Example</em></p>
<pre>
@@ -814,6 +821,120 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
See also
<seealso marker="stdlib:rand#seed_s-1">rand:seed_s/1</seealso>.
</p>
+ <p>
+ When using the state object from this function the
+ <seealso marker="stdlib:rand">rand</seealso> functions using it
+ may throw exception <c>low_entropy</c> in case the random generator
+ failed due to lack of secure "randomness".
+ </p>
+ <note>
+ <p>
+ The state returned from this function can not be used
+ to get a reproducable random sequence as from
+ the other
+ <seealso marker="stdlib:rand">rand</seealso>
+ functions,
+ since reproducability does not match cryptographically safe.
+ </p>
+ <p>
+ The only supported usage is to generate one distinct
+ random sequence from this start state.
+ </p>
+ </note>
+ </desc>
+ </func>
+
+ <func>
+ <name>rand_seed_alg(Alg) -> rand:state()</name>
+ <fsummary>Strong random number generation plugin state</fsummary>
+ <type>
+ <v>Alg = crypto | crypto_cache</v>
+ </type>
+ <desc>
+ <marker id="rand_seed_alg-1" />
+ <p>
+ Creates state object for
+ <seealso marker="stdlib:rand">random number generation</seealso>,
+ in order to generate cryptographically strong random numbers.
+ See also
+ <seealso marker="stdlib:rand#seed-1">rand:seed/1</seealso> and
+ <seealso marker="#rand_seed_alg_s-1">rand_seed_alg_s/1</seealso>.
+ </p>
+ <p>
+ When using the state object from this function the
+ <seealso marker="stdlib:rand">rand</seealso> functions using it
+ may throw exception <c>low_entropy</c> in case the random generator
+ failed due to lack of secure "randomness".
+ </p>
+ <p>
+ The cache size can be changed from its default value using the
+ <seealso marker="crypto_app">
+ crypto app's
+ </seealso> configuration parameter <c>rand_cache_size</c>.
+ </p>
+ <p><em>Example</em></p>
+ <pre>
+_ = crypto:rand_seed_alg(crypto_cache),
+_IntegerValue = rand:uniform(42), % [1; 42]
+_FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
+ </desc>
+ </func>
+
+ <func>
+ <name>rand_seed_alg_s(Alg) -> rand:state()</name>
+ <fsummary>Strong random number generation plugin state</fsummary>
+ <type>
+ <v>Alg = crypto | crypto_cache</v>
+ </type>
+ <desc>
+ <marker id="rand_seed_alg_s-1" />
+ <p>
+ Creates state object for
+ <seealso marker="stdlib:rand">random number generation</seealso>,
+ in order to generate cryptographically strongly random numbers.
+ See also
+ <seealso marker="stdlib:rand#seed_s-1">rand:seed_s/1</seealso>.
+ </p>
+ <p>
+ If <c>Alg</c> is <c>crypto</c> this function behaves exactly like
+ <seealso marker="#rand_seed_s-0">rand_seed_s/0</seealso>.
+ </p>
+ <p>
+ If <c>Alg</c> is <c>crypto_cache</c> this function
+ fetches random data with OpenSSL's <c>RAND_bytes</c>
+ and caches it for speed using an internal word size
+ of 56 bits that makes calculations fast on 64 bit machines.
+ </p>
+ <p>
+ When using the state object from this function the
+ <seealso marker="stdlib:rand">rand</seealso> functions using it
+ may throw exception <c>low_entropy</c> in case the random generator
+ failed due to lack of secure "randomness".
+ </p>
+ <p>
+ The cache size can be changed from its default value using the
+ <seealso marker="crypto_app">
+ crypto app's
+ </seealso> configuration parameter <c>rand_cache_size</c>.
+ </p>
+ <note>
+ <p>
+ The state returned from this function can not be used
+ to get a reproducable random sequence as from
+ the other
+ <seealso marker="stdlib:rand">rand</seealso>
+ functions,
+ since reproducability does not match cryptographically safe.
+ </p>
+ <p>
+ In fact since random data is cached some numbers may
+ get reproduced if you try, but this is unpredictable.
+ </p>
+ <p>
+ The only supported usage is to generate one distinct
+ random sequence from this start state.
+ </p>
+ </note>
</desc>
</func>
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.</p>
</item>
+ <tag><c>rand_cache_size = integer()</c></tag>
+ <item>
+ <p>
+ Sets the cache size in bytes to use by
+ <seealso marker="crypto#rand_seed_alg-1">
+ <c>crypto:rand_seed_alg(crypto_cache)</c>
+ </seealso> and
+ <seealso marker="crypto#rand_seed_alg_s-1">
+ <c>crypto:rand_seed_alg_s(crypto_cache)</c>
+ </seealso>.
+ 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.
+ </p>
+ </item>
</taglist>
</section>
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 1a1b4f98b5..df259d5419 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]).
@@ -317,9 +318,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: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().
@@ -335,12 +344,36 @@ 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) ->
+ CacheBits = ?CRYPTO_CACHE_BITS,
+ EnvCacheSize =
+ application:get_env(
+ 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 ->
+ Sz;
+ _ ->
+ Bytes
+ end,
+ {#{ type => crypto_cache,
+ bits => CacheBits,
+ next => fun ?MODULE:rand_cache_plugin_next/1},
+ {CacheBits, CacheSize, <<>>}}.
rand_plugin_next(Seed) ->
{bytes_to_integer(strong_rand_range(1 bsl 64)), Seed}.
@@ -351,6 +384,12 @@ rand_plugin_uniform(State) ->
rand_plugin_uniform(Max, State) ->
{bytes_to_integer(strong_rand_range(Max)) + 1, State}.
+rand_cache_plugin_next({CacheBits, CacheSize, <<>>}) ->
+ rand_cache_plugin_next(
+ {CacheBits, CacheSize, strong_rand_bytes(CacheSize)});
+rand_cache_plugin_next({CacheBits, CacheSize, Cache}) ->
+ <<I:CacheBits, NewCache/binary>> = Cache,
+ {I, {CacheBits, CacheSize, NewCache}}.
strong_rand_range(Range) when is_integer(Range), Range > 0 ->
BinRange = int_to_bin(Range),
@@ -398,7 +437,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.