diff mbox series

[API-NEXT,v4,13/15] linux-gen: crypto: implement AES-CMAC

Message ID 1517331619-18755-14-git-send-email-odpbot@yandex.ru
State New
Headers show
Series [API-NEXT,v4,1/15] api: crypto: add enumeration for AES-CMAC | expand

Commit Message

Github ODP bot Jan. 30, 2018, 5 p.m. UTC
From: Dmitry Eremin-Solenikov <dmitry.ereminsolenikov@linaro.org>


Signed-off-by: Dmitry Eremin-Solenikov <dmitry.ereminsolenikov@linaro.org>

---
/** Email created from pull request 434 (lumag:crypto-upd)
 ** https://github.com/Linaro/odp/pull/434
 ** Patch: https://github.com/Linaro/odp/pull/434.patch
 ** Base sha: 5718327018debbb02aacb464493504c95fbe57a3
 ** Merge commit sha: c5d9389a8d3b1a532e290aff4508756a920173ee
 **/
 platform/linux-generic/odp_crypto.c | 147 ++++++++++++++++++++++++++++++++++++
 1 file changed, 147 insertions(+)
diff mbox series

Patch

diff --git a/platform/linux-generic/odp_crypto.c b/platform/linux-generic/odp_crypto.c
index faa415cd0..5579ade5b 100644
--- a/platform/linux-generic/odp_crypto.c
+++ b/platform/linux-generic/odp_crypto.c
@@ -25,6 +25,7 @@ 
 
 #include <openssl/rand.h>
 #include <openssl/hmac.h>
+#include <openssl/cmac.h>
 #include <openssl/evp.h>
 
 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(OPENSSL_NO_POLY1305)
@@ -108,6 +109,14 @@  static const odp_crypto_auth_capability_t auth_capa_aes_gmac[] = {
 {.digest_len = 16, .key_len = 16, .aad_len = {.min = 0, .max = 0, .inc = 0},
 	.iv_len = 12 } };
 
+static const odp_crypto_auth_capability_t auth_capa_aes_cmac[] = {
+{.digest_len = 12, .key_len = 16, .aad_len = {.min = 0, .max = 0, .inc = 0} },
+{.digest_len = 16, .key_len = 16, .aad_len = {.min = 0, .max = 0, .inc = 0} },
+{.digest_len = 12, .key_len = 24, .aad_len = {.min = 0, .max = 0, .inc = 0} },
+{.digest_len = 16, .key_len = 24, .aad_len = {.min = 0, .max = 0, .inc = 0} },
+{.digest_len = 12, .key_len = 32, .aad_len = {.min = 0, .max = 0, .inc = 0} },
+{.digest_len = 16, .key_len = 32, .aad_len = {.min = 0, .max = 0, .inc = 0} } };
+
 #if _ODP_HAVE_CHACHA20_POLY1305
 static const odp_crypto_auth_capability_t auth_capa_chacha20_poly1305[] = {
 {.digest_len = 16, .key_len = 0, .aad_len = {.min = 8, .max = 12, .inc = 4} } };
