aboutsummaryrefslogtreecommitdiffstats
path: root/lib/crypto
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2019-05-14 17:01:17 +0200
committerHans Nilsson <[email protected]>2019-06-14 13:33:07 +0200
commit160cea3f655913b370650f93b0c8f6c1bd163e32 (patch)
treee03013d6f39625ac2bac84ddc2cd7b9757328fbb /lib/crypto
parentae4c8e6ee26e3c606054e4a845ac06f95ade1e57 (diff)
downloadotp-160cea3f655913b370650f93b0c8f6c1bd163e32.tar.gz
otp-160cea3f655913b370650f93b0c8f6c1bd163e32.tar.bz2
otp-160cea3f655913b370650f93b0c8f6c1bd163e32.zip
crypto: MAC nif unifying HMAC, CMAC and POLY1305
into one nif using the EVP_DigestSign interface. This enables acceleration if available in lower layers, that is, in cryptolib and lower. However, for older cryptolibs the old HMAC and CMAC low-level interfaces are used, but moved from hmac.c and cmac.c into mac.c.
Diffstat (limited to 'lib/crypto')
-rw-r--r--lib/crypto/c_src/Makefile.in1
-rw-r--r--lib/crypto/c_src/algorithms.c27
-rw-r--r--lib/crypto/c_src/atoms.c9
-rw-r--r--lib/crypto/c_src/atoms.h4
-rw-r--r--lib/crypto/c_src/crypto.c3
-rw-r--r--lib/crypto/c_src/mac.c389
-rw-r--r--lib/crypto/c_src/mac.h33
-rw-r--r--lib/crypto/c_src/openssl_config.h7
-rw-r--r--lib/crypto/src/crypto.erl16
9 files changed, 464 insertions, 25 deletions
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index b6a65d7488..35ded001d6 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -92,6 +92,7 @@ CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o \
$(OBJDIR)/hash$(TYPEMARKER).o \
$(OBJDIR)/hmac$(TYPEMARKER).o \
$(OBJDIR)/info$(TYPEMARKER).o \
+ $(OBJDIR)/mac$(TYPEMARKER).o \
$(OBJDIR)/math$(TYPEMARKER).o \
$(OBJDIR)/pkey$(TYPEMARKER).o \
$(OBJDIR)/poly1305$(TYPEMARKER).o \
diff --git a/lib/crypto/c_src/algorithms.c b/lib/crypto/c_src/algorithms.c
index 75cddeb1e9..53b8b7eaa9 100644
--- a/lib/crypto/c_src/algorithms.c
+++ b/lib/crypto/c_src/algorithms.c
@@ -20,13 +20,12 @@
#include "algorithms.h"
#include "cipher.h"
+#include "mac.h"
static unsigned int algo_hash_cnt, algo_hash_fips_cnt;
static ERL_NIF_TERM algo_hash[14]; /* increase when extending the list */
static unsigned int algo_pubkey_cnt, algo_pubkey_fips_cnt;
static ERL_NIF_TERM algo_pubkey[12]; /* increase when extending the list */
-static unsigned int algo_mac_cnt, algo_mac_fips_cnt;
-static ERL_NIF_TERM algo_mac[3]; /* increase when extending the list */
static unsigned int algo_curve_cnt, algo_curve_fips_cnt;
static ERL_NIF_TERM algo_curve[89]; /* increase when extending the list */
static unsigned int algo_rsa_opts_cnt, algo_rsa_opts_fips_cnt;
@@ -101,19 +100,6 @@ void init_algorithms_types(ErlNifEnv* env)
#endif
algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "srp");
-
- // Validated algorithms first
- algo_mac_cnt = 0;
- algo_mac[algo_mac_cnt++] = enif_make_atom(env,"hmac");
-#ifdef HAVE_CMAC
- algo_mac[algo_mac_cnt++] = enif_make_atom(env,"cmac");
-#endif
-#ifdef HAVE_POLY1305
- algo_mac[algo_mac_cnt++] = enif_make_atom(env,"poly1305");
-#endif
- // Non-validated algorithms follow
- algo_mac_fips_cnt = algo_mac_cnt;
-
// Validated algorithms first
algo_curve_cnt = 0;
#if defined(HAVE_EC)
@@ -250,7 +236,6 @@ void init_algorithms_types(ErlNifEnv* env)
// Check that the max number of algos is updated
ASSERT(algo_hash_cnt <= sizeof(algo_hash)/sizeof(ERL_NIF_TERM));
ASSERT(algo_pubkey_cnt <= sizeof(algo_pubkey)/sizeof(ERL_NIF_TERM));
- ASSERT(algo_mac_cnt <= sizeof(algo_mac)/sizeof(ERL_NIF_TERM));
ASSERT(algo_curve_cnt <= sizeof(algo_curve)/sizeof(ERL_NIF_TERM));
ASSERT(algo_rsa_opts_cnt <= sizeof(algo_rsa_opts)/sizeof(ERL_NIF_TERM));
}
@@ -284,18 +269,12 @@ ERL_NIF_TERM cipher_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
return cipher_types_as_list(env); /* Exclude old api ciphers */
}
+
ERL_NIF_TERM mac_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- unsigned int cnt =
-#ifdef FIPS_SUPPORT
- FIPS_mode() ? algo_mac_fips_cnt :
-#endif
- algo_mac_cnt;
-
- return enif_make_list_from_array(env, algo_mac, cnt);
+ return mac_types_as_list(env);
}
-
ERL_NIF_TERM curve_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
unsigned int cnt =
diff --git a/lib/crypto/c_src/atoms.c b/lib/crypto/c_src/atoms.c
index 059c14690f..bbeb329fa2 100644
--- a/lib/crypto/c_src/atoms.c
+++ b/lib/crypto/c_src/atoms.c
@@ -30,6 +30,10 @@ ERL_NIF_TERM atom_rsa_no_padding;
ERL_NIF_TERM atom_signature_md;
ERL_NIF_TERM atom_undefined;
+ERL_NIF_TERM atom_hmac;
+ERL_NIF_TERM atom_cmac;
+ERL_NIF_TERM atom_poly1305;
+
ERL_NIF_TERM atom_ok;
ERL_NIF_TERM atom_none;
ERL_NIF_TERM atom_notsup;
@@ -155,6 +159,11 @@ int init_atoms(ErlNifEnv *env, const ERL_NIF_TERM fips_mode, const ERL_NIF_TERM
atom_rsa_no_padding = enif_make_atom(env,"rsa_no_padding");
atom_signature_md = enif_make_atom(env,"signature_md");
atom_undefined = enif_make_atom(env,"undefined");
+
+ atom_hmac = enif_make_atom(env,"hmac");
+ atom_cmac = enif_make_atom(env,"cmac");
+ atom_poly1305 = enif_make_atom(env,"poly1305");
+
atom_ok = enif_make_atom(env,"ok");
atom_none = enif_make_atom(env,"none");
atom_notsup = enif_make_atom(env,"notsup");
diff --git a/lib/crypto/c_src/atoms.h b/lib/crypto/c_src/atoms.h
index f5913de96f..0e2f1a0022 100644
--- a/lib/crypto/c_src/atoms.h
+++ b/lib/crypto/c_src/atoms.h
@@ -34,6 +34,10 @@ extern ERL_NIF_TERM atom_rsa_no_padding;
extern ERL_NIF_TERM atom_signature_md;
extern ERL_NIF_TERM atom_undefined;
+extern ERL_NIF_TERM atom_hmac;
+extern ERL_NIF_TERM atom_cmac;
+extern ERL_NIF_TERM atom_poly1305;
+
extern ERL_NIF_TERM atom_ok;
extern ERL_NIF_TERM atom_none;
extern ERL_NIF_TERM atom_notsup;
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index d533cba140..7cdc95a841 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -32,6 +32,7 @@
#include "bn.h"
#include "cipher.h"
#include "cmac.h"
+#include "mac.h"
#include "dh.h"
#include "digest.h"
#include "dss.h"
@@ -81,6 +82,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},
+ {"mac_nif", 4, mac_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},
@@ -248,6 +250,7 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
#endif /* OPENSSL_THREADS */
init_digest_types(env);
+ init_mac_types(env);
init_cipher_types(env);
init_algorithms_types(env);
diff --git a/lib/crypto/c_src/mac.c b/lib/crypto/c_src/mac.c
new file mode 100644
index 0000000000..91dd42314e
--- /dev/null
+++ b/lib/crypto/c_src/mac.c
@@ -0,0 +1,389 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2019. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "common.h"
+#include "cipher.h"
+#include "digest.h"
+#include "mac.h"
+
+#ifdef HAS_EVP_PKEY_CTX
+struct mac_type_t {
+ union {
+ const char* str; /* before init, NULL for end-of-table */
+ ERL_NIF_TERM atom; /* after init, 'false' for end-of-table */
+ }type;
+ union {
+ const int type;
+ }alg;
+};
+
+
+static struct mac_type_t mac_types[] =
+{
+ {{"poly1305"},
+#ifdef HAVE_POLY1305
+ {EVP_PKEY_POLY1305}
+#else
+ {EVP_PKEY_NONE}
+#endif
+ },
+
+ {{"hmac"},
+#ifdef HAVE_PKEY_HMAC
+ {EVP_PKEY_HMAC}
+#else
+ {EVP_PKEY_NONE}
+#endif
+ },
+
+ {{"cmac"},
+#ifdef HAVE_CMAC
+ {EVP_PKEY_CMAC}
+#else
+ {EVP_PKEY_NONE}
+#endif
+ },
+ /*==== End of list ==== */
+ {{NULL},{0}}
+};
+
+#endif /* HAS_EVP_PKEY_CTX */
+
+
+void init_mac_types(ErlNifEnv* env)
+{
+#ifdef HAS_EVP_PKEY_CTX
+ struct mac_type_t* p = mac_types;
+
+ for (p = mac_types; p->type.str; p++) {
+ p->type.atom = enif_make_atom(env, p->type.str);
+ }
+ p->type.atom = atom_false; /* end marker */
+#endif
+}
+
+
+ERL_NIF_TERM mac_types_as_list(ErlNifEnv* env)
+{
+#ifdef HAS_EVP_PKEY_CTX
+ struct mac_type_t* p;
+ ERL_NIF_TERM prev, hd;
+
+ hd = enif_make_list(env, 0);
+ prev = atom_undefined;
+
+ for (p = mac_types; (p->type.atom & (p->type.atom != atom_false)); p++) {
+ if (prev == p->type.atom)
+ continue;
+
+ if (p->alg.type != EVP_PKEY_NONE)
+ {
+ hd = enif_make_list_cell(env, p->type.atom, hd);
+ }
+ }
+
+ return hd;
+#else
+ return enif_make_list1(env, atom_hmac);
+#endif
+}
+
+
+#ifdef HAS_EVP_PKEY_CTX
+struct mac_type_t* get_mac_type(ERL_NIF_TERM type);
+
+struct mac_type_t* get_mac_type(ERL_NIF_TERM type)
+{
+ struct mac_type_t* p = NULL;
+ for (p = mac_types; p->type.atom != atom_false; p++) {
+ if (type == p->type.atom) {
+ return p;
+ }
+ }
+ return NULL;
+}
+#endif
+
+
+
+
+ERL_NIF_TERM mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (MacType, SubType, Key, Text) */
+
+ ErlNifBinary key_bin, text;
+ int ret_bin_alloc = 0;
+ size_t size;
+ ERL_NIF_TERM return_term;
+ const EVP_MD *md = NULL;
+ ErlNifBinary ret_bin;
+#ifdef HAS_EVP_PKEY_CTX
+ EVP_PKEY *pkey = NULL;
+ EVP_MD_CTX *mctx = NULL;
+ EVP_PKEY_CTX *pctx = NULL;
+#endif
+
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &key_bin))
+ {
+ return_term = EXCP_BADARG(env, "Bad key");
+ goto err;
+ }
+
+ if (!enif_inspect_iolist_as_binary(env, argv[3], &text))
+ {
+ return_term = EXCP_BADARG(env, "Bad text");
+ goto err;
+ }
+
+ if (argv[0] == atom_hmac)
+ {
+ 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;
+
+#ifndef HAS_EVP_PKEY_CTX
+ /* Old cryptolib: use low level functions */
+ {
+ unsigned int size_int;
+
+ /* Find the needed space */
+ if (HMAC(md,
+ key_bin.data, (int)key_bin.size,
+ text.data, text.size,
+ NULL, &size_int) == NULL)
+ {
+ return_term = EXCP_ERROR(env, "Get HMAC size failed");
+ goto err;
+ }
+
+ size = (size_t)size_int; /* Otherwise "size" is unused in 0.9.8.... */
+ if (!enif_alloc_binary(size, &ret_bin))
+ {
+ return_term = EXCP_ERROR(env, "Alloc binary");
+ goto err;
+ }
+ ret_bin_alloc = 1;
+
+ /* And do the real HMAC calc */
+ if (HMAC(md,
+ key_bin.data, (int)key_bin.size,
+ text.data, text.size,
+ ret_bin.data, &size_int) == NULL)
+ {
+ return_term = EXCP_ERROR(env, "HMAC sign failed");
+ goto err;
+ }
+ }
+#else
+/* HAS_EVP_PKEY_CTX and HMAC is the type. Produce a PKEY for later use */
+
+# 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
+ }
+
+ else if (argv[0] == atom_cmac)
+ {
+#ifdef HAVE_CMAC
+ 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;
+ }
+
+# ifdef HAVE_EVP_PKEY_new_CMAC_key
+ pkey = EVP_PKEY_new_CMAC_key(/*engine*/ NULL, key_bin.data, key_bin.size, cipherp->cipher.p);
+# else
+ /* Compatibility with < 1.1.1 that doesn't have EVP_PKEY_new_CMAC_key
+ It is a complicated flow so just do some goto to get out of it.
+ */
+ {
+ CMAC_CTX *ctx = NULL;
+
+ if ((ctx = CMAC_CTX_new()) == NULL)
+ goto local_err;
+
+ if (!CMAC_Init(ctx, key_bin.data, key_bin.size, cipherp->cipher.p, NULL))
+ goto local_err;
+
+ if (!CMAC_Update(ctx, text.data, text.size))
+ goto local_err;
+
+ if ((size = (size_t)EVP_CIPHER_block_size(cipherp->cipher.p)) < 0)
+ goto local_err;
+
+ if (!enif_alloc_binary(size, &ret_bin))
+ goto local_err;
+ ret_bin_alloc = 1;
+
+ if (!CMAC_Final(ctx, ret_bin.data, &ret_bin.size))
+ goto local_err;
+
+ CONSUME_REDS(env, text);
+
+ return_term = enif_make_binary(env, &ret_bin);
+ ret_bin_alloc = 0;
+ goto done;
+
+ local_err:
+ if (ctx)
+ CMAC_CTX_free(ctx);
+
+ return_term=EXCP_ERROR(env,"Compat cmac");
+ goto err;
+ }
+# endif
+#else
+ return_term = EXCP_NOTSUP(env, "Unsupported mac type");
+ goto err;
+#endif /* HAVE_CMAC */
+ }
+
+ else if (argv[0] == atom_poly1305)
+ {
+#ifdef HAVE_POLY1305
+ 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);
+#else
+ return_term = EXCP_NOTSUP(env, "Unsupported mac type");
+ goto err;
+#endif /* HAVE_POLY1305 */
+#endif /* HAS_EVP_PKEY_CTX */
+
+ }
+ else
+ {
+ return_term = EXCP_BADARG(env, "Bad mac type");
+ goto err;
+ }
+
+#ifdef HAS_EVP_PKEY_CTX
+ if (!pkey)
+ {
+ return_term = EXCP_ERROR(env, "EVP_PKEY_key creation");
+ goto err;
+ }
+
+
+ if ((mctx = EVP_MD_CTX_new()) == NULL)
+ {
+ return_term = EXCP_ERROR(env, "EVP_MD_CTX_new");
+ goto err;
+ }
+
+ if (EVP_DigestSignInit(mctx, &pctx, md, /*engine*/ NULL, pkey) != 1)
+ {
+ return_term = EXCP_ERROR(env, "EVP_DigestSign");
+ goto err;
+ }
+
+# ifdef HAVE_DigestSign_as_single_op
+ if (EVP_DigestSign(mctx, NULL, &size, text.data, text.size) != 1)
+# else
+ if (EVP_DigestSignUpdate(mctx, text.data, text.size) != 1)
+ {
+ return_term = EXCP_ERROR(env, "EVP_DigestSignUpdate");
+ goto err;
+ }
+
+ if (EVP_DigestSignFinal(mctx, NULL, &size) != 1)
+# endif
+ {
+ return_term = EXCP_ERROR(env, "Can't get sign size");
+ goto err;
+ }
+
+ if (!enif_alloc_binary(size, &ret_bin))
+ {
+ return_term = EXCP_ERROR(env, "Alloc binary");
+ goto err;
+ }
+ ret_bin_alloc = 1;
+
+# ifdef HAVE_DigestSign_as_single_op
+ if (EVP_DigestSign(mctx, ret_bin.data, &size, text.data, text.size) != 1)
+# else
+ if (EVP_DigestSignFinal(mctx, ret_bin.data, &size) != 1)
+# endif
+ {
+ return_term = EXCP_ERROR(env, "Signing");
+ goto err;
+ }
+
+#endif /* ifdef HAS_EVP_PKEY_CTX */
+
+ CONSUME_REDS(env, text);
+
+ return_term = enif_make_binary(env, &ret_bin);
+ ret_bin_alloc = 0;
+ goto done;
+
+err:
+ if (ret_bin_alloc)
+ enif_release_binary(&ret_bin);
+
+done:
+#ifdef HAS_EVP_PKEY_CTX
+ if (pkey)
+ EVP_PKEY_free(pkey);
+#endif
+ return return_term;
+}
+
+
+
+
+
diff --git a/lib/crypto/c_src/mac.h b/lib/crypto/c_src/mac.h
new file mode 100644
index 0000000000..00b94a2232
--- /dev/null
+++ b/lib/crypto/c_src/mac.h
@@ -0,0 +1,33 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_MAC_H__
+#define E_MAC_H__ 1
+
+#include "common.h"
+
+
+void init_mac_types(ErlNifEnv* env);
+
+ERL_NIF_TERM mac_types_as_list(ErlNifEnv* env);
+
+ERL_NIF_TERM mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_MAC_H__ */
diff --git a/lib/crypto/c_src/openssl_config.h b/lib/crypto/c_src/openssl_config.h
index 339eb5b8f4..aee08ea65f 100644
--- a/lib/crypto/c_src/openssl_config.h
+++ b/lib/crypto/c_src/openssl_config.h
@@ -110,6 +110,12 @@
# define HAS_EVP_PKEY_CTX
# define HAVE_EVP_CIPHER_CTX_COPY
# endif
+
+# if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,1)
+# define HAVE_PKEY_new_raw_private_key
+# define HAVE_EVP_PKEY_new_CMAC_key
+# define HAVE_DigestSign_as_single_op
+# endif
#endif
@@ -278,6 +284,7 @@
#endif
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
+# define HAVE_PKEY_HMAC
# ifdef RSA_PKCS1_PSS_PADDING
# define HAVE_RSA_PKCS1_PSS_PADDING
# endif
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 169c0f2e91..fd4b9df5e0 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -62,7 +62,8 @@
crypto_one_time_aead/6, crypto_one_time_aead/7,
crypto_dyn_iv_init/3,
crypto_dyn_iv_update/3,
- supports/1
+ supports/1,
+ mac/3, mac/4, mac/5
]).
@@ -602,6 +603,19 @@ hash_final(Context) ->
%%%
%%%================================================================
+mac(Type, SubType, Key, Data, MacLength) ->
+ erlang:binary_part(mac(Type, SubType, Key, Data), 0, MacLength).
+
+mac(poly1305, _, Key, Data) -> mac_nif(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_nif(_Type, _SubType, _Key, _Data) -> ?nif_stub.
+
+
%%%---- HMAC
-type hmac_hash_algorithm() :: sha1() | sha2() | sha3() | compatibility_only_hash().