aboutsummaryrefslogtreecommitdiffstats
path: root/lib/crypto
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2019-03-05 13:34:48 +0100
committerLoïc Hoguin <[email protected]>2019-03-06 12:42:40 +0100
commit2f0aff476c585524b4eb2d8edb13c5e7357c111d (patch)
treeafccd817f3334f7c55bb5835cdbbeb2c130137f4 /lib/crypto
parent1378b465cfa5e6eb2311bb633a0ebae1a8de3773 (diff)
downloadotp-2f0aff476c585524b4eb2d8edb13c5e7357c111d.tar.gz
otp-2f0aff476c585524b4eb2d8edb13c5e7357c111d.tar.bz2
otp-2f0aff476c585524b4eb2d8edb13c5e7357c111d.zip
Add crypto:cipher_info/1 and crypto:hash_info/1
Also adds some more aliases that contain the key length in their name.
Diffstat (limited to 'lib/crypto')
-rw-r--r--lib/crypto/c_src/atoms.c24
-rw-r--r--lib/crypto/c_src/atoms.h12
-rw-r--r--lib/crypto/c_src/cipher.c93
-rw-r--r--lib/crypto/c_src/cipher.h4
-rw-r--r--lib/crypto/c_src/crypto.c2
-rw-r--r--lib/crypto/c_src/hash.c26
-rw-r--r--lib/crypto/c_src/hash.h1
-rw-r--r--lib/crypto/src/crypto.erl15
-rw-r--r--lib/crypto/test/crypto_SUITE.erl21
9 files changed, 197 insertions, 1 deletions
diff --git a/lib/crypto/c_src/atoms.c b/lib/crypto/c_src/atoms.c
index 2e417da7f4..798c26c9bb 100644
--- a/lib/crypto/c_src/atoms.c
+++ b/lib/crypto/c_src/atoms.c
@@ -41,6 +41,18 @@ ERL_NIF_TERM atom_not_enabled;
ERL_NIF_TERM atom_not_supported;
#endif
+ERL_NIF_TERM atom_type;
+ERL_NIF_TERM atom_size;
+ERL_NIF_TERM atom_block_size;
+ERL_NIF_TERM atom_key_length;
+ERL_NIF_TERM atom_iv_length;
+ERL_NIF_TERM atom_mode;
+ERL_NIF_TERM atom_ecb_mode;
+ERL_NIF_TERM atom_cbc_mode;
+ERL_NIF_TERM atom_cfb_mode;
+ERL_NIF_TERM atom_ofb_mode;
+ERL_NIF_TERM atom_stream_cipher;
+
#if defined(HAVE_EC)
ERL_NIF_TERM atom_prime_field;
ERL_NIF_TERM atom_characteristic_two_field;
@@ -140,6 +152,18 @@ int init_atoms(ErlNifEnv *env, const ERL_NIF_TERM fips_mode, const ERL_NIF_TERM
atom_notsup = enif_make_atom(env,"notsup");
atom_digest = enif_make_atom(env,"digest");
+ atom_type = enif_make_atom(env,"type");
+ atom_size = enif_make_atom(env,"size");
+ atom_block_size = enif_make_atom(env,"block_size");
+ atom_key_length = enif_make_atom(env,"key_length");
+ atom_iv_length = enif_make_atom(env,"iv_length");
+ atom_mode = enif_make_atom(env,"mode");
+ atom_ecb_mode = enif_make_atom(env,"ecb_mode");
+ atom_cbc_mode = enif_make_atom(env,"cbc_mode");
+ atom_cfb_mode = enif_make_atom(env,"cfb_mode");
+ atom_ofb_mode = enif_make_atom(env,"ofb_mode");
+ atom_stream_cipher = enif_make_atom(env,"stream_cipher");
+
#if defined(HAVE_EC)
atom_prime_field = enif_make_atom(env,"prime_field");
atom_characteristic_two_field = enif_make_atom(env,"characteristic_two_field");
diff --git a/lib/crypto/c_src/atoms.h b/lib/crypto/c_src/atoms.h
index f15523d865..f8e9211459 100644
--- a/lib/crypto/c_src/atoms.h
+++ b/lib/crypto/c_src/atoms.h
@@ -45,6 +45,18 @@ extern ERL_NIF_TERM atom_not_enabled;
extern ERL_NIF_TERM atom_not_supported;
#endif
+extern ERL_NIF_TERM atom_type;
+extern ERL_NIF_TERM atom_size;
+extern ERL_NIF_TERM atom_block_size;
+extern ERL_NIF_TERM atom_key_length;
+extern ERL_NIF_TERM atom_iv_length;
+extern ERL_NIF_TERM atom_mode;
+extern ERL_NIF_TERM atom_ecb_mode;
+extern ERL_NIF_TERM atom_cbc_mode;
+extern ERL_NIF_TERM atom_cfb_mode;
+extern ERL_NIF_TERM atom_ofb_mode;
+extern ERL_NIF_TERM atom_stream_cipher;
+
#if defined(HAVE_EC)
extern ERL_NIF_TERM atom_prime_field;
extern ERL_NIF_TERM atom_characteristic_two_field;
diff --git a/lib/crypto/c_src/cipher.c b/lib/crypto/c_src/cipher.c
index f8e44b228a..c055a62654 100644
--- a/lib/crypto/c_src/cipher.c
+++ b/lib/crypto/c_src/cipher.c
@@ -67,14 +67,26 @@ static struct cipher_type_t cipher_types[] =
{{"aes_cfb8"}, {&EVP_aes_192_cfb8}, 24, NO_FIPS_CIPHER | AES_CFBx},
{{"aes_cfb8"}, {&EVP_aes_256_cfb8}, 32, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_128_cfb8"}, {&EVP_aes_128_cfb8}, 16, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_192_cfb8"}, {&EVP_aes_192_cfb8}, 24, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_256_cfb8"}, {&EVP_aes_256_cfb8}, 32, NO_FIPS_CIPHER | AES_CFBx},
+
{{"aes_cfb128"}, {&EVP_aes_128_cfb128}, 16, NO_FIPS_CIPHER | AES_CFBx},
{{"aes_cfb128"}, {&EVP_aes_192_cfb128}, 24, NO_FIPS_CIPHER | AES_CFBx},
{{"aes_cfb128"}, {&EVP_aes_256_cfb128}, 32, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_128_cfb128"}, {&EVP_aes_128_cfb128}, 16, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_192_cfb128"}, {&EVP_aes_192_cfb128}, 24, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_256_cfb128"}, {&EVP_aes_256_cfb128}, 32, NO_FIPS_CIPHER | AES_CFBx},
+
{{"aes_ecb"}, {&EVP_aes_128_ecb}, 16, ECB_BUG_0_9_8L},
{{"aes_ecb"}, {&EVP_aes_192_ecb}, 24, ECB_BUG_0_9_8L},
{{"aes_ecb"}, {&EVP_aes_256_ecb}, 32, ECB_BUG_0_9_8L},
+ {{"aes_128_ecb"}, {&EVP_aes_128_ecb}, 16, ECB_BUG_0_9_8L},
+ {{"aes_192_ecb"}, {&EVP_aes_192_ecb}, 24, ECB_BUG_0_9_8L},
+ {{"aes_256_ecb"}, {&EVP_aes_256_ecb}, 32, ECB_BUG_0_9_8L},
+
#if defined(HAVE_EVP_AES_CTR)
{{"aes_128_ctr"}, {&EVP_aes_128_ctr}, 16, 0},
{{"aes_192_ctr"}, {&EVP_aes_192_ctr}, 24, 0},
@@ -207,6 +219,87 @@ int cmp_cipher_types(const void *keyp, const void *elemp) {
}
+ERL_NIF_TERM cipher_info_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type) */
+ const struct cipher_type_t *cipherp;
+ const EVP_CIPHER *cipher;
+ ERL_NIF_TERM ret, ret_mode;
+ unsigned type;
+ unsigned long mode;
+
+ if ((cipherp = get_cipher_type_no_key(argv[0])) == NULL)
+ return enif_make_badarg(env);
+
+ if (FORBIDDEN_IN_FIPS(cipherp))
+ return enif_raise_exception(env, atom_notsup);
+ if ((cipher = cipherp->cipher.p) == NULL)
+ return enif_raise_exception(env, atom_notsup);
+
+ ret = enif_make_new_map(env);
+
+ type = EVP_CIPHER_type(cipher);
+ enif_make_map_put(env, ret, atom_type,
+ type == NID_undef ? atom_undefined : enif_make_int(env, type),
+ &ret);
+
+ enif_make_map_put(env, ret, atom_key_length,
+ enif_make_int(env, EVP_CIPHER_key_length(cipher)), &ret);
+ enif_make_map_put(env, ret, atom_iv_length,
+ enif_make_int(env, EVP_CIPHER_iv_length(cipher)), &ret);
+ enif_make_map_put(env, ret, atom_block_size,
+ enif_make_int(env, EVP_CIPHER_block_size(cipher)), &ret);
+
+ mode = EVP_CIPHER_mode(cipher);
+ switch (mode) {
+ case EVP_CIPH_ECB_MODE:
+ ret_mode = atom_ecb_mode;
+ break;
+
+ case EVP_CIPH_CBC_MODE:
+ ret_mode = atom_cbc_mode;
+ break;
+
+ case EVP_CIPH_CFB_MODE:
+ ret_mode = atom_cfb_mode;
+ break;
+
+ case EVP_CIPH_OFB_MODE:
+ ret_mode = atom_ofb_mode;
+ break;
+
+ case EVP_CIPH_STREAM_CIPHER:
+ ret_mode = atom_stream_cipher;
+ break;
+
+ default:
+ ret_mode = atom_undefined;
+ break;
+ }
+
+ enif_make_map_put(env, ret, atom_mode, ret_mode, &ret);
+
+ return ret;
+}
+
+const struct cipher_type_t* get_cipher_type_no_key(ERL_NIF_TERM type)
+{
+ struct cipher_type_t key;
+
+ key.type.atom = type;
+
+ return bsearch(&key, cipher_types, num_cipher_types, sizeof(cipher_types[0]), cmp_cipher_types_no_key);
+}
+
+int cmp_cipher_types_no_key(const void *keyp, const void *elemp) {
+ const struct cipher_type_t *key = keyp;
+ const struct cipher_type_t *elem = elemp;
+
+ if (key->type.atom < elem->type.atom) return -1;
+ else if (key->type.atom > elem->type.atom) return 1;
+ else /* key->type.atom == elem->type.atom */ return 0;
+}
+
+
ERL_NIF_TERM cipher_types_as_list(ErlNifEnv* env)
{
struct cipher_type_t* p;
diff --git a/lib/crypto/c_src/cipher.h b/lib/crypto/c_src/cipher.h
index 6b43afea99..b0d9d324e1 100644
--- a/lib/crypto/c_src/cipher.h
+++ b/lib/crypto/c_src/cipher.h
@@ -61,12 +61,16 @@ struct evp_cipher_ctx {
EVP_CIPHER_CTX* ctx;
};
+ERL_NIF_TERM cipher_info_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
int init_cipher_ctx(ErlNifEnv *env);
void init_cipher_types(ErlNifEnv* env);
+const struct cipher_type_t* get_cipher_type_no_key(ERL_NIF_TERM type);
const struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len);
int cmp_cipher_types(const void *keyp, const void *elemp);
+int cmp_cipher_types_no_key(const void *keyp, const void *elemp);
ERL_NIF_TERM cipher_types_as_list(ErlNifEnv* env);
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 06439c34b2..261590d9a5 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -67,6 +67,7 @@ static ErlNifFunc nif_funcs[] = {
{"info_fips", 0, info_fips, 0},
{"enable_fips_mode", 1, enable_fips_mode, 0},
{"algorithms", 0, algorithms, 0},
+ {"hash_info", 1, hash_info_nif, 0},
{"hash_nif", 2, hash_nif, 0},
{"hash_init_nif", 1, hash_init_nif, 0},
{"hash_update_nif", 2, hash_update_nif, 0},
@@ -78,6 +79,7 @@ static ErlNifFunc nif_funcs[] = {
{"hmac_final_nif", 1, hmac_final_nif, 0},
{"hmac_final_nif", 2, hmac_final_nif, 0},
{"cmac_nif", 3, cmac_nif, 0},
+ {"cipher_info_nif", 1, cipher_info_nif, 0},
{"block_crypt_nif", 5, block_crypt_nif, 0},
{"block_crypt_nif", 4, block_crypt_nif, 0},
{"aes_ige_crypt_nif", 4, aes_ige_crypt_nif, 0},
diff --git a/lib/crypto/c_src/hash.c b/lib/crypto/c_src/hash.c
index 457e9d071a..0a9f64acef 100644
--- a/lib/crypto/c_src/hash.c
+++ b/lib/crypto/c_src/hash.c
@@ -61,6 +61,32 @@ int init_hash_ctx(ErlNifEnv* env) {
#endif
}
+ERL_NIF_TERM hash_info_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type) */
+ struct digest_type_t *digp = NULL;
+ const EVP_MD *md;
+ ERL_NIF_TERM ret;
+
+ ASSERT(argc == 1);
+
+ if ((digp = get_digest_type(argv[0])) == NULL)
+ return enif_make_badarg(env);
+
+ if ((md = digp->md.p) == NULL)
+ return atom_notsup;
+
+ ret = enif_make_new_map(env);
+
+ enif_make_map_put(env, ret, atom_type,
+ enif_make_int(env, EVP_MD_type(md)), &ret);
+ enif_make_map_put(env, ret, atom_size,
+ enif_make_int(env, EVP_MD_size(md)), &ret);
+ enif_make_map_put(env, ret, atom_block_size,
+ enif_make_int(env, EVP_MD_block_size(md)), &ret);
+
+ return ret;
+}
+
ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Type, Data) */
struct digest_type_t *digp = NULL;
diff --git a/lib/crypto/c_src/hash.h b/lib/crypto/c_src/hash.h
index 8bae07f39a..92a25cedb7 100644
--- a/lib/crypto/c_src/hash.h
+++ b/lib/crypto/c_src/hash.h
@@ -25,6 +25,7 @@
int init_hash_ctx(ErlNifEnv *env);
+ERL_NIF_TERM hash_info_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM hash_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index fe8390c5b8..97a4a7a3f0 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -24,6 +24,7 @@
-export([start/0, stop/0, info_lib/0, info_fips/0, supports/0, enable_fips_mode/1,
version/0, bytes_to_integer/1]).
+-export([cipher_info/1, hash_info/1]).
-export([hash/2, hash_init/1, hash_update/2, hash_final/1]).
-export([sign/4, sign/5, verify/5, verify/6]).
-export([generate_key/2, generate_key/3, compute_key/4]).
@@ -403,6 +404,11 @@ enable_fips_mode(_) -> ?nif_stub.
-define(HASH_HASH_ALGORITHM, sha1() | sha2() | sha3() | blake2() | ripemd160 | compatibility_only_hash() ).
+-spec hash_info(Type) -> map() when Type :: ?HASH_HASH_ALGORITHM.
+
+hash_info(Type) ->
+ notsup_to_error(hash_info_nif(Type)).
+
-spec hash(Type, Data) -> Digest when Type :: ?HASH_HASH_ALGORITHM,
Data :: iodata(),
Digest :: binary().
@@ -531,6 +537,12 @@ poly1305(Key, Data) ->
%%%
%%%================================================================
+-spec cipher_info(Type) -> map() when Type :: block_cipher_with_iv()
+ | aead_cipher()
+ | block_cipher_without_iv().
+cipher_info(Type) ->
+ cipher_info_nif(Type).
+
%%%---- Block ciphers
%%%----------------------------------------------------------------
@@ -1726,6 +1738,7 @@ hash_update(State0, Data, _, MaxBytes) ->
State = notsup_to_error(hash_update_nif(State0, Increment)),
hash_update(State, Rest, erlang:byte_size(Rest), MaxBytes).
+hash_info_nif(_Hash) -> ?nif_stub.
hash_nif(_Hash, _Data) -> ?nif_stub.
hash_init_nif(_Hash) -> ?nif_stub.
hash_update_nif(_State, _Data) -> ?nif_stub.
@@ -1770,6 +1783,8 @@ poly1305_nif(_Key, _Data) -> ?nif_stub.
%% CIPHERS --------------------------------------------------------------------
+cipher_info_nif(_Type) -> ?nif_stub.
+
block_crypt_nif(_Type, _Key, _Ivec, _Text, _IsEncrypt) -> ?nif_stub.
block_crypt_nif(_Type, _Key, _Text, _IsEncrypt) -> ?nif_stub.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index ab6d88deb2..7257f4fb9f 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -40,7 +40,9 @@ all() ->
rand_uniform,
rand_threads,
rand_plugin,
- rand_plugin_s
+ rand_plugin_s,
+ cipher_info,
+ hash_info
].
groups() ->
@@ -666,6 +668,23 @@ rand_plugin_s(Config) when is_list(Config) ->
rand_plugin_aux(explicit_state).
%%--------------------------------------------------------------------
+cipher_info() ->
+ [{doc, "crypto cipher_info testing"}].
+cipher_info(Config) when is_list(Config) ->
+ #{type := _,key_length := _,iv_length := _,
+ block_size := _,mode := _} = crypto:cipher_info(aes_128_cbc),
+ {'EXIT',_} = (catch crypto:cipher_info(not_a_cipher)),
+ ok.
+
+%%--------------------------------------------------------------------
+hash_info() ->
+ [{doc, "crypto hash_info testing"}].
+hash_info(Config) when is_list(Config) ->
+ #{type := _,size := _,block_size := _} = crypto:hash_info(sha256),
+ {'EXIT',_} = (catch crypto:hash_info(not_a_hash)),
+ ok.
+
+%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
hash(_, [], []) ->