diff mbox series

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

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

Commit Message

Github ODP bot Nov. 9, 2017, 2 a.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: d22c949cc466bf28de559855a1cb525740578137
 ** Merge commit sha: d0ac0597cf696e17a40a8eba131ad379ba0fa08f
 **/
 .../linux-generic/include/odp_crypto_internal.h    |   5 +-
 platform/linux-generic/odp_crypto.c                | 149 ++++++++++++++++++++-
 2 files changed, 152 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 3174feee0..ac0fa337b 100644
--- a/platform/linux-generic/odp_crypto.c
+++ b/platform/linux-generic/odp_crypto.c
@@ -38,7 +38,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_des[] = {
 {.key_len = 24, .iv_len = 8} };
@@ -83,6 +85,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 {
@@ -235,6 +240,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)
@@ -555,6 +587,106 @@  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);
+
+	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)
@@ -600,6 +732,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;
@@ -687,6 +820,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;
 	}
@@ -849,6 +986,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;
 	}