diff mbox series

[API-NEXT,v6,5/12] linux-gen: crypto: add AES-GMAC implementation

Message ID 1510581611-13870-6-git-send-email-odpbot@yandex.ru
State Superseded
Headers show
Series [API-NEXT,v6,1/12] linux-gen: ipsec: use counter instead of random IV for GCM | expand

Commit Message

Github ODP bot Nov. 13, 2017, 2 p.m. UTC
From: Dmitry Eremin-Solenikov <dmitry.ereminsolenikov@linaro.org>


Implement AES-GMAC on top of OpenSSL AES-GCM with all text going into
AAD part.

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

---
/** Email created from pull request 288 (lumag:gmac)
 ** https://github.com/Linaro/odp/pull/288
 ** Patch: https://github.com/Linaro/odp/pull/288.patch
 ** Base sha: a908a4dead95321e84d6a8a23de060051dcd8969
 ** Merge commit sha: 60f2c36c67f6b216666f85876af63f7091b1bff0
 **/
 .../linux-generic/include/odp_crypto_internal.h    |   5 +-
 platform/linux-generic/odp_crypto.c                | 151 ++++++++++++++++++++-
 2 files changed, 154 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/platform/linux-generic/include/odp_crypto_internal.h b/platform/linux-generic/include/odp_crypto_internal.h
index 12d1720b7..21174daa4 100644
--- a/platform/linux-generic/include/odp_crypto_internal.h
+++ b/platform/linux-generic/include/odp_crypto_internal.h
@@ -51,7 +51,10 @@  struct odp_crypto_generic_session {
 		uint8_t  key[EVP_MAX_KEY_LENGTH];
 		uint32_t key_length;
 		uint32_t bytes;
-		const EVP_MD *evp_md;
+		union {
+			const EVP_MD *evp_md;
+			const EVP_CIPHER *evp_cipher;
+		};
 		crypto_func_t func;
 	} auth;
 };
diff --git a/platform/linux-generic/odp_crypto.c b/platform/linux-generic/odp_crypto.c
index f34863bf2..1cc2d7018 100644
--- a/platform/linux-generic/odp_crypto.c
+++ b/platform/linux-generic/odp_crypto.c
@@ -37,7 +37,9 @@ 
  * Keep sorted: first by key length, then by IV length
  */
 static const odp_crypto_cipher_capability_t cipher_capa_null[] = {
-{.key_len = 0, .iv_len = 0} };
+{.key_len = 0, .iv_len = 0},
+/* Special case for GMAC */
+{.key_len = 0, .iv_len = 12} };
 
 static const odp_crypto_cipher_capability_t cipher_capa_trides_cbc[] = {
 {.key_len = 24, .iv_len = 8} };