@@ -177,6 +186,7 @@  static odp_crypto_global_t *global;
 
 typedef struct crypto_local_t {
 	HMAC_CTX *hmac_ctx[MAX_SESSIONS];
+	CMAC_CTX *cmac_ctx[MAX_SESSIONS];
 	EVP_CIPHER_CTX *cipher_ctx[MAX_SESSIONS];
 	EVP_CIPHER_CTX *mac_cipher_ctx[MAX_SESSIONS];
 	uint8_t *ctx_valid;
@@ -344,6 +354,93 @@  odp_crypto_alg_err_t auth_hmac_check(odp_packet_t pkt,
 	return ODP_CRYPTO_ALG_ERR_NONE;
 }
 
+static void
+auth_cmac_init(odp_crypto_generic_session_t *session)
+{
+	CMAC_CTX *ctx = local.cmac_ctx[session->idx];
+
+	CMAC_Init(ctx,
+		  session->auth.key,
+		  session->p.auth_key.length,
+		  session->auth.evp_cipher,
+		  NULL);
+}
+
+static
+void packet_cmac(odp_packet_t pkt,
+		 const odp_crypto_packet_op_param_t *param,
+		 odp_crypto_generic_session_t *session,
+		 uint8_t *hash)
+{
+	CMAC_CTX *ctx = local.cmac_ctx[session->idx];
+	uint32_t offset = param->auth_range.offset;
+	uint32_t len   = param->auth_range.length;
+	size_t outlen;
+
+	ODP_ASSERT(offset + len <= odp_packet_len(pkt));
+
+	/* Reinitialize CMAC calculation without resetting the key */
+	CMAC_Init(ctx, NULL, 0, NULL, NULL);
+
+	while (len > 0) {
+		uint32_t seglen = 0; /* GCC */
+		void *mapaddr = odp_packet_offset(pkt, offset, &seglen, NULL);
+		uint32_t maclen = len > seglen ? seglen : len;
+
+		CMAC_Update(ctx, mapaddr, maclen);
+		offset  += maclen;
+		len     -= maclen;
+	}
+
+	CMAC_Final(ctx, hash, &outlen);
+}
+
+static
+odp_crypto_alg_err_t auth_cmac_gen(odp_packet_t pkt,
+				   const odp_crypto_packet_op_param_t *param,
+				   odp_crypto_generic_session_t *session)
+{
+	uint8_t  hash[EVP_MAX_MD_SIZE];
+
+	/* Hash it */
+	packet_cmac(pkt, param, session, hash);
+
+	/* Copy to the output location */
+	odp_packet_copy_from_mem(pkt,
+				 param->hash_result_offset,
+				 session->p.auth_digest_len,
+				 hash);
+
+	return ODP_CRYPTO_ALG_ERR_NONE;
+}
+
+static
+odp_crypto_alg_err_t auth_cmac_check(odp_packet_t pkt,
+				     const odp_crypto_packet_op_param_t *param,
+				     odp_crypto_generic_session_t *session)
+{
+	uint32_t bytes = session->p.auth_digest_len;
+	uint8_t  hash_in[EVP_MAX_MD_SIZE];
+	uint8_t  hash_out[EVP_MAX_MD_SIZE];
+
+	/* Copy current value out and clear it before authentication */
+	odp_packet_copy_to_mem(pkt, param->hash_result_offset,
+			       bytes, hash_in);
+
+	_odp_packet_set_data(pkt, param->hash_result_offset,
+			     0, bytes);
+
+	/* Hash it */
+	packet_cmac(pkt, param, session, hash_out);
+
+	/* Verify match */
+	if (0 != memcmp(hash_in, hash_out, bytes))
+		return ODP_CRYPTO_ALG_ERR_ICV_CHECK;
+
+	/* Matched */
+	return ODP_CRYPTO_ALG_ERR_NONE;
+}
+
 static
 int internal_aad(EVP_CIPHER_CTX *ctx,
 		 odp_packet_t pkt,
@@ -1001,6 +1098,35 @@  static int process_auth_hmac_param(odp_crypto_generic_session_t *session,
 	return 0;
 }
 
+static int process_auth_cmac_param(odp_crypto_generic_session_t *session,
+				   const EVP_CIPHER *cipher)
+{
+	/* Verify Key len is valid */
+	if ((uint32_t)EVP_CIPHER_key_length(cipher) !=
+	    session->p.auth_key.length)
+		return -1;
+
+	/* Set function */
+	if (ODP_CRYPTO_OP_ENCODE == session->p.op)
+		session->auth.func = auth_cmac_gen;
+	else
+		session->auth.func = auth_cmac_check;
+	session->auth.init = auth_cmac_init;
+
+	session->auth.evp_cipher = cipher;
+
+	/* Number of valid bytes */
+	if (session->p.auth_digest_len <
+	    (unsigned)EVP_CIPHER_block_size(cipher) / 2)
+		return -1;
+
+	/* Convert keys */
+	memcpy(session->auth.key, session->p.auth_key.data,
+	       session->p.auth_key.length);
+
+	return 0;
+}
+
 int odp_crypto_capability(odp_crypto_capability_t *capa)
 {
 	if (NULL == capa)
@@ -1030,6 +1156,7 @@  int odp_crypto_capability(odp_crypto_capability_t *capa)
 	capa->auths.bit.aes_gcm      = 1;
 	capa->auths.bit.aes_ccm      = 1;
 	capa->auths.bit.aes_gmac     = 1;
+	capa->auths.bit.aes_cmac     = 1;
 #if _ODP_HAVE_CHACHA20_POLY1305
 	capa->auths.bit.chacha20_poly1305 = 1;
 #endif
@@ -1138,6 +1265,10 @@  int odp_crypto_auth_capability(odp_auth_alg_t auth,
 		src = auth_capa_aes_ccm;
 		num = sizeof(auth_capa_aes_ccm) / size;
 		break;
+	case ODP_AUTH_ALG_AES_CMAC:
+		src = auth_capa_aes_cmac;
+		num = sizeof(auth_capa_aes_cmac) / size;
+		break;
 #if _ODP_HAVE_CHACHA20_POLY1305
 	case ODP_AUTH_ALG_CHACHA20_POLY1305:
 		src = auth_capa_chacha20_poly1305;
@@ -1374,6 +1505,19 @@  odp_crypto_session_create(odp_crypto_session_param_t *param,
 			rc = -1;
 		}
 		break;
+	case ODP_AUTH_ALG_AES_CMAC:
+		if (param->auth_key.length == 16)
+			rc = process_auth_cmac_param(session,
+						     EVP_aes_128_cbc());
+		else if (param->auth_key.length == 24)
+			rc = process_auth_cmac_param(session,
+						     EVP_aes_192_cbc());
+		else if (param->auth_key.length == 32)
+			rc = process_auth_cmac_param(session,
+						     EVP_aes_256_cbc());
+		else
+			rc = -1;
+		break;
 #if _ODP_HAVE_CHACHA20_POLY1305
 	case ODP_AUTH_ALG_CHACHA20_POLY1305:
 		/* ChaCha20_Poly1305 requires to do both auth and
@@ -1561,6 +1705,7 @@  int _odp_crypto_init_local(void)
 
 	for (i = 0; i < MAX_SESSIONS; i++) {
 		local.hmac_ctx[i] = HMAC_CTX_new();
+		local.cmac_ctx[i] = CMAC_CTX_new();
 		local.cipher_ctx[i] = EVP_CIPHER_CTX_new();
 		local.mac_cipher_ctx[i] = EVP_CIPHER_CTX_new();
 
@@ -1584,6 +1729,8 @@  int _odp_crypto_term_local(void)
 	unsigned i;
 
 	for (i = 0; i < MAX_SESSIONS; i++) {
+		if (local.cmac_ctx[i] != NULL)
+			CMAC_CTX_free(local.cmac_ctx[i]);
 		if (local.hmac_ctx[i] != NULL)
 			HMAC_CTX_free(local.hmac_ctx[i]);
 		if (local.cipher_ctx[i] != NULL)