aboutsummaryrefslogtreecommitdiffstats
path: root/lib/crypto
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2019-06-03 16:08:02 +0200
committerHans Nilsson <[email protected]>2019-06-14 13:33:07 +0200
commitde310ac450cf452b57150ea3abd65b74942d94fd (patch)
tree9a2e7fc48b9cf1ce0d6de4dc001df1fe56838026 /lib/crypto
parent45fe2d9fa1f9997bbdf6f50ef721f42204c812f0 (diff)
downloadotp-de310ac450cf452b57150ea3abd65b74942d94fd.tar.gz
otp-de310ac450cf452b57150ea3abd65b74942d94fd.tar.bz2
otp-de310ac450cf452b57150ea3abd65b74942d94fd.zip
crypto: Implement NIFs for the new mac_init, mac_update and mac_final
Use them for old HMAC functions. Also simplify hmac and cmac on the Erlang level
Diffstat (limited to 'lib/crypto')
-rw-r--r--lib/crypto/c_src/crypto.c13
-rw-r--r--lib/crypto/c_src/hmac.c11
-rw-r--r--lib/crypto/c_src/hmac.h3
-rw-r--r--lib/crypto/c_src/mac.c294
-rw-r--r--lib/crypto/c_src/mac.h5
-rw-r--r--lib/crypto/src/crypto.erl75
6 files changed, 337 insertions, 64 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index ab6907f828..802818541b 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -73,11 +73,10 @@ static ErlNifFunc nif_funcs[] = {
{"hash_init_nif", 1, hash_init_nif, 0},
{"hash_update_nif", 2, hash_update_nif, 0},
{"hash_final_nif", 1, hash_final_nif, 0},
- {"hmac_init_nif", 2, hmac_init_nif, 0},
- {"hmac_update_nif", 2, hmac_update_nif, 0},
- {"hmac_final_nif", 1, hmac_final_nif, 0},
- {"hmac_final_nif", 2, hmac_final_nif, 0},
{"mac_nif", 4, mac_nif, 0},
+ {"mac_init_nif", 3, mac_init_nif, 0},
+ {"mac_update_nif", 2, mac_update_nif, 0},
+ {"mac_final_nif", 1, mac_final_nif, 0},
{"cipher_info_nif", 1, cipher_info_nif, 0},
{"aes_ige_crypt_nif", 4, aes_ige_crypt_nif, 0},
{"ng_crypto_init_nif", 4, ng_crypto_init_nif, 0},
@@ -176,9 +175,15 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
if (!enif_inspect_binary(env, tpl_array[1], &lib_bin))
return __LINE__;
+#ifdef HAS_EVP_PKEY_CTX
+ if (!init_mac_ctx(env)) {
+ return __LINE__;
+ }
+#else
if (!init_hmac_ctx(env)) {
return __LINE__;
}
+#endif
if (!init_hash_ctx(env)) {
return __LINE__;
}
diff --git a/lib/crypto/c_src/hmac.c b/lib/crypto/c_src/hmac.c
index 060ad6230f..1a4f96e1d5 100644
--- a/lib/crypto/c_src/hmac.c
+++ b/lib/crypto/c_src/hmac.c
@@ -18,6 +18,8 @@
* %CopyrightEnd%
*/
+#ifndef HAS_EVP_PKEY_CTX
+
#include "hmac.h"
#include "digest.h"
@@ -63,17 +65,17 @@ static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context *obj)
}
ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type, Key) */
+{/* (hmac, Type, Key) */
struct digest_type_t *digp = NULL;
ErlNifBinary key;
ERL_NIF_TERM ret;
struct hmac_context *obj = NULL;
- ASSERT(argc == 2);
+ ASSERT(argc == 3);
- if ((digp = get_digest_type(argv[0])) == NULL)
+ if ((digp = get_digest_type(argv[1])) == NULL)
goto bad_arg;
- if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &key))
goto bad_arg;
if (key.size > INT_MAX)
goto bad_arg;
@@ -213,3 +215,4 @@ ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return ret;
}
+#endif
diff --git a/lib/crypto/c_src/hmac.h b/lib/crypto/c_src/hmac.h
index 01c6d3d226..5df837a874 100644
--- a/lib/crypto/c_src/hmac.h
+++ b/lib/crypto/c_src/hmac.h
@@ -21,6 +21,8 @@
#ifndef E_HMAC_H__
#define E_HMAC_H__ 1
+#ifndef HAS_EVP_PKEY_CTX
+
#include "common.h"
int init_hmac_ctx(ErlNifEnv *env);
@@ -28,5 +30,6 @@ int init_hmac_ctx(ErlNifEnv *env);
ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+#endif
#endif /* E_HMAC_H__ */
diff --git a/lib/crypto/c_src/mac.c b/lib/crypto/c_src/mac.c
index 0ee431f394..0482f97028 100644
--- a/lib/crypto/c_src/mac.c
+++ b/lib/crypto/c_src/mac.c
@@ -21,6 +21,7 @@
#include "common.h"
#include "cipher.h"
#include "digest.h"
+#include "hmac.h"
#include "mac.h"
/***************************
@@ -184,7 +185,6 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
size_t size;
EVP_PKEY *pkey = NULL;
EVP_MD_CTX *mctx = NULL;
- EVP_PKEY_CTX *pctx = NULL;
#endif
/*---------------------------------
@@ -341,7 +341,7 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
goto err;
}
- if (EVP_DigestSignInit(mctx, &pctx, md, /*engine*/ NULL, pkey) != 1)
+ if (EVP_DigestSignInit(mctx, /*&pctx*/ NULL, md, /*engine*/ NULL, pkey) != 1)
{
return_term = EXCP_ERROR(env, "EVP_DigestSign");
goto err;
@@ -399,7 +399,7 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return_term = enif_make_binary(env, &ret_bin);
ret_bin_alloc = 0;
- out: /* Common for success: and for err: */
+ err:
#ifdef HAS_EVP_PKEY_CTX
if (pkey)
@@ -408,17 +408,10 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
EVP_MD_CTX_free(mctx);
#endif
- return return_term;
-
-
- /*****************
- Error exit
- ******************/
- err:
if (ret_bin_alloc)
enif_release_binary(&ret_bin);
- goto out;
+ return return_term;
}
@@ -511,3 +504,282 @@ int hmac_low_level(ErlNifEnv* env, const EVP_MD *md,
return 1;
}
#endif
+
+
+/*******************************************************************
+ *
+ * Mac ctx
+ *
+ ******************************************************************/
+
+int init_mac_ctx(ErlNifEnv *env);
+
+struct mac_context
+{
+ EVP_MD_CTX *ctx;
+};
+
+static ErlNifResourceType* mac_context_rtype;
+
+static void mac_context_dtor(ErlNifEnv* env, struct mac_context*);
+
+int init_mac_ctx(ErlNifEnv *env) {
+ mac_context_rtype = enif_open_resource_type(env, NULL, "mac_context",
+ (ErlNifResourceDtor*) mac_context_dtor,
+ ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
+ NULL);
+ if (mac_context_rtype == NULL)
+ goto err;
+
+ return 1;
+
+ err:
+ PRINTF_ERR0("CRYPTO: Could not open resource type 'mac_context'");
+ return 0;
+}
+
+
+static void mac_context_dtor(ErlNifEnv* env, struct mac_context *obj)
+{
+ if (obj == NULL)
+ return;
+
+ if (obj->ctx)
+ EVP_MD_CTX_free(obj->ctx);
+}
+
+/*******************************************************************
+ *
+ * Mac nif
+ *
+ ******************************************************************/
+
+ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (MacType, SubType, Key) */
+#ifdef HAS_EVP_PKEY_CTX
+ struct mac_context *obj = NULL;
+ struct mac_type_t *macp;
+ ErlNifBinary key_bin;
+ ERL_NIF_TERM return_term;
+ const EVP_MD *md = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ /*---------------------------------
+ Get common indata and validate it
+ */
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &key_bin))
+ {
+ return_term = EXCP_BADARG(env, "Bad key");
+ goto err;
+ }
+
+ if (!(macp = get_mac_type(argv[0])))
+ {
+ return_term = EXCP_BADARG(env, "Unknown mac algorithm");
+ goto err;
+ }
+
+ /*--------------------------------------------------
+ Algorithm dependent indata checking and computation.
+ If EVP_PKEY is available, only set the pkey variable
+ and do the computation after the switch statement.
+ If not available, do the low-level calls in the
+ corresponding case part
+ */
+ switch (macp->type) {
+
+ /********
+ * HMAC *
+ ********/
+ case HMAC_mac:
+ {
+ struct digest_type_t *digp;
+
+ if ((digp = get_digest_type(argv[1])) == NULL)
+ {
+ return_term = EXCP_BADARG(env, "Bad digest algorithm for HMAC");
+ goto err;
+ }
+ if (digp->md.p == NULL)
+ {
+ return_term = EXCP_NOTSUP(env, "Unsupported digest algorithm");
+ goto err;
+ }
+
+ md = digp->md.p;
+
+# ifdef HAVE_PKEY_new_raw_private_key
+ /* Prefered for new applications according to EVP_PKEY_new_mac_key(3) */
+ pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, /*engine*/ NULL, key_bin.data, key_bin.size);
+# else
+ /* Available in older versions */
+ pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, /*engine*/ NULL, key_bin.data, key_bin.size);
+# endif
+ }
+ break;
+
+
+ /********
+ * CMAC *
+ ********/
+#if defined(HAVE_CMAC) && defined(HAVE_EVP_PKEY_new_CMAC_key)
+ case CMAC_mac:
+ {
+ const struct cipher_type_t *cipherp;
+ if (!(cipherp = get_cipher_type(argv[1], key_bin.size)))
+ { /* Something went wrong. Find out what by retrying in another way. */
+ if (!get_cipher_type_no_key(argv[1]))
+ return_term = EXCP_BADARG(env, "Unknown cipher");
+ else
+ /* Cipher exists, so it must be the key size that is wrong */
+ return_term = EXCP_BADARG(env, "Bad key size");
+ goto err;
+ }
+
+ if (FORBIDDEN_IN_FIPS(cipherp))
+ {
+ return_term = EXCP_NOTSUP(env, "Cipher algorithm not supported in FIPS");
+ goto err;
+ }
+
+ if (cipherp->cipher.p == NULL)
+ {
+ return_term = EXCP_NOTSUP(env, "Unsupported cipher algorithm");
+ goto err;
+ }
+
+ pkey = EVP_PKEY_new_CMAC_key(/*engine*/ NULL, key_bin.data, key_bin.size, cipherp->cipher.p);
+ }
+ break;
+#endif /* HAVE_CMAC && HAVE_EVP_PKEY_new_CMAC_key */
+
+
+ /************
+ * POLY1305 *
+ ************/
+#ifdef HAVE_POLY1305
+ case POLY1305_mac:
+ if (key_bin.size != 32)
+ {
+ return_term = EXCP_BADARG(env, "Bad key size, != 32 bytes");
+ goto err;
+ }
+ /* poly1305 implies that EVP_PKEY_new_raw_private_key exists */
+ pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305, /*engine*/ NULL, key_bin.data, key_bin.size);
+ break;
+#endif
+
+
+ /***************
+ * Unknown MAC *
+ ***************/
+ case NO_mac:
+ default:
+ /* We know that this mac is supported with some version(s) of cryptolib */
+ return_term = EXCP_NOTSUP(env, "Unsupported mac algorithm");
+ goto err;
+ }
+
+ /*-----------------------------------------
+ Common computations
+ */
+ if (!pkey)
+ {
+ return_term = EXCP_ERROR(env, "EVP_PKEY_key creation");
+ goto err;
+ }
+
+ if ((obj = enif_alloc_resource(mac_context_rtype, sizeof(struct mac_context))) == NULL)
+ {
+ return_term = EXCP_ERROR(env, "Can't allocate mac_context_rtype");
+ goto err;
+ }
+
+ if ((obj->ctx = EVP_MD_CTX_new()) == NULL)
+ {
+ return_term = EXCP_ERROR(env, "EVP_MD_CTX_new");
+ goto err;
+ }
+
+ if (EVP_DigestSignInit(obj->ctx, /*&pctx*/ NULL, md, /*engine*/ NULL, pkey) != 1)
+ {
+ return_term = EXCP_ERROR(env, "EVP_DigestSign");
+ goto err;
+ }
+
+ return_term = enif_make_resource(env, obj);
+
+ err:
+
+ if (obj)
+ enif_release_resource(obj);
+
+ if (pkey)
+ EVP_PKEY_free(pkey);
+
+ return return_term;
+
+#else
+ if (argv[0] != atom_hmac)
+ return EXCP_NOTSUP(env, "Unsupported mac algorithm");
+
+ return hmac_init_nif(env, argc, argv);
+#endif
+}
+
+
+
+ERL_NIF_TERM mac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Ref, Text) */
+#ifdef HAS_EVP_PKEY_CTX
+ struct mac_context *obj = NULL;
+ ErlNifBinary text;
+
+ if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)mac_context_rtype, (void**)&obj))
+ return EXCP_BADARG(env, "Bad ref");
+
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &text))
+ return EXCP_BADARG(env, "Bad text");
+
+ if (EVP_DigestSignUpdate(obj->ctx, text.data, text.size) != 1)
+ return EXCP_ERROR(env, "EVP_DigestSignUpdate");
+
+ CONSUME_REDS(env, text);
+ return argv[0];
+
+#else
+ return hmac_update_nif(env, argc, argv);
+#endif
+}
+
+
+
+ERL_NIF_TERM mac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Ref) */
+#ifdef HAS_EVP_PKEY_CTX
+ struct mac_context *obj;
+ size_t size;
+ ErlNifBinary ret_bin;
+
+ if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)mac_context_rtype, (void**)&obj))
+ return EXCP_BADARG(env, "Bad ref");
+
+ if (EVP_DigestSignFinal(obj->ctx, NULL, &size) != 1)
+ return EXCP_ERROR(env, "Can't get sign size");
+
+ if (!enif_alloc_binary(size, &ret_bin))
+ return EXCP_ERROR(env, "Alloc binary");
+
+ if (EVP_DigestSignFinal(obj->ctx, ret_bin.data, &size) != 1)
+ {
+ enif_release_binary(&ret_bin);
+ return EXCP_ERROR(env, "Signing");
+ }
+
+ return enif_make_binary(env, &ret_bin);
+
+#else
+ return hmac_final_nif(env, argc, argv);
+#endif
+}
+
diff --git a/lib/crypto/c_src/mac.h b/lib/crypto/c_src/mac.h
index 00b94a2232..053a331324 100644
--- a/lib/crypto/c_src/mac.h
+++ b/lib/crypto/c_src/mac.h
@@ -23,6 +23,7 @@
#include "common.h"
+int init_mac_ctx(ErlNifEnv *env);
void init_mac_types(ErlNifEnv* env);
@@ -30,4 +31,8 @@ ERL_NIF_TERM mac_types_as_list(ErlNifEnv* env);
ERL_NIF_TERM mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM mac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM mac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
#endif /* E_MAC_H__ */
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index d2a5786be8..371a2ee451 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -63,7 +63,8 @@
crypto_dyn_iv_init/3,
crypto_dyn_iv_update/3,
supports/1,
- mac/3, mac/4, mac/5
+ mac/3, mac/4, mac/5,
+ mac_init/3, mac_update/2, mac_final/1
]).
@@ -617,17 +618,33 @@ hash_final(Context) ->
%%%================================================================
mac(Type, SubType, Key, Data, MacLength) ->
- erlang:binary_part(mac(Type, SubType, Key, Data), 0, MacLength).
+ erlang:binary_part(mac(Type,SubType,Key,Data), 0, MacLength).
-mac(poly1305, _, Key, Data) -> mac_nif(poly1305, undefined, Key, Data);
+mac(poly1305, _, Key, Data) -> mac(poly1305, undefined, Key, Data);
mac(Type, SubType, Key, Data) -> mac_nif(Type, SubType, Key, Data).
mac(poly1305, Key, Data) -> mac(poly1305, undefined, Key, Data).
-
+
+mac_init(Type, SubType, Key) ->
+ mac_init_nif(Type, SubType, Key).
+
+mac_update(Ref, Data) ->
+ mac_update_nif(Ref, Data).
+
+mac_final(Ref) ->
+ mac_final_nif(Ref).
+
+mac_final(Ref, MacLength) ->
+ erlang:binary_part(mac_final(Ref), 0, MacLength).
+
mac_nif(_Type, _SubType, _Key, _Data) -> ?nif_stub.
+mac_init_nif(_Type, _SubType, _Key) -> ?nif_stub.
+mac_update_nif(_Ref, _Data) -> ?nif_stub.
+mac_final_nif(_Ref) -> ?nif_stub.
+
%%%---- HMAC
@@ -641,8 +658,7 @@ mac_nif(_Type, _SubType, _Key, _Data) -> ?nif_stub.
Data :: iodata(),
Mac :: binary() .
hmac(Type, Key, Data) ->
- Data1 = iolist_to_binary(Data),
- hmac(Type, Key, Data1, undefined, erlang:byte_size(Data1), max_bytes()).
+ ?COMPAT(mac(hmac, Type, Key, Data)).
-spec hmac(Type, Key, Data, MacLength) ->
Mac when Type :: hmac_hash_algorithm(),
@@ -652,8 +668,7 @@ hmac(Type, Key, Data) ->
Mac :: binary() .
hmac(Type, Key, Data, MacLength) ->
- Data1 = iolist_to_binary(Data),
- hmac(Type, Key, Data1, MacLength, erlang:byte_size(Data1), max_bytes()).
+ ?COMPAT(mac(hmac, Type, Key, Data, MacLength)).
%%%---- hmac_init, hamc_update, hmac_final
@@ -664,29 +679,28 @@ hmac(Type, Key, Data, MacLength) ->
Key :: iodata(),
State :: hmac_state() .
hmac_init(Type, Key) ->
- notsup_to_error(hmac_init_nif(Type, Key)).
+ ?COMPAT(mac_init(hmac, Type, Key)).
%%%---- hmac_update
-spec hmac_update(State, Data) -> NewState when Data :: iodata(),
State :: hmac_state(),
NewState :: hmac_state().
-hmac_update(State, Data0) ->
- Data = iolist_to_binary(Data0),
- hmac_update(State, Data, erlang:byte_size(Data), max_bytes()).
+hmac_update(State, Data) ->
+ ?COMPAT(mac_update(State, Data)).
%%%---- hmac_final
-spec hmac_final(State) -> Mac when State :: hmac_state(),
Mac :: binary().
hmac_final(Context) ->
- notsup_to_error(hmac_final_nif(Context)).
+ ?COMPAT(mac_final(Context)).
-spec hmac_final_n(State, HashLen) -> Mac when State :: hmac_state(),
HashLen :: integer(),
Mac :: binary().
hmac_final_n(Context, HashLen) ->
- notsup_to_error(hmac_final_nif(Context, HashLen)).
+ ?COMPAT(mac_final(Context, HashLen)).
%%%---- CMAC
@@ -708,14 +722,14 @@ cmac(Type, Key, Data) ->
Mac :: binary().
cmac(Type, Key, Data, MacLength) ->
- erlang:binary_part(cmac(alias(Type), Key, Data), 0, MacLength).
+ ?COMPAT(mac(cmac, alias(Type), Key, Data, MacLength)).
%%%---- POLY1305
-spec poly1305(iodata(), iodata()) -> Mac when Mac :: binary().
poly1305(Key, Data) ->
- ?COMPAT( mac(poly1305, Key, Data) ).
+ ?COMPAT(mac(poly1305, Key, Data)).
%%%================================================================
%%%
@@ -2260,35 +2274,6 @@ hash_init_nif(_Hash) -> ?nif_stub.
hash_update_nif(_State, _Data) -> ?nif_stub.
hash_final_nif(_State) -> ?nif_stub.
-%% HMAC --------------------------------------------------------------------
-
-hmac(Type, Key, Data, MacSize, Size, MaxBytes) when Size =< MaxBytes ->
- ?COMPAT(
- case MacSize of
- undefined -> mac(hmac, Type, Key, Data);
- _ -> mac(hmac, Type, Key, Data, MacSize)
- end
- );
-hmac(Type, Key, Data, MacSize, Size, MaxBytes) ->
- State0 = hmac_init(Type, Key),
- State1 = hmac_update(State0, Data, Size, MaxBytes),
- case MacSize of
- undefined -> hmac_final(State1);
- _ -> hmac_final_n(State1, MacSize)
- end.
-
-hmac_update(State, Data, Size, MaxBytes) when Size =< MaxBytes ->
- notsup_to_error(hmac_update_nif(State, Data));
-hmac_update(State0, Data, _, MaxBytes) ->
- <<Increment:MaxBytes/binary, Rest/binary>> = Data,
- State = notsup_to_error(hmac_update_nif(State0, Increment)),
- hmac_update(State, Rest, erlang:byte_size(Rest), MaxBytes).
-
-hmac_init_nif(_Type, _Key) -> ?nif_stub.
-hmac_update_nif(_Context, _Data) -> ?nif_stub.
-hmac_final_nif(_Context) -> ?nif_stub.
-hmac_final_nif(_Context, _MacSize) -> ?nif_stub.
-
%% CIPHERS --------------------------------------------------------------------
cipher_info_nif(_Type) -> ?nif_stub.