@@ -84,6 +86,9 @@  static const odp_crypto_auth_capability_t auth_capa_sha512_hmac[] = {
 static const odp_crypto_auth_capability_t auth_capa_aes_gcm[] = {
 {.digest_len = 16, .key_len = 0, .aad_len = {.min = 8, .max = 12, .inc = 4} } };
 
+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} } };
+
 typedef struct odp_crypto_global_s odp_crypto_global_t;
 
 struct odp_crypto_global_s {
@@ -236,6 +241,33 @@  odp_crypto_alg_err_t auth_check(odp_packet_t pkt,
 }
 
 static
+int internal_aad(EVP_CIPHER_CTX *ctx,
+		 odp_packet_t pkt,
+		 const odp_crypto_packet_op_param_t *param)
+{
+	uint32_t offset = param->auth_range.offset;
+	uint32_t len   = param->auth_range.length;
+	int dummy_len;
+	int ret;
+
+	ODP_ASSERT(offset + len <= odp_packet_len(pkt));
+
+	while (len > 0) {
+		uint32_t seglen = 0; /* GCC */
+		void *mapaddr = odp_packet_offset(pkt, offset, &seglen, NULL);
+		uint32_t maclen = len > seglen ? seglen : len;
+
+		EVP_EncryptUpdate(ctx, NULL, &dummy_len, mapaddr, maclen);
+		offset  += maclen;
+		len     -= maclen;
+	}
+
+	ret = EVP_EncryptFinal_ex(ctx, NULL, &dummy_len);
+
+	return ret;
+}
+
+static
 int internal_encrypt(EVP_CIPHER_CTX *ctx,
 		     odp_packet_t pkt,
 		     const odp_crypto_packet_op_param_t *param)
@@ -556,6 +588,108 @@  static int process_aes_gcm_param(odp_crypto_generic_session_t *session,
 	return 0;
 }
 
+static
+odp_crypto_alg_err_t aes_gmac_gen(odp_packet_t pkt,
+				  const odp_crypto_packet_op_param_t *param,
+				  odp_crypto_generic_session_t *session)
+{
+	EVP_CIPHER_CTX *ctx;
+	void *iv_ptr;
+	uint8_t block[EVP_MAX_MD_SIZE];
+	int ret;
+
+	if (param->override_iv_ptr)
+		iv_ptr = param->override_iv_ptr;
+	else if (session->p.iv.data)
+		iv_ptr = session->cipher.iv_data;
+	else
+		return ODP_CRYPTO_ALG_ERR_IV_INVALID;
+
+	/* Encrypt it */
+	ctx = EVP_CIPHER_CTX_new();
+	EVP_EncryptInit_ex(ctx, session->auth.evp_cipher, NULL,
+			   session->auth.key, NULL);
+	EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
+			    session->p.iv.length, NULL);
+	EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
+	EVP_CIPHER_CTX_set_padding(ctx, 0);
+
+	ret = internal_aad(ctx, pkt, param);
+
+	EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG,
+			    session->p.auth_digest_len, block);
+	odp_packet_copy_from_mem(pkt, param->hash_result_offset,
+				 session->p.auth_digest_len, block);
+
+	EVP_CIPHER_CTX_free(ctx);
+
+	return ret <= 0 ? ODP_CRYPTO_ALG_ERR_DATA_SIZE :
+			  ODP_CRYPTO_ALG_ERR_NONE;
+}
+
+static
+odp_crypto_alg_err_t aes_gmac_check(odp_packet_t pkt,
+				    const odp_crypto_packet_op_param_t *param,
+				    odp_crypto_generic_session_t *session)
+{
+	EVP_CIPHER_CTX *ctx;
+	void *iv_ptr;
+	uint8_t block[EVP_MAX_MD_SIZE];
+	int ret;
+
+	if (param->override_iv_ptr)
+		iv_ptr = param->override_iv_ptr;
+	else if (session->p.iv.data)
+		iv_ptr = session->cipher.iv_data;
+	else
+		return ODP_CRYPTO_ALG_ERR_IV_INVALID;
+
+	/* Decrypt it */
+	ctx = EVP_CIPHER_CTX_new();
+	EVP_DecryptInit_ex(ctx, session->auth.evp_cipher, NULL,
+			   session->auth.key, NULL);
+	EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
+			    session->p.iv.length, NULL);
+	EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
+	EVP_CIPHER_CTX_set_padding(ctx, 0);
+
+	odp_packet_copy_to_mem(pkt, param->hash_result_offset,
+			       session->p.auth_digest_len, block);
+	EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG,
+			    session->p.auth_digest_len, block);
+	_odp_packet_set_data(pkt, param->hash_result_offset,
+			     0, session->p.auth_digest_len);
+
+	ret = internal_aad(ctx, pkt, param);
+
+	EVP_CIPHER_CTX_free(ctx);
+
+	return ret <= 0 ? ODP_CRYPTO_ALG_ERR_ICV_CHECK :
+			  ODP_CRYPTO_ALG_ERR_NONE;
+}
+
+static int process_aes_gmac_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;
+
+	memcpy(session->auth.key, session->p.auth_key.data,
+	       session->p.auth_key.length);
+
+	session->auth.evp_cipher = cipher;
+
+	/* Set function */
+	if (ODP_CRYPTO_OP_ENCODE == session->p.op)
+		session->auth.func = aes_gmac_gen;
+	else
+		session->auth.func = aes_gmac_check;
+
+	return 0;
+}
+
 static int process_auth_param(odp_crypto_generic_session_t *session,
 			      uint32_t key_length,
 			      const EVP_MD *evp_md)
@@ -601,6 +735,7 @@  int odp_crypto_capability(odp_crypto_capability_t *capa)
 	capa->auths.bit.sha256_hmac  = 1;
 	capa->auths.bit.sha512_hmac  = 1;
 	capa->auths.bit.aes_gcm      = 1;
+	capa->auths.bit.aes_gmac     = 1;
 
 #if ODP_DEPRECATED_API
 	capa->ciphers.bit.aes128_cbc = 1;
@@ -688,6 +823,10 @@  int odp_crypto_auth_capability(odp_auth_alg_t auth,
 		src = auth_capa_aes_gcm;
 		num = sizeof(auth_capa_aes_gcm) / size;
 		break;
+	case ODP_AUTH_ALG_AES_GMAC:
+		src = auth_capa_aes_gmac;
+		num = sizeof(auth_capa_aes_gmac) / size;
+		break;
 	default:
 		return -1;
 	}
@@ -859,6 +998,16 @@  odp_crypto_session_create(odp_crypto_session_param_t *param,
 			rc = -1;
 		}
 		break;
+	case ODP_AUTH_ALG_AES_GMAC:
+		if (param->auth_key.length == 16)
+			rc = process_aes_gmac_param(session, EVP_aes_128_gcm());
+		else if (param->auth_key.length == 24)
+			rc = process_aes_gmac_param(session, EVP_aes_192_gcm());
+		else if (param->auth_key.length == 32)
+			rc = process_aes_gmac_param(session, EVP_aes_256_gcm());
+		else
+			rc = -1;
+		break;
 	default:
 		rc = -1;
 	}