0001
0002
0003
0004
0005
0006
0007 #include <linux/kernel.h>
0008 #include <linux/types.h>
0009 #include <linux/err.h>
0010 #include <crypto/aead.h>
0011 #include <crypto/aes.h>
0012
0013 #include <net/mac80211.h>
0014 #include "key.h"
0015 #include "aes_gmac.h"
0016
0017 int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
0018 const u8 *data, size_t data_len, u8 *mic)
0019 {
0020 struct scatterlist sg[5];
0021 u8 *zero, *__aad, iv[AES_BLOCK_SIZE];
0022 struct aead_request *aead_req;
0023 int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
0024 const __le16 *fc;
0025 int ret;
0026
0027 if (data_len < GMAC_MIC_LEN)
0028 return -EINVAL;
0029
0030 aead_req = kzalloc(reqsize + GMAC_MIC_LEN + GMAC_AAD_LEN, GFP_ATOMIC);
0031 if (!aead_req)
0032 return -ENOMEM;
0033
0034 zero = (u8 *)aead_req + reqsize;
0035 __aad = zero + GMAC_MIC_LEN;
0036 memcpy(__aad, aad, GMAC_AAD_LEN);
0037
0038 fc = (const __le16 *)aad;
0039 if (ieee80211_is_beacon(*fc)) {
0040
0041 sg_init_table(sg, 5);
0042 sg_set_buf(&sg[0], __aad, GMAC_AAD_LEN);
0043 sg_set_buf(&sg[1], zero, 8);
0044 sg_set_buf(&sg[2], data + 8, data_len - 8 - GMAC_MIC_LEN);
0045 sg_set_buf(&sg[3], zero, GMAC_MIC_LEN);
0046 sg_set_buf(&sg[4], mic, GMAC_MIC_LEN);
0047 } else {
0048 sg_init_table(sg, 4);
0049 sg_set_buf(&sg[0], __aad, GMAC_AAD_LEN);
0050 sg_set_buf(&sg[1], data, data_len - GMAC_MIC_LEN);
0051 sg_set_buf(&sg[2], zero, GMAC_MIC_LEN);
0052 sg_set_buf(&sg[3], mic, GMAC_MIC_LEN);
0053 }
0054
0055 memcpy(iv, nonce, GMAC_NONCE_LEN);
0056 memset(iv + GMAC_NONCE_LEN, 0, sizeof(iv) - GMAC_NONCE_LEN);
0057 iv[AES_BLOCK_SIZE - 1] = 0x01;
0058
0059 aead_request_set_tfm(aead_req, tfm);
0060 aead_request_set_crypt(aead_req, sg, sg, 0, iv);
0061 aead_request_set_ad(aead_req, GMAC_AAD_LEN + data_len);
0062
0063 ret = crypto_aead_encrypt(aead_req);
0064 kfree_sensitive(aead_req);
0065
0066 return ret;
0067 }
0068
0069 struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[],
0070 size_t key_len)
0071 {
0072 struct crypto_aead *tfm;
0073 int err;
0074
0075 tfm = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC);
0076 if (IS_ERR(tfm))
0077 return tfm;
0078
0079 err = crypto_aead_setkey(tfm, key, key_len);
0080 if (!err)
0081 err = crypto_aead_setauthsize(tfm, GMAC_MIC_LEN);
0082 if (!err)
0083 return tfm;
0084
0085 crypto_free_aead(tfm);
0086 return ERR_PTR(err);
0087 }
0088
0089 void ieee80211_aes_gmac_key_free(struct crypto_aead *tfm)
0090 {
0091 crypto_free_aead(tfm);
0092 }