1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * AES-GMAC for IEEE 802.11 BIP-GMAC-128 and BIP-GMAC-256
4*4882a593Smuzhiyun * Copyright 2015, Qualcomm Atheros, Inc.
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/kernel.h>
8*4882a593Smuzhiyun #include <linux/types.h>
9*4882a593Smuzhiyun #include <linux/err.h>
10*4882a593Smuzhiyun #include <crypto/aead.h>
11*4882a593Smuzhiyun #include <crypto/aes.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <net/mac80211.h>
14*4882a593Smuzhiyun #include "key.h"
15*4882a593Smuzhiyun #include "aes_gmac.h"
16*4882a593Smuzhiyun
ieee80211_aes_gmac(struct crypto_aead * tfm,const u8 * aad,u8 * nonce,const u8 * data,size_t data_len,u8 * mic)17*4882a593Smuzhiyun int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
18*4882a593Smuzhiyun const u8 *data, size_t data_len, u8 *mic)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun struct scatterlist sg[5];
21*4882a593Smuzhiyun u8 *zero, *__aad, iv[AES_BLOCK_SIZE];
22*4882a593Smuzhiyun struct aead_request *aead_req;
23*4882a593Smuzhiyun int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
24*4882a593Smuzhiyun const __le16 *fc;
25*4882a593Smuzhiyun int ret;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun if (data_len < GMAC_MIC_LEN)
28*4882a593Smuzhiyun return -EINVAL;
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun aead_req = kzalloc(reqsize + GMAC_MIC_LEN + GMAC_AAD_LEN, GFP_ATOMIC);
31*4882a593Smuzhiyun if (!aead_req)
32*4882a593Smuzhiyun return -ENOMEM;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun zero = (u8 *)aead_req + reqsize;
35*4882a593Smuzhiyun __aad = zero + GMAC_MIC_LEN;
36*4882a593Smuzhiyun memcpy(__aad, aad, GMAC_AAD_LEN);
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun fc = (const __le16 *)aad;
39*4882a593Smuzhiyun if (ieee80211_is_beacon(*fc)) {
40*4882a593Smuzhiyun /* mask Timestamp field to zero */
41*4882a593Smuzhiyun sg_init_table(sg, 5);
42*4882a593Smuzhiyun sg_set_buf(&sg[0], __aad, GMAC_AAD_LEN);
43*4882a593Smuzhiyun sg_set_buf(&sg[1], zero, 8);
44*4882a593Smuzhiyun sg_set_buf(&sg[2], data + 8, data_len - 8 - GMAC_MIC_LEN);
45*4882a593Smuzhiyun sg_set_buf(&sg[3], zero, GMAC_MIC_LEN);
46*4882a593Smuzhiyun sg_set_buf(&sg[4], mic, GMAC_MIC_LEN);
47*4882a593Smuzhiyun } else {
48*4882a593Smuzhiyun sg_init_table(sg, 4);
49*4882a593Smuzhiyun sg_set_buf(&sg[0], __aad, GMAC_AAD_LEN);
50*4882a593Smuzhiyun sg_set_buf(&sg[1], data, data_len - GMAC_MIC_LEN);
51*4882a593Smuzhiyun sg_set_buf(&sg[2], zero, GMAC_MIC_LEN);
52*4882a593Smuzhiyun sg_set_buf(&sg[3], mic, GMAC_MIC_LEN);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun memcpy(iv, nonce, GMAC_NONCE_LEN);
56*4882a593Smuzhiyun memset(iv + GMAC_NONCE_LEN, 0, sizeof(iv) - GMAC_NONCE_LEN);
57*4882a593Smuzhiyun iv[AES_BLOCK_SIZE - 1] = 0x01;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun aead_request_set_tfm(aead_req, tfm);
60*4882a593Smuzhiyun aead_request_set_crypt(aead_req, sg, sg, 0, iv);
61*4882a593Smuzhiyun aead_request_set_ad(aead_req, GMAC_AAD_LEN + data_len);
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun ret = crypto_aead_encrypt(aead_req);
64*4882a593Smuzhiyun kfree_sensitive(aead_req);
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun return ret;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun
ieee80211_aes_gmac_key_setup(const u8 key[],size_t key_len)69*4882a593Smuzhiyun struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[],
70*4882a593Smuzhiyun size_t key_len)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun struct crypto_aead *tfm;
73*4882a593Smuzhiyun int err;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun tfm = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC);
76*4882a593Smuzhiyun if (IS_ERR(tfm))
77*4882a593Smuzhiyun return tfm;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun err = crypto_aead_setkey(tfm, key, key_len);
80*4882a593Smuzhiyun if (!err)
81*4882a593Smuzhiyun err = crypto_aead_setauthsize(tfm, GMAC_MIC_LEN);
82*4882a593Smuzhiyun if (!err)
83*4882a593Smuzhiyun return tfm;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun crypto_free_aead(tfm);
86*4882a593Smuzhiyun return ERR_PTR(err);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
ieee80211_aes_gmac_key_free(struct crypto_aead * tfm)89*4882a593Smuzhiyun void ieee80211_aes_gmac_key_free(struct crypto_aead *tfm)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun crypto_free_aead(tfm);
92*4882a593Smuzhiyun }
93