summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qdf/inc/qdf_crypto.h24
-rw-r--r--qdf/linux/src/qdf_crypto.c86
2 files changed, 108 insertions, 2 deletions
diff --git a/qdf/inc/qdf_crypto.h b/qdf/inc/qdf_crypto.h
index 1cd3394245ca..a640a4a07ef7 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,11 @@ extern "C" {
#define FIXED_PARAM_OFFSET_ASSOC_REQ 4
#define FIXED_PARAM_OFFSET_ASSOC_RSP 6
+#ifdef WLAN_FEATURE_GMAC
+#define AAD_LEN 20
+#define IEEE80211_MMIE_GMAC_MICLEN 16
+#endif
+
/* Function declarations and documenation */
/**
@@ -133,6 +138,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 af6d456e273f..80ccd965b82b 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 <crypto/hash.h>
#include <crypto/aes.h>
#include <crypto/skcipher.h>
+#include <crypto/aead.h>
+#include <linux/ieee80211.h>
/* Function Definitions and Documentation */
#define MAX_HMAC_ELEMENT_CNT 10
@@ -352,3 +354,85 @@ int qdf_aes_ctr(const uint8_t *key, unsigned int key_len, uint8_t *siv,
return -EINVAL;
}
#endif
+
+#if defined(WLAN_FEATURE_GMAC) && \
+ (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