From f5d592433f20216ad1b48d6110434200424399ec Mon Sep 17 00:00:00 2001 From: "Padma, Santhosh Kumar" Date: Mon, 18 Dec 2017 16:29:05 +0530 Subject: [PATCH] qcacmn: Add support for GMAC MIC calculation Add changes to calculate MIC using aead calls in linux Change-Id: I710b1c748c36babc8e66aaf920a07f9657f6e273 CRs-Fixed: 2164910 --- qdf/inc/qdf_crypto.h | 22 +++++++++- qdf/linux/src/qdf_crypto.c | 85 +++++++++++++++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/qdf/inc/qdf_crypto.h b/qdf/inc/qdf_crypto.h index 2aa0d54f18..8d592fdd44 100644 --- a/qdf/inc/qdf_crypto.h +++ b/qdf/inc/qdf_crypto.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -47,6 +47,9 @@ extern "C" { #define FIXED_PARAM_OFFSET_ASSOC_REQ 4 #define FIXED_PARAM_OFFSET_ASSOC_RSP 6 +#define AAD_LEN 20 +#define IEEE80211_MMIE_GMAC_MICLEN 16 + #define IS_VALID_CTR_KEY_LEN(len) ((((len) == 16) || ((len) == 32) || \ ((len) == 48)) ? 1 : 0) @@ -136,6 +139,23 @@ int qdf_aes_s2v(const uint8_t *key, unsigned int key_len, const uint8_t *s[], */ int qdf_aes_ctr(const uint8_t *key, unsigned int key_len, uint8_t *siv, const uint8_t *src, size_t src_len, uint8_t *dest, bool enc); + +/** + * qdf_crypto_aes_gmac: This API calculates MIC for GMAC + * @key: key used for operation + * @key_length: key length + * @iv: Initialization vector + * @aad: Additional authentication data + * @data: Pointer to data + * @data_len: Length of data + * @mic: Pointer to MIC + * + * Return: 0 if success else Error number + */ +int qdf_crypto_aes_gmac(uint8_t *key, uint16_t key_length, + uint8_t *iv, uint8_t *aad, uint8_t *data, + uint16_t data_len, uint8_t *mic); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/qdf/linux/src/qdf_crypto.c b/qdf/linux/src/qdf_crypto.c index f2c67b8b67..c0e6234342 100644 --- a/qdf/linux/src/qdf_crypto.c +++ b/qdf/linux/src/qdf_crypto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -28,6 +28,8 @@ #include #include #include +#include +#include /* Function Definitions and Documentation */ #define MAX_HMAC_ELEMENT_CNT 10 @@ -352,3 +354,84 @@ int qdf_aes_ctr(const uint8_t *key, unsigned int key_len, uint8_t *siv, return -EINVAL; } #endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +int qdf_crypto_aes_gmac(uint8_t *key, uint16_t key_length, + uint8_t *iv, uint8_t *aad, uint8_t *data, + uint16_t data_len, uint8_t *mic) +{ + struct crypto_aead *tfm; + int ret = 0; + struct scatterlist sg[4]; + uint16_t req_size; + struct aead_request *req = NULL; + uint8_t *aad_ptr, *input; + + tfm = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + ret = PTR_ERR(tfm); + tfm = NULL; + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: crypto_alloc_aead failed (%d)", __func__, ret); + goto err_tfm; + } + + ret = crypto_aead_setkey(tfm, key, key_length); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "crypto_aead_setkey failed (%d)", ret); + goto err_tfm; + } + + ret = crypto_aead_setauthsize(tfm, IEEE80211_MMIE_GMAC_MICLEN); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "crypto_aead_setauthsize failed (%d)", ret); + goto err_tfm; + } + + /* Prepare aead request */ + req_size = sizeof(*req) + crypto_aead_reqsize(tfm) + + IEEE80211_MMIE_GMAC_MICLEN + AAD_LEN; + req = qdf_mem_malloc(req_size); + if (!req) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Memory allocation failed"); + ret = -ENOMEM; + goto err_tfm; + } + + input = (uint8_t *)req + sizeof(*req) + crypto_aead_reqsize(tfm); + aad_ptr = input + IEEE80211_MMIE_GMAC_MICLEN; + qdf_mem_copy(aad_ptr, aad, AAD_LEN); + + /* Scatter list operations */ + sg_init_table(sg, 4); + sg_set_buf(&sg[0], aad_ptr, AAD_LEN); + sg_set_buf(&sg[1], data, data_len); + sg_set_buf(&sg[2], input, IEEE80211_MMIE_GMAC_MICLEN); + sg_set_buf(&sg[3], mic, IEEE80211_MMIE_GMAC_MICLEN); + + aead_request_set_tfm(req, tfm); + aead_request_set_crypt(req, sg, sg, 0, iv); + aead_request_set_ad(req, + AAD_LEN + data_len + IEEE80211_MMIE_GMAC_MICLEN); + crypto_aead_encrypt(req); + +err_tfm: + if (tfm) + crypto_free_aead(tfm); + + if (req) + qdf_mem_free(req); + + return ret; +} +#else +int qdf_crypto_aes_gmac(uint8_t *key, uint16_t key_length, + uint8_t *iv, uint8_t *aad, uint8_t *data, + uint16_t data_len, uint8_t *mic) +{ + return -EINVAL; +} +#endif