158391efdSNathan Chancellor // SPDX-License-Identifier: GPL-2.0
2554c0a3aSHans de Goede /******************************************************************************
3554c0a3aSHans de Goede *
4554c0a3aSHans de Goede * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
5554c0a3aSHans de Goede *
6554c0a3aSHans de Goede ******************************************************************************/
7b97fad10SFabio Aiuto #include <linux/crc32.h>
8554c0a3aSHans de Goede #include <drv_types.h>
9554c0a3aSHans de Goede #include <rtw_debug.h>
107d40753dSFabio Aiuto #include <crypto/aes.h>
11554c0a3aSHans de Goede
126cf26021SJoe Perches static const char * const _security_type_str[] = {
13554c0a3aSHans de Goede "N/A",
14554c0a3aSHans de Goede "WEP40",
15554c0a3aSHans de Goede "TKIP",
16554c0a3aSHans de Goede "TKIP_WM",
17554c0a3aSHans de Goede "AES",
18554c0a3aSHans de Goede "WEP104",
19554c0a3aSHans de Goede "SMS4",
20554c0a3aSHans de Goede "WEP_WPA",
21554c0a3aSHans de Goede "BIP",
22554c0a3aSHans de Goede };
23554c0a3aSHans de Goede
security_type_str(u8 value)24554c0a3aSHans de Goede const char *security_type_str(u8 value)
25554c0a3aSHans de Goede {
26554c0a3aSHans de Goede if (value <= _BIP_)
27554c0a3aSHans de Goede return _security_type_str[value];
28554c0a3aSHans de Goede return NULL;
29554c0a3aSHans de Goede }
30554c0a3aSHans de Goede
31554c0a3aSHans de Goede /* WEP related ===== */
32554c0a3aSHans de Goede
33554c0a3aSHans de Goede /*
34554c0a3aSHans de Goede Need to consider the fragment situation
35554c0a3aSHans de Goede */
rtw_wep_encrypt(struct adapter * padapter,u8 * pxmitframe)36554c0a3aSHans de Goede void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe)
37554c0a3aSHans de Goede { /* exclude ICV */
38aef1c966SFabio M. De Francesco union {
39aef1c966SFabio M. De Francesco __le32 f0;
40aef1c966SFabio M. De Francesco unsigned char f1[4];
41aef1c966SFabio M. De Francesco } crc;
42554c0a3aSHans de Goede
43d495c550SMarco Cesati signed int curfragnum, length;
44554c0a3aSHans de Goede u32 keylength;
45554c0a3aSHans de Goede
46554c0a3aSHans de Goede u8 *pframe, *payload, *iv; /* wepkey */
47554c0a3aSHans de Goede u8 wepkey[16];
48554c0a3aSHans de Goede u8 hw_hdr_offset = 0;
49554c0a3aSHans de Goede struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib;
50554c0a3aSHans de Goede struct security_priv *psecuritypriv = &padapter->securitypriv;
51554c0a3aSHans de Goede struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
52a1b8a9bbSFabio Aiuto struct arc4_ctx *ctx = &psecuritypriv->xmit_arc4_ctx;
53554c0a3aSHans de Goede
54cd1f1450SMichael Straube if (!((struct xmit_frame *)pxmitframe)->buf_addr)
55554c0a3aSHans de Goede return;
56554c0a3aSHans de Goede
57554c0a3aSHans de Goede hw_hdr_offset = TXDESC_OFFSET;
58554c0a3aSHans de Goede pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset;
59554c0a3aSHans de Goede
60554c0a3aSHans de Goede /* start to encrypt each fragment */
61554c0a3aSHans de Goede if ((pattrib->encrypt == _WEP40_) || (pattrib->encrypt == _WEP104_)) {
62554c0a3aSHans de Goede keylength = psecuritypriv->dot11DefKeylen[psecuritypriv->dot11PrivacyKeyIndex];
63554c0a3aSHans de Goede
64554c0a3aSHans de Goede for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) {
65554c0a3aSHans de Goede iv = pframe+pattrib->hdrlen;
66554c0a3aSHans de Goede memcpy(&wepkey[0], iv, 3);
67554c0a3aSHans de Goede memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[psecuritypriv->dot11PrivacyKeyIndex].skey[0], keylength);
68554c0a3aSHans de Goede payload = pframe+pattrib->iv_len+pattrib->hdrlen;
69554c0a3aSHans de Goede
70554c0a3aSHans de Goede if ((curfragnum+1) == pattrib->nr_frags) { /* the last fragment */
71554c0a3aSHans de Goede
72554c0a3aSHans de Goede length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
73554c0a3aSHans de Goede
74aef1c966SFabio M. De Francesco crc.f0 = cpu_to_le32(~crc32_le(~0, payload, length));
75554c0a3aSHans de Goede
76a1b8a9bbSFabio Aiuto arc4_setkey(ctx, wepkey, 3 + keylength);
77a1b8a9bbSFabio Aiuto arc4_crypt(ctx, payload, payload, length);
78aef1c966SFabio M. De Francesco arc4_crypt(ctx, payload + length, crc.f1, 4);
79554c0a3aSHans de Goede
80554c0a3aSHans de Goede } else {
81554c0a3aSHans de Goede length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
82aef1c966SFabio M. De Francesco crc.f0 = cpu_to_le32(~crc32_le(~0, payload, length));
83a1b8a9bbSFabio Aiuto arc4_setkey(ctx, wepkey, 3 + keylength);
84a1b8a9bbSFabio Aiuto arc4_crypt(ctx, payload, payload, length);
85aef1c966SFabio M. De Francesco arc4_crypt(ctx, payload + length, crc.f1, 4);
86554c0a3aSHans de Goede
87554c0a3aSHans de Goede pframe += pxmitpriv->frag_len;
8887fe08d7SRoss Schmidt pframe = (u8 *)round_up((SIZE_PTR)(pframe), 4);
89554c0a3aSHans de Goede }
90554c0a3aSHans de Goede }
91554c0a3aSHans de Goede }
92554c0a3aSHans de Goede }
93554c0a3aSHans de Goede
rtw_wep_decrypt(struct adapter * padapter,u8 * precvframe)94554c0a3aSHans de Goede void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe)
95554c0a3aSHans de Goede {
96554c0a3aSHans de Goede /* exclude ICV */
97554c0a3aSHans de Goede u8 crc[4];
98d495c550SMarco Cesati signed int length;
99554c0a3aSHans de Goede u32 keylength;
100554c0a3aSHans de Goede u8 *pframe, *payload, *iv, wepkey[16];
101554c0a3aSHans de Goede u8 keyindex;
102554c0a3aSHans de Goede struct rx_pkt_attrib *prxattrib = &(((union recv_frame *)precvframe)->u.hdr.attrib);
103554c0a3aSHans de Goede struct security_priv *psecuritypriv = &padapter->securitypriv;
104a1b8a9bbSFabio Aiuto struct arc4_ctx *ctx = &psecuritypriv->recv_arc4_ctx;
105554c0a3aSHans de Goede
106554c0a3aSHans de Goede pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
107554c0a3aSHans de Goede
108554c0a3aSHans de Goede /* start to decrypt recvframe */
109554c0a3aSHans de Goede if ((prxattrib->encrypt == _WEP40_) || (prxattrib->encrypt == _WEP104_)) {
110554c0a3aSHans de Goede iv = pframe+prxattrib->hdrlen;
111554c0a3aSHans de Goede /* keyindex =(iv[3]&0x3); */
112554c0a3aSHans de Goede keyindex = prxattrib->key_index;
113554c0a3aSHans de Goede keylength = psecuritypriv->dot11DefKeylen[keyindex];
114554c0a3aSHans de Goede memcpy(&wepkey[0], iv, 3);
115554c0a3aSHans de Goede /* memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[psecuritypriv->dot11PrivacyKeyIndex].skey[0], keylength); */
116554c0a3aSHans de Goede memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[keyindex].skey[0], keylength);
117554c0a3aSHans de Goede length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len;
118554c0a3aSHans de Goede
119554c0a3aSHans de Goede payload = pframe+prxattrib->iv_len+prxattrib->hdrlen;
120554c0a3aSHans de Goede
121554c0a3aSHans de Goede /* decrypt payload include icv */
122a1b8a9bbSFabio Aiuto arc4_setkey(ctx, wepkey, 3 + keylength);
123a1b8a9bbSFabio Aiuto arc4_crypt(ctx, payload, payload, length);
124554c0a3aSHans de Goede
125554c0a3aSHans de Goede /* calculate icv and compare the icv */
126aef1c966SFabio M. De Francesco *((u32 *)crc) = ~crc32_le(~0, payload, length - 4);
127554c0a3aSHans de Goede
128554c0a3aSHans de Goede }
129554c0a3aSHans de Goede }
130554c0a3aSHans de Goede
131554c0a3aSHans de Goede /* 3 =====TKIP related ===== */
132554c0a3aSHans de Goede
secmicgetuint32(u8 * p)133554c0a3aSHans de Goede static u32 secmicgetuint32(u8 *p)
134554c0a3aSHans de Goede /* Convert from Byte[] to Us3232 in a portable way */
135554c0a3aSHans de Goede {
136554c0a3aSHans de Goede s32 i;
137554c0a3aSHans de Goede u32 res = 0;
138554c0a3aSHans de Goede
139df94d3b2SBrother Matthew De Angelis for (i = 0; i < 4; i++)
140554c0a3aSHans de Goede res |= ((u32)(*p++)) << (8 * i);
141554c0a3aSHans de Goede
142554c0a3aSHans de Goede return res;
143554c0a3aSHans de Goede }
144554c0a3aSHans de Goede
secmicputuint32(u8 * p,u32 val)145554c0a3aSHans de Goede static void secmicputuint32(u8 *p, u32 val)
146554c0a3aSHans de Goede /* Convert from Us3232 to Byte[] in a portable way */
147554c0a3aSHans de Goede {
148554c0a3aSHans de Goede long i;
149554c0a3aSHans de Goede
150554c0a3aSHans de Goede for (i = 0; i < 4; i++) {
151554c0a3aSHans de Goede *p++ = (u8) (val & 0xff);
152554c0a3aSHans de Goede val >>= 8;
153554c0a3aSHans de Goede }
154554c0a3aSHans de Goede }
155554c0a3aSHans de Goede
secmicclear(struct mic_data * pmicdata)156554c0a3aSHans de Goede static void secmicclear(struct mic_data *pmicdata)
157554c0a3aSHans de Goede {
158554c0a3aSHans de Goede /* Reset the state to the empty message. */
159554c0a3aSHans de Goede pmicdata->L = pmicdata->K0;
160554c0a3aSHans de Goede pmicdata->R = pmicdata->K1;
161554c0a3aSHans de Goede pmicdata->nBytesInM = 0;
162554c0a3aSHans de Goede pmicdata->M = 0;
163554c0a3aSHans de Goede }
164554c0a3aSHans de Goede
rtw_secmicsetkey(struct mic_data * pmicdata,u8 * key)165554c0a3aSHans de Goede void rtw_secmicsetkey(struct mic_data *pmicdata, u8 *key)
166554c0a3aSHans de Goede {
167554c0a3aSHans de Goede /* Set the key */
168554c0a3aSHans de Goede pmicdata->K0 = secmicgetuint32(key);
169554c0a3aSHans de Goede pmicdata->K1 = secmicgetuint32(key + 4);
170554c0a3aSHans de Goede /* and reset the message */
171554c0a3aSHans de Goede secmicclear(pmicdata);
172554c0a3aSHans de Goede }
173554c0a3aSHans de Goede
rtw_secmicappendbyte(struct mic_data * pmicdata,u8 b)174554c0a3aSHans de Goede void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b)
175554c0a3aSHans de Goede {
176554c0a3aSHans de Goede /* Append the byte to our word-sized buffer */
177554c0a3aSHans de Goede pmicdata->M |= ((unsigned long)b) << (8*pmicdata->nBytesInM);
178554c0a3aSHans de Goede pmicdata->nBytesInM++;
179554c0a3aSHans de Goede /* Process the word if it is full. */
180554c0a3aSHans de Goede if (pmicdata->nBytesInM >= 4) {
181554c0a3aSHans de Goede pmicdata->L ^= pmicdata->M;
182554c0a3aSHans de Goede pmicdata->R ^= ROL32(pmicdata->L, 17);
183554c0a3aSHans de Goede pmicdata->L += pmicdata->R;
184554c0a3aSHans de Goede pmicdata->R ^= ((pmicdata->L & 0xff00ff00) >> 8) | ((pmicdata->L & 0x00ff00ff) << 8);
185554c0a3aSHans de Goede pmicdata->L += pmicdata->R;
186554c0a3aSHans de Goede pmicdata->R ^= ROL32(pmicdata->L, 3);
187554c0a3aSHans de Goede pmicdata->L += pmicdata->R;
188554c0a3aSHans de Goede pmicdata->R ^= ROR32(pmicdata->L, 2);
189554c0a3aSHans de Goede pmicdata->L += pmicdata->R;
190554c0a3aSHans de Goede /* Clear the buffer */
191554c0a3aSHans de Goede pmicdata->M = 0;
192554c0a3aSHans de Goede pmicdata->nBytesInM = 0;
193554c0a3aSHans de Goede }
194554c0a3aSHans de Goede }
195554c0a3aSHans de Goede
rtw_secmicappend(struct mic_data * pmicdata,u8 * src,u32 nbytes)196554c0a3aSHans de Goede void rtw_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nbytes)
197554c0a3aSHans de Goede {
198554c0a3aSHans de Goede /* This is simple */
199554c0a3aSHans de Goede while (nbytes > 0) {
200554c0a3aSHans de Goede rtw_secmicappendbyte(pmicdata, *src++);
201554c0a3aSHans de Goede nbytes--;
202554c0a3aSHans de Goede }
203554c0a3aSHans de Goede }
204554c0a3aSHans de Goede
rtw_secgetmic(struct mic_data * pmicdata,u8 * dst)205554c0a3aSHans de Goede void rtw_secgetmic(struct mic_data *pmicdata, u8 *dst)
206554c0a3aSHans de Goede {
207554c0a3aSHans de Goede /* Append the minimum padding */
208554c0a3aSHans de Goede rtw_secmicappendbyte(pmicdata, 0x5a);
209554c0a3aSHans de Goede rtw_secmicappendbyte(pmicdata, 0);
210554c0a3aSHans de Goede rtw_secmicappendbyte(pmicdata, 0);
211554c0a3aSHans de Goede rtw_secmicappendbyte(pmicdata, 0);
212554c0a3aSHans de Goede rtw_secmicappendbyte(pmicdata, 0);
213554c0a3aSHans de Goede /* and then zeroes until the length is a multiple of 4 */
214df94d3b2SBrother Matthew De Angelis while (pmicdata->nBytesInM != 0)
215554c0a3aSHans de Goede rtw_secmicappendbyte(pmicdata, 0);
216554c0a3aSHans de Goede /* The appendByte function has already computed the result. */
217554c0a3aSHans de Goede secmicputuint32(dst, pmicdata->L);
218554c0a3aSHans de Goede secmicputuint32(dst + 4, pmicdata->R);
219554c0a3aSHans de Goede /* Reset to the empty message. */
220554c0a3aSHans de Goede secmicclear(pmicdata);
221554c0a3aSHans de Goede }
222554c0a3aSHans de Goede
223554c0a3aSHans de Goede
rtw_seccalctkipmic(u8 * key,u8 * header,u8 * data,u32 data_len,u8 * mic_code,u8 pri)224554c0a3aSHans de Goede void rtw_seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len, u8 *mic_code, u8 pri)
225554c0a3aSHans de Goede {
226554c0a3aSHans de Goede
227554c0a3aSHans de Goede struct mic_data micdata;
228554c0a3aSHans de Goede u8 priority[4] = {0x0, 0x0, 0x0, 0x0};
229554c0a3aSHans de Goede
230554c0a3aSHans de Goede rtw_secmicsetkey(&micdata, key);
231554c0a3aSHans de Goede priority[0] = pri;
232554c0a3aSHans de Goede
233554c0a3aSHans de Goede /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */
234554c0a3aSHans de Goede if (header[1] & 1) { /* ToDS == 1 */
235554c0a3aSHans de Goede rtw_secmicappend(&micdata, &header[16], 6); /* DA */
236554c0a3aSHans de Goede if (header[1] & 2) /* From Ds == 1 */
237554c0a3aSHans de Goede rtw_secmicappend(&micdata, &header[24], 6);
238554c0a3aSHans de Goede else
239554c0a3aSHans de Goede rtw_secmicappend(&micdata, &header[10], 6);
240554c0a3aSHans de Goede } else { /* ToDS == 0 */
241554c0a3aSHans de Goede rtw_secmicappend(&micdata, &header[4], 6); /* DA */
242554c0a3aSHans de Goede if (header[1] & 2) /* From Ds == 1 */
243554c0a3aSHans de Goede rtw_secmicappend(&micdata, &header[16], 6);
244554c0a3aSHans de Goede else
245554c0a3aSHans de Goede rtw_secmicappend(&micdata, &header[10], 6);
246554c0a3aSHans de Goede }
247554c0a3aSHans de Goede rtw_secmicappend(&micdata, &priority[0], 4);
248554c0a3aSHans de Goede
249554c0a3aSHans de Goede
250554c0a3aSHans de Goede rtw_secmicappend(&micdata, data, data_len);
251554c0a3aSHans de Goede
252554c0a3aSHans de Goede rtw_secgetmic(&micdata, mic_code);
253554c0a3aSHans de Goede }
254554c0a3aSHans de Goede
255554c0a3aSHans de Goede /* macros for extraction/creation of unsigned char/unsigned short values */
256554c0a3aSHans de Goede #define RotR1(v16) ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15))
257554c0a3aSHans de Goede #define Lo8(v16) ((u8)((v16) & 0x00FF))
258554c0a3aSHans de Goede #define Hi8(v16) ((u8)(((v16) >> 8) & 0x00FF))
259554c0a3aSHans de Goede #define Lo16(v32) ((u16)((v32) & 0xFFFF))
260554c0a3aSHans de Goede #define Hi16(v32) ((u16)(((v32) >> 16) & 0xFFFF))
261554c0a3aSHans de Goede #define Mk16(hi, lo) ((lo) ^ (((u16)(hi)) << 8))
262554c0a3aSHans de Goede
263554c0a3aSHans de Goede /* select the Nth 16-bit word of the temporal key unsigned char array TK[] */
264554c0a3aSHans de Goede #define TK16(N) Mk16(tk[2*(N)+1], tk[2*(N)])
265554c0a3aSHans de Goede
266554c0a3aSHans de Goede /* S-box lookup: 16 bits --> 16 bits */
267554c0a3aSHans de Goede #define _S_(v16) (Sbox1[0][Lo8(v16)] ^ Sbox1[1][Hi8(v16)])
268554c0a3aSHans de Goede
269554c0a3aSHans de Goede /* fixed algorithm "parameters" */
270554c0a3aSHans de Goede #define PHASE1_LOOP_CNT 8 /* this needs to be "big enough" */
271554c0a3aSHans de Goede
272554c0a3aSHans de Goede /* 2-unsigned char by 2-unsigned char subset of the full AES S-box table */
273554c0a3aSHans de Goede static const unsigned short Sbox1[2][256] = { /* Sbox for hash (can be in ROM) */
274554c0a3aSHans de Goede {
275554c0a3aSHans de Goede 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
276554c0a3aSHans de Goede 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
277554c0a3aSHans de Goede 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
278554c0a3aSHans de Goede 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
279554c0a3aSHans de Goede 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
280554c0a3aSHans de Goede 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
281554c0a3aSHans de Goede 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
282554c0a3aSHans de Goede 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
283554c0a3aSHans de Goede 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
284554c0a3aSHans de Goede 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
285554c0a3aSHans de Goede 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
286554c0a3aSHans de Goede 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
287554c0a3aSHans de Goede 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
288554c0a3aSHans de Goede 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
289554c0a3aSHans de Goede 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
290554c0a3aSHans de Goede 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
291554c0a3aSHans de Goede 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
292554c0a3aSHans de Goede 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
293554c0a3aSHans de Goede 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
294554c0a3aSHans de Goede 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
295554c0a3aSHans de Goede 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
296554c0a3aSHans de Goede 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
297554c0a3aSHans de Goede 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
298554c0a3aSHans de Goede 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
299554c0a3aSHans de Goede 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
300554c0a3aSHans de Goede 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
301554c0a3aSHans de Goede 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
302554c0a3aSHans de Goede 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
303554c0a3aSHans de Goede 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
304554c0a3aSHans de Goede 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
305554c0a3aSHans de Goede 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
306554c0a3aSHans de Goede 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
307554c0a3aSHans de Goede },
308554c0a3aSHans de Goede
309554c0a3aSHans de Goede
310554c0a3aSHans de Goede { /* second half of table is unsigned char-reversed version of first! */
311554c0a3aSHans de Goede 0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491,
312554c0a3aSHans de Goede 0x5060, 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC,
313554c0a3aSHans de Goede 0x458F, 0x9D1F, 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB,
314554c0a3aSHans de Goede 0xEC41, 0x67B3, 0xFD5F, 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B,
315554c0a3aSHans de Goede 0xC275, 0x1CE1, 0xAE3D, 0x6A4C, 0x5A6C, 0x417E, 0x02F5, 0x4F83,
316554c0a3aSHans de Goede 0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, 0x73AB, 0x5362, 0x3F2A,
317554c0a3aSHans de Goede 0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, 0x0F0A, 0xB52F,
318554c0a3aSHans de Goede 0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, 0x9FEA,
319554c0a3aSHans de Goede 0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B,
320554c0a3aSHans de Goede 0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713,
321554c0a3aSHans de Goede 0xF5A6, 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6,
322554c0a3aSHans de Goede 0xBED4, 0x468D, 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85,
323554c0a3aSHans de Goede 0x6BBB, 0x2AC5, 0xE54F, 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411,
324554c0a3aSHans de Goede 0xCF8A, 0x10E9, 0x0604, 0x81FE, 0xF0A0, 0x4478, 0xBA25, 0xE34B,
325554c0a3aSHans de Goede 0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, 0xBC21, 0x4870, 0x04F1,
326554c0a3aSHans de Goede 0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, 0x0EFD, 0x6DBF,
327554c0a3aSHans de Goede 0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, 0x392E,
328554c0a3aSHans de Goede 0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6,
329554c0a3aSHans de Goede 0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B,
330554c0a3aSHans de Goede 0xCA8C, 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD,
331554c0a3aSHans de Goede 0x3BDB, 0x5664, 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8,
332554c0a3aSHans de Goede 0x5D9F, 0x6EBD, 0xEF43, 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2,
333554c0a3aSHans de Goede 0x32D5, 0x438B, 0x596E, 0xB7DA, 0x8C01, 0x64B1, 0xD29C, 0xE049,
334554c0a3aSHans de Goede 0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, 0x8EF4, 0xE947, 0x1810,
335554c0a3aSHans de Goede 0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, 0xC773, 0x5197,
336554c0a3aSHans de Goede 0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, 0x850F,
337554c0a3aSHans de Goede 0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C,
338554c0a3aSHans de Goede 0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927,
339554c0a3aSHans de Goede 0x38D9, 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733,
340554c0a3aSHans de Goede 0xB62D, 0x223C, 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5,
341554c0a3aSHans de Goede 0x8F03, 0xF859, 0x8009, 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0,
342554c0a3aSHans de Goede 0xC382, 0xB029, 0x775A, 0x111E, 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C,
343554c0a3aSHans de Goede }
344554c0a3aSHans de Goede };
345554c0a3aSHans de Goede
346554c0a3aSHans de Goede /*
347554c0a3aSHans de Goede **********************************************************************
348554c0a3aSHans de Goede * Routine: Phase 1 -- generate P1K, given TA, TK, IV32
349554c0a3aSHans de Goede *
350554c0a3aSHans de Goede * Inputs:
351554c0a3aSHans de Goede * tk[] = temporal key [128 bits]
352554c0a3aSHans de Goede * ta[] = transmitter's MAC address [ 48 bits]
353554c0a3aSHans de Goede * iv32 = upper 32 bits of IV [ 32 bits]
354554c0a3aSHans de Goede * Output:
355554c0a3aSHans de Goede * p1k[] = Phase 1 key [ 80 bits]
356554c0a3aSHans de Goede *
357554c0a3aSHans de Goede * Note:
358554c0a3aSHans de Goede * This function only needs to be called every 2**16 packets,
359554c0a3aSHans de Goede * although in theory it could be called every packet.
360554c0a3aSHans de Goede *
361554c0a3aSHans de Goede **********************************************************************
362554c0a3aSHans de Goede */
phase1(u16 * p1k,const u8 * tk,const u8 * ta,u32 iv32)363554c0a3aSHans de Goede static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32)
364554c0a3aSHans de Goede {
365d495c550SMarco Cesati signed int i;
366554c0a3aSHans de Goede
367554c0a3aSHans de Goede /* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */
368554c0a3aSHans de Goede p1k[0] = Lo16(iv32);
369554c0a3aSHans de Goede p1k[1] = Hi16(iv32);
370554c0a3aSHans de Goede p1k[2] = Mk16(ta[1], ta[0]); /* use TA[] as little-endian */
371554c0a3aSHans de Goede p1k[3] = Mk16(ta[3], ta[2]);
372554c0a3aSHans de Goede p1k[4] = Mk16(ta[5], ta[4]);
373554c0a3aSHans de Goede
374554c0a3aSHans de Goede /* Now compute an unbalanced Feistel cipher with 80-bit block */
375554c0a3aSHans de Goede /* size on the 80-bit block P1K[], using the 128-bit key TK[] */
376554c0a3aSHans de Goede for (i = 0; i < PHASE1_LOOP_CNT; i++) {
377554c0a3aSHans de Goede /* Each add operation here is mod 2**16 */
378554c0a3aSHans de Goede p1k[0] += _S_(p1k[4] ^ TK16((i&1)+0));
379554c0a3aSHans de Goede p1k[1] += _S_(p1k[0] ^ TK16((i&1)+2));
380554c0a3aSHans de Goede p1k[2] += _S_(p1k[1] ^ TK16((i&1)+4));
381554c0a3aSHans de Goede p1k[3] += _S_(p1k[2] ^ TK16((i&1)+6));
382554c0a3aSHans de Goede p1k[4] += _S_(p1k[3] ^ TK16((i&1)+0));
383554c0a3aSHans de Goede p1k[4] += (unsigned short)i; /* avoid "slide attacks" */
384554c0a3aSHans de Goede }
385554c0a3aSHans de Goede }
386554c0a3aSHans de Goede
387554c0a3aSHans de Goede
388554c0a3aSHans de Goede /*
389554c0a3aSHans de Goede **********************************************************************
390554c0a3aSHans de Goede * Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16
391554c0a3aSHans de Goede *
392554c0a3aSHans de Goede * Inputs:
393554c0a3aSHans de Goede * tk[] = Temporal key [128 bits]
394554c0a3aSHans de Goede * p1k[] = Phase 1 output key [ 80 bits]
395554c0a3aSHans de Goede * iv16 = low 16 bits of IV counter [ 16 bits]
396554c0a3aSHans de Goede * Output:
397554c0a3aSHans de Goede * rc4key[] = the key used to encrypt the packet [128 bits]
398554c0a3aSHans de Goede *
399554c0a3aSHans de Goede * Note:
400554c0a3aSHans de Goede * The value {TA, IV32, IV16} for Phase1/Phase2 must be unique
401554c0a3aSHans de Goede * across all packets using the same key TK value. Then, for a
402554c0a3aSHans de Goede * given value of TK[], this TKIP48 construction guarantees that
403554c0a3aSHans de Goede * the final RC4KEY value is unique across all packets.
404554c0a3aSHans de Goede *
405554c0a3aSHans de Goede * Suggested implementation optimization: if PPK[] is "overlaid"
406554c0a3aSHans de Goede * appropriately on RC4KEY[], there is no need for the final
407554c0a3aSHans de Goede * for loop below that copies the PPK[] result into RC4KEY[].
408554c0a3aSHans de Goede *
409554c0a3aSHans de Goede **********************************************************************
410554c0a3aSHans de Goede */
phase2(u8 * rc4key,const u8 * tk,const u16 * p1k,u16 iv16)411554c0a3aSHans de Goede static void phase2(u8 *rc4key, const u8 *tk, const u16 *p1k, u16 iv16)
412554c0a3aSHans de Goede {
413d495c550SMarco Cesati signed int i;
414554c0a3aSHans de Goede u16 PPK[6]; /* temporary key for mixing */
415554c0a3aSHans de Goede
416554c0a3aSHans de Goede /* Note: all adds in the PPK[] equations below are mod 2**16 */
417554c0a3aSHans de Goede for (i = 0; i < 5; i++)
418554c0a3aSHans de Goede PPK[i] = p1k[i]; /* first, copy P1K to PPK */
419554c0a3aSHans de Goede
420554c0a3aSHans de Goede PPK[5] = p1k[4]+iv16; /* next, add in IV16 */
421554c0a3aSHans de Goede
422554c0a3aSHans de Goede /* Bijective non-linear mixing of the 96 bits of PPK[0..5] */
423554c0a3aSHans de Goede PPK[0] += _S_(PPK[5] ^ TK16(0)); /* Mix key in each "round" */
424554c0a3aSHans de Goede PPK[1] += _S_(PPK[0] ^ TK16(1));
425554c0a3aSHans de Goede PPK[2] += _S_(PPK[1] ^ TK16(2));
426554c0a3aSHans de Goede PPK[3] += _S_(PPK[2] ^ TK16(3));
427554c0a3aSHans de Goede PPK[4] += _S_(PPK[3] ^ TK16(4));
428554c0a3aSHans de Goede PPK[5] += _S_(PPK[4] ^ TK16(5)); /* Total # S-box lookups == 6 */
429554c0a3aSHans de Goede
430554c0a3aSHans de Goede /* Final sweep: bijective, "linear". Rotates kill LSB correlations */
431554c0a3aSHans de Goede PPK[0] += RotR1(PPK[5] ^ TK16(6));
432554c0a3aSHans de Goede PPK[1] += RotR1(PPK[0] ^ TK16(7)); /* Use all of TK[] in Phase2 */
433554c0a3aSHans de Goede PPK[2] += RotR1(PPK[1]);
434554c0a3aSHans de Goede PPK[3] += RotR1(PPK[2]);
435554c0a3aSHans de Goede PPK[4] += RotR1(PPK[3]);
436554c0a3aSHans de Goede PPK[5] += RotR1(PPK[4]);
437554c0a3aSHans de Goede /* Note: At this point, for a given key TK[0..15], the 96-bit output */
438554c0a3aSHans de Goede /* value PPK[0..5] is guaranteed to be unique, as a function */
439554c0a3aSHans de Goede /* of the 96-bit "input" value {TA, IV32, IV16}. That is, P1K */
440554c0a3aSHans de Goede /* is now a keyed permutation of {TA, IV32, IV16}. */
441554c0a3aSHans de Goede
442554c0a3aSHans de Goede /* Set RC4KEY[0..3], which includes "cleartext" portion of RC4 key */
443554c0a3aSHans de Goede rc4key[0] = Hi8(iv16); /* RC4KEY[0..2] is the WEP IV */
444554c0a3aSHans de Goede rc4key[1] = (Hi8(iv16) | 0x20) & 0x7F; /* Help avoid weak (FMS) keys */
445554c0a3aSHans de Goede rc4key[2] = Lo8(iv16);
446554c0a3aSHans de Goede rc4key[3] = Lo8((PPK[5] ^ TK16(0)) >> 1);
447554c0a3aSHans de Goede
448554c0a3aSHans de Goede
449554c0a3aSHans de Goede /* Copy 96 bits of PPK[0..5] to RC4KEY[4..15] (little-endian) */
450554c0a3aSHans de Goede for (i = 0; i < 6; i++) {
451554c0a3aSHans de Goede rc4key[4+2*i] = Lo8(PPK[i]);
452554c0a3aSHans de Goede rc4key[5+2*i] = Hi8(PPK[i]);
453554c0a3aSHans de Goede }
454554c0a3aSHans de Goede }
455554c0a3aSHans de Goede
456554c0a3aSHans de Goede
457554c0a3aSHans de Goede /* The hlen isn't include the IV */
rtw_tkip_encrypt(struct adapter * padapter,u8 * pxmitframe)458554c0a3aSHans de Goede u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe)
459554c0a3aSHans de Goede { /* exclude ICV */
460554c0a3aSHans de Goede u16 pnl;
461554c0a3aSHans de Goede u32 pnh;
462554c0a3aSHans de Goede u8 rc4key[16];
463554c0a3aSHans de Goede u8 ttkey[16];
464aef1c966SFabio M. De Francesco union {
465aef1c966SFabio M. De Francesco __le32 f0;
466aef1c966SFabio M. De Francesco u8 f1[4];
467aef1c966SFabio M. De Francesco } crc;
468554c0a3aSHans de Goede u8 hw_hdr_offset = 0;
469d495c550SMarco Cesati signed int curfragnum, length;
470554c0a3aSHans de Goede
471554c0a3aSHans de Goede u8 *pframe, *payload, *iv, *prwskey;
472554c0a3aSHans de Goede union pn48 dot11txpn;
473554c0a3aSHans de Goede struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib;
474554c0a3aSHans de Goede struct security_priv *psecuritypriv = &padapter->securitypriv;
475554c0a3aSHans de Goede struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
476a1b8a9bbSFabio Aiuto struct arc4_ctx *ctx = &psecuritypriv->xmit_arc4_ctx;
477554c0a3aSHans de Goede u32 res = _SUCCESS;
478554c0a3aSHans de Goede
479cd1f1450SMichael Straube if (!((struct xmit_frame *)pxmitframe)->buf_addr)
480554c0a3aSHans de Goede return _FAIL;
481554c0a3aSHans de Goede
482554c0a3aSHans de Goede hw_hdr_offset = TXDESC_OFFSET;
483554c0a3aSHans de Goede pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset;
484554c0a3aSHans de Goede
485554c0a3aSHans de Goede /* 4 start to encrypt each fragment */
486554c0a3aSHans de Goede if (pattrib->encrypt == _TKIP_) {
487554c0a3aSHans de Goede
488554c0a3aSHans de Goede {
489*be6cded3SRuan Jinjie if (is_multicast_ether_addr(pattrib->ra))
490554c0a3aSHans de Goede prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey;
491554c0a3aSHans de Goede else
492554c0a3aSHans de Goede prwskey = pattrib->dot118021x_UncstKey.skey;
493554c0a3aSHans de Goede
494554c0a3aSHans de Goede for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) {
495554c0a3aSHans de Goede iv = pframe+pattrib->hdrlen;
496554c0a3aSHans de Goede payload = pframe+pattrib->iv_len+pattrib->hdrlen;
497554c0a3aSHans de Goede
498554c0a3aSHans de Goede GET_TKIP_PN(iv, dot11txpn);
499554c0a3aSHans de Goede
500554c0a3aSHans de Goede pnl = (u16)(dot11txpn.val);
501554c0a3aSHans de Goede pnh = (u32)(dot11txpn.val>>16);
502554c0a3aSHans de Goede
503554c0a3aSHans de Goede phase1((u16 *)&ttkey[0], prwskey, &pattrib->ta[0], pnh);
504554c0a3aSHans de Goede
505554c0a3aSHans de Goede phase2(&rc4key[0], prwskey, (u16 *)&ttkey[0], pnl);
506554c0a3aSHans de Goede
507554c0a3aSHans de Goede if ((curfragnum+1) == pattrib->nr_frags) { /* 4 the last fragment */
508554c0a3aSHans de Goede length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
509aef1c966SFabio M. De Francesco crc.f0 = cpu_to_le32(~crc32_le(~0, payload, length));
510554c0a3aSHans de Goede
511a1b8a9bbSFabio Aiuto arc4_setkey(ctx, rc4key, 16);
512a1b8a9bbSFabio Aiuto arc4_crypt(ctx, payload, payload, length);
513aef1c966SFabio M. De Francesco arc4_crypt(ctx, payload + length, crc.f1, 4);
514554c0a3aSHans de Goede
515554c0a3aSHans de Goede } else {
516554c0a3aSHans de Goede length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
517aef1c966SFabio M. De Francesco crc.f0 = cpu_to_le32(~crc32_le(~0, payload, length));
5181f5adcfeSFabio Aiuto
519a1b8a9bbSFabio Aiuto arc4_setkey(ctx, rc4key, 16);
520a1b8a9bbSFabio Aiuto arc4_crypt(ctx, payload, payload, length);
521aef1c966SFabio M. De Francesco arc4_crypt(ctx, payload + length, crc.f1, 4);
522554c0a3aSHans de Goede
523554c0a3aSHans de Goede pframe += pxmitpriv->frag_len;
52487fe08d7SRoss Schmidt pframe = (u8 *)round_up((SIZE_PTR)(pframe), 4);
525554c0a3aSHans de Goede }
526554c0a3aSHans de Goede }
527554c0a3aSHans de Goede }
528554c0a3aSHans de Goede }
529554c0a3aSHans de Goede return res;
530554c0a3aSHans de Goede }
531554c0a3aSHans de Goede
532554c0a3aSHans de Goede
533554c0a3aSHans de Goede /* The hlen isn't include the IV */
rtw_tkip_decrypt(struct adapter * padapter,u8 * precvframe)534554c0a3aSHans de Goede u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe)
535554c0a3aSHans de Goede { /* exclude ICV */
536554c0a3aSHans de Goede u16 pnl;
537554c0a3aSHans de Goede u32 pnh;
538554c0a3aSHans de Goede u8 rc4key[16];
539554c0a3aSHans de Goede u8 ttkey[16];
540554c0a3aSHans de Goede u8 crc[4];
541d495c550SMarco Cesati signed int length;
542554c0a3aSHans de Goede
543554c0a3aSHans de Goede u8 *pframe, *payload, *iv, *prwskey;
544554c0a3aSHans de Goede union pn48 dot11txpn;
545554c0a3aSHans de Goede struct sta_info *stainfo;
546554c0a3aSHans de Goede struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib;
547554c0a3aSHans de Goede struct security_priv *psecuritypriv = &padapter->securitypriv;
548a1b8a9bbSFabio Aiuto struct arc4_ctx *ctx = &psecuritypriv->recv_arc4_ctx;
549554c0a3aSHans de Goede u32 res = _SUCCESS;
550554c0a3aSHans de Goede
551554c0a3aSHans de Goede pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
552554c0a3aSHans de Goede
553554c0a3aSHans de Goede /* 4 start to decrypt recvframe */
554554c0a3aSHans de Goede if (prxattrib->encrypt == _TKIP_) {
555554c0a3aSHans de Goede stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]);
55634557e23SIzabela Bakollari if (stainfo) {
557*be6cded3SRuan Jinjie if (is_multicast_ether_addr(prxattrib->ra)) {
55840d4aa0fSShreeya Patel static unsigned long start;
55940d4aa0fSShreeya Patel static u32 no_gkey_bc_cnt;
56040d4aa0fSShreeya Patel static u32 no_gkey_mc_cnt;
561554c0a3aSHans de Goede
5623ac5add1SJohn Oldman if (!psecuritypriv->binstallGrpkey) {
563554c0a3aSHans de Goede res = _FAIL;
564554c0a3aSHans de Goede
565554c0a3aSHans de Goede if (start == 0)
566554c0a3aSHans de Goede start = jiffies;
567554c0a3aSHans de Goede
568554c0a3aSHans de Goede if (is_broadcast_mac_addr(prxattrib->ra))
569554c0a3aSHans de Goede no_gkey_bc_cnt++;
570554c0a3aSHans de Goede else
571554c0a3aSHans de Goede no_gkey_mc_cnt++;
572554c0a3aSHans de Goede
573554c0a3aSHans de Goede if (jiffies_to_msecs(jiffies - start) > 1000) {
574554c0a3aSHans de Goede if (no_gkey_bc_cnt || no_gkey_mc_cnt) {
57579df841bSFabio Aiuto netdev_dbg(padapter->pnetdev,
57679df841bSFabio Aiuto FUNC_ADPT_FMT " no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n",
57779df841bSFabio Aiuto FUNC_ADPT_ARG(padapter),
57879df841bSFabio Aiuto no_gkey_bc_cnt,
57979df841bSFabio Aiuto no_gkey_mc_cnt);
580554c0a3aSHans de Goede }
581554c0a3aSHans de Goede start = jiffies;
582554c0a3aSHans de Goede no_gkey_bc_cnt = 0;
583554c0a3aSHans de Goede no_gkey_mc_cnt = 0;
584554c0a3aSHans de Goede }
585554c0a3aSHans de Goede goto exit;
586554c0a3aSHans de Goede }
587554c0a3aSHans de Goede
588554c0a3aSHans de Goede if (no_gkey_bc_cnt || no_gkey_mc_cnt) {
58979df841bSFabio Aiuto netdev_dbg(padapter->pnetdev,
59079df841bSFabio Aiuto FUNC_ADPT_FMT " gkey installed. no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n",
59179df841bSFabio Aiuto FUNC_ADPT_ARG(padapter),
59279df841bSFabio Aiuto no_gkey_bc_cnt,
59379df841bSFabio Aiuto no_gkey_mc_cnt);
594554c0a3aSHans de Goede }
595554c0a3aSHans de Goede start = 0;
596554c0a3aSHans de Goede no_gkey_bc_cnt = 0;
597554c0a3aSHans de Goede no_gkey_mc_cnt = 0;
598554c0a3aSHans de Goede
599554c0a3aSHans de Goede prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey;
600554c0a3aSHans de Goede } else {
601554c0a3aSHans de Goede prwskey = &stainfo->dot118021x_UncstKey.skey[0];
602554c0a3aSHans de Goede }
603554c0a3aSHans de Goede
604554c0a3aSHans de Goede iv = pframe+prxattrib->hdrlen;
605554c0a3aSHans de Goede payload = pframe+prxattrib->iv_len+prxattrib->hdrlen;
606554c0a3aSHans de Goede length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len;
607554c0a3aSHans de Goede
608554c0a3aSHans de Goede GET_TKIP_PN(iv, dot11txpn);
609554c0a3aSHans de Goede
610554c0a3aSHans de Goede pnl = (u16)(dot11txpn.val);
611554c0a3aSHans de Goede pnh = (u32)(dot11txpn.val>>16);
612554c0a3aSHans de Goede
613554c0a3aSHans de Goede phase1((u16 *)&ttkey[0], prwskey, &prxattrib->ta[0], pnh);
614554c0a3aSHans de Goede phase2(&rc4key[0], prwskey, (unsigned short *)&ttkey[0], pnl);
615554c0a3aSHans de Goede
616554c0a3aSHans de Goede /* 4 decrypt payload include icv */
617554c0a3aSHans de Goede
618a1b8a9bbSFabio Aiuto arc4_setkey(ctx, rc4key, 16);
619a1b8a9bbSFabio Aiuto arc4_crypt(ctx, payload, payload, length);
620554c0a3aSHans de Goede
621aef1c966SFabio M. De Francesco *((u32 *)crc) = ~crc32_le(~0, payload, length - 4);
622554c0a3aSHans de Goede
6230e1b6fe2SFabio Aiuto if (crc[3] != payload[length - 1] || crc[2] != payload[length - 2] ||
6240e1b6fe2SFabio Aiuto crc[1] != payload[length - 3] || crc[0] != payload[length - 4])
625554c0a3aSHans de Goede res = _FAIL;
626554c0a3aSHans de Goede } else {
627554c0a3aSHans de Goede res = _FAIL;
628554c0a3aSHans de Goede }
629554c0a3aSHans de Goede }
630554c0a3aSHans de Goede exit:
631554c0a3aSHans de Goede return res;
632554c0a3aSHans de Goede }
633554c0a3aSHans de Goede
634554c0a3aSHans de Goede
635554c0a3aSHans de Goede /* 3 =====AES related ===== */
636554c0a3aSHans de Goede
637554c0a3aSHans de Goede
638554c0a3aSHans de Goede
639554c0a3aSHans de Goede #define MAX_MSG_SIZE 2048
640554c0a3aSHans de Goede
641554c0a3aSHans de Goede /*****************************/
642554c0a3aSHans de Goede /**** Function Prototypes ****/
643554c0a3aSHans de Goede /*****************************/
644554c0a3aSHans de Goede
645554c0a3aSHans de Goede static void bitwise_xor(u8 *ina, u8 *inb, u8 *out);
6465641eeecSRoss Schmidt static void construct_mic_iv(u8 *mic_header1,
647d495c550SMarco Cesati signed int qc_exists,
648d495c550SMarco Cesati signed int a4_exists,
649554c0a3aSHans de Goede u8 *mpdu,
650554c0a3aSHans de Goede uint payload_length,
651554c0a3aSHans de Goede u8 *pn_vector,
6525641eeecSRoss Schmidt uint frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */
6535641eeecSRoss Schmidt static void construct_mic_header1(u8 *mic_header1,
654d495c550SMarco Cesati signed int header_length,
655554c0a3aSHans de Goede u8 *mpdu,
6565641eeecSRoss Schmidt uint frtype); /* for CONFIG_IEEE80211W, none 11w also can use */
6575641eeecSRoss Schmidt static void construct_mic_header2(u8 *mic_header2,
658554c0a3aSHans de Goede u8 *mpdu,
659d495c550SMarco Cesati signed int a4_exists,
660d495c550SMarco Cesati signed int qc_exists);
6615641eeecSRoss Schmidt static void construct_ctr_preload(u8 *ctr_preload,
662d495c550SMarco Cesati signed int a4_exists,
663d495c550SMarco Cesati signed int qc_exists,
664554c0a3aSHans de Goede u8 *mpdu,
665554c0a3aSHans de Goede u8 *pn_vector,
666d495c550SMarco Cesati signed int c,
6675641eeecSRoss Schmidt uint frtype); /* for CONFIG_IEEE80211W, none 11w also can use */
6683d3a170fSFabio Aiuto
669554c0a3aSHans de Goede static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext);
670554c0a3aSHans de Goede
671554c0a3aSHans de Goede
672554c0a3aSHans de Goede /****************************************/
673554c0a3aSHans de Goede /* aes128k128d() */
674554c0a3aSHans de Goede /* Performs a 128 bit AES encrypt with */
675554c0a3aSHans de Goede /* 128 bit data. */
676554c0a3aSHans de Goede /****************************************/
aes128k128d(u8 * key,u8 * data,u8 * ciphertext)677554c0a3aSHans de Goede static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext)
678554c0a3aSHans de Goede {
6793d3a170fSFabio Aiuto struct crypto_aes_ctx ctx;
680554c0a3aSHans de Goede
6813d3a170fSFabio Aiuto aes_expandkey(&ctx, key, 16);
6823d3a170fSFabio Aiuto aes_encrypt(&ctx, ciphertext, data);
6833d3a170fSFabio Aiuto memzero_explicit(&ctx, sizeof(ctx));
684554c0a3aSHans de Goede }
685554c0a3aSHans de Goede
686554c0a3aSHans de Goede /************************************************/
687554c0a3aSHans de Goede /* construct_mic_iv() */
688554c0a3aSHans de Goede /* Builds the MIC IV from header fields and PN */
689554c0a3aSHans de Goede /* Baron think the function is construct CCM */
690554c0a3aSHans de Goede /* nonce */
691554c0a3aSHans de Goede /************************************************/
construct_mic_iv(u8 * mic_iv,signed int qc_exists,signed int a4_exists,u8 * mpdu,uint payload_length,u8 * pn_vector,uint frtype)6925641eeecSRoss Schmidt static void construct_mic_iv(u8 *mic_iv,
693d495c550SMarco Cesati signed int qc_exists,
694d495c550SMarco Cesati signed int a4_exists,
695554c0a3aSHans de Goede u8 *mpdu,
696554c0a3aSHans de Goede uint payload_length,
697554c0a3aSHans de Goede u8 *pn_vector,
6985641eeecSRoss Schmidt uint frtype) /* add for CONFIG_IEEE80211W, none 11w also can use */
699554c0a3aSHans de Goede {
700d495c550SMarco Cesati signed int i;
701554c0a3aSHans de Goede
702554c0a3aSHans de Goede mic_iv[0] = 0x59;
703554c0a3aSHans de Goede
704554c0a3aSHans de Goede if (qc_exists && a4_exists)
705554c0a3aSHans de Goede mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */
706554c0a3aSHans de Goede
707554c0a3aSHans de Goede if (qc_exists && !a4_exists)
708554c0a3aSHans de Goede mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */
709554c0a3aSHans de Goede
710554c0a3aSHans de Goede if (!qc_exists)
711554c0a3aSHans de Goede mic_iv[1] = 0x00;
712554c0a3aSHans de Goede
713554c0a3aSHans de Goede /* 802.11w management frame should set management bit(4) */
714554c0a3aSHans de Goede if (frtype == WIFI_MGT_TYPE)
715554c0a3aSHans de Goede mic_iv[1] |= BIT(4);
716554c0a3aSHans de Goede
717554c0a3aSHans de Goede for (i = 2; i < 8; i++)
718554c0a3aSHans de Goede mic_iv[i] = mpdu[i + 8]; /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */
719554c0a3aSHans de Goede #ifdef CONSISTENT_PN_ORDER
720554c0a3aSHans de Goede for (i = 8; i < 14; i++)
721554c0a3aSHans de Goede mic_iv[i] = pn_vector[i - 8]; /* mic_iv[8:13] = PN[0:5] */
722554c0a3aSHans de Goede #else
723554c0a3aSHans de Goede for (i = 8; i < 14; i++)
724554c0a3aSHans de Goede mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */
725554c0a3aSHans de Goede #endif
726554c0a3aSHans de Goede mic_iv[14] = (unsigned char) (payload_length / 256);
727554c0a3aSHans de Goede mic_iv[15] = (unsigned char) (payload_length % 256);
728554c0a3aSHans de Goede }
729554c0a3aSHans de Goede
730554c0a3aSHans de Goede /************************************************/
731554c0a3aSHans de Goede /* construct_mic_header1() */
732554c0a3aSHans de Goede /* Builds the first MIC header block from */
733554c0a3aSHans de Goede /* header fields. */
734554c0a3aSHans de Goede /* Build AAD SC, A1, A2 */
735554c0a3aSHans de Goede /************************************************/
construct_mic_header1(u8 * mic_header1,signed int header_length,u8 * mpdu,uint frtype)7365641eeecSRoss Schmidt static void construct_mic_header1(u8 *mic_header1,
737d495c550SMarco Cesati signed int header_length,
738554c0a3aSHans de Goede u8 *mpdu,
7395641eeecSRoss Schmidt uint frtype) /* for CONFIG_IEEE80211W, none 11w also can use */
740554c0a3aSHans de Goede {
741554c0a3aSHans de Goede mic_header1[0] = (u8)((header_length - 2) / 256);
742554c0a3aSHans de Goede mic_header1[1] = (u8)((header_length - 2) % 256);
743554c0a3aSHans de Goede
744554c0a3aSHans de Goede /* 802.11w management frame don't AND subtype bits 4, 5, 6 of frame control field */
745554c0a3aSHans de Goede if (frtype == WIFI_MGT_TYPE)
746554c0a3aSHans de Goede mic_header1[2] = mpdu[0];
747554c0a3aSHans de Goede else
748554c0a3aSHans de Goede mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */
749554c0a3aSHans de Goede
750554c0a3aSHans de Goede mic_header1[3] = mpdu[1] & 0xc7; /* Mute retry, more data and pwr mgt bits */
751554c0a3aSHans de Goede mic_header1[4] = mpdu[4]; /* A1 */
752554c0a3aSHans de Goede mic_header1[5] = mpdu[5];
753554c0a3aSHans de Goede mic_header1[6] = mpdu[6];
754554c0a3aSHans de Goede mic_header1[7] = mpdu[7];
755554c0a3aSHans de Goede mic_header1[8] = mpdu[8];
756554c0a3aSHans de Goede mic_header1[9] = mpdu[9];
757554c0a3aSHans de Goede mic_header1[10] = mpdu[10]; /* A2 */
758554c0a3aSHans de Goede mic_header1[11] = mpdu[11];
759554c0a3aSHans de Goede mic_header1[12] = mpdu[12];
760554c0a3aSHans de Goede mic_header1[13] = mpdu[13];
761554c0a3aSHans de Goede mic_header1[14] = mpdu[14];
762554c0a3aSHans de Goede mic_header1[15] = mpdu[15];
763554c0a3aSHans de Goede }
764554c0a3aSHans de Goede
765554c0a3aSHans de Goede /************************************************/
766554c0a3aSHans de Goede /* construct_mic_header2() */
767554c0a3aSHans de Goede /* Builds the last MIC header block from */
768554c0a3aSHans de Goede /* header fields. */
769554c0a3aSHans de Goede /************************************************/
construct_mic_header2(u8 * mic_header2,u8 * mpdu,signed int a4_exists,signed int qc_exists)7705641eeecSRoss Schmidt static void construct_mic_header2(u8 *mic_header2,
771554c0a3aSHans de Goede u8 *mpdu,
772d495c550SMarco Cesati signed int a4_exists,
773d495c550SMarco Cesati signed int qc_exists)
774554c0a3aSHans de Goede {
775d495c550SMarco Cesati signed int i;
776554c0a3aSHans de Goede
777554c0a3aSHans de Goede for (i = 0; i < 16; i++)
778554c0a3aSHans de Goede mic_header2[i] = 0x00;
779554c0a3aSHans de Goede
780554c0a3aSHans de Goede mic_header2[0] = mpdu[16]; /* A3 */
781554c0a3aSHans de Goede mic_header2[1] = mpdu[17];
782554c0a3aSHans de Goede mic_header2[2] = mpdu[18];
783554c0a3aSHans de Goede mic_header2[3] = mpdu[19];
784554c0a3aSHans de Goede mic_header2[4] = mpdu[20];
785554c0a3aSHans de Goede mic_header2[5] = mpdu[21];
786554c0a3aSHans de Goede
787554c0a3aSHans de Goede mic_header2[6] = 0x00;
788554c0a3aSHans de Goede mic_header2[7] = 0x00; /* mpdu[23]; */
789554c0a3aSHans de Goede
790554c0a3aSHans de Goede if (!qc_exists && a4_exists) {
791554c0a3aSHans de Goede for (i = 0; i < 6; i++)
792554c0a3aSHans de Goede mic_header2[8+i] = mpdu[24+i]; /* A4 */
793554c0a3aSHans de Goede }
794554c0a3aSHans de Goede
795554c0a3aSHans de Goede if (qc_exists && !a4_exists) {
796554c0a3aSHans de Goede mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */
797554c0a3aSHans de Goede mic_header2[9] = mpdu[25] & 0x00;
798554c0a3aSHans de Goede }
799554c0a3aSHans de Goede
800554c0a3aSHans de Goede if (qc_exists && a4_exists) {
801554c0a3aSHans de Goede for (i = 0; i < 6; i++)
802554c0a3aSHans de Goede mic_header2[8+i] = mpdu[24+i]; /* A4 */
803554c0a3aSHans de Goede
804554c0a3aSHans de Goede mic_header2[14] = mpdu[30] & 0x0f;
805554c0a3aSHans de Goede mic_header2[15] = mpdu[31] & 0x00;
806554c0a3aSHans de Goede }
807554c0a3aSHans de Goede }
808554c0a3aSHans de Goede
809554c0a3aSHans de Goede /************************************************/
810554c0a3aSHans de Goede /* construct_mic_header2() */
811554c0a3aSHans de Goede /* Builds the last MIC header block from */
812554c0a3aSHans de Goede /* header fields. */
813554c0a3aSHans de Goede /* Baron think the function is construct CCM */
814554c0a3aSHans de Goede /* nonce */
815554c0a3aSHans de Goede /************************************************/
construct_ctr_preload(u8 * ctr_preload,signed int a4_exists,signed int qc_exists,u8 * mpdu,u8 * pn_vector,signed int c,uint frtype)8165641eeecSRoss Schmidt static void construct_ctr_preload(u8 *ctr_preload,
817d495c550SMarco Cesati signed int a4_exists,
818d495c550SMarco Cesati signed int qc_exists,
819554c0a3aSHans de Goede u8 *mpdu,
820554c0a3aSHans de Goede u8 *pn_vector,
821d495c550SMarco Cesati signed int c,
8225641eeecSRoss Schmidt uint frtype) /* for CONFIG_IEEE80211W, none 11w also can use */
823554c0a3aSHans de Goede {
824d495c550SMarco Cesati signed int i = 0;
825554c0a3aSHans de Goede
826554c0a3aSHans de Goede for (i = 0; i < 16; i++)
827554c0a3aSHans de Goede ctr_preload[i] = 0x00;
828554c0a3aSHans de Goede i = 0;
829554c0a3aSHans de Goede
830554c0a3aSHans de Goede ctr_preload[0] = 0x01; /* flag */
831554c0a3aSHans de Goede if (qc_exists && a4_exists)
832554c0a3aSHans de Goede ctr_preload[1] = mpdu[30] & 0x0f; /* QoC_Control */
833554c0a3aSHans de Goede if (qc_exists && !a4_exists)
834554c0a3aSHans de Goede ctr_preload[1] = mpdu[24] & 0x0f;
835554c0a3aSHans de Goede
836554c0a3aSHans de Goede /* 802.11w management frame should set management bit(4) */
837554c0a3aSHans de Goede if (frtype == WIFI_MGT_TYPE)
838554c0a3aSHans de Goede ctr_preload[1] |= BIT(4);
839554c0a3aSHans de Goede
840554c0a3aSHans de Goede for (i = 2; i < 8; i++)
841554c0a3aSHans de Goede ctr_preload[i] = mpdu[i + 8]; /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */
842554c0a3aSHans de Goede #ifdef CONSISTENT_PN_ORDER
843554c0a3aSHans de Goede for (i = 8; i < 14; i++)
844554c0a3aSHans de Goede ctr_preload[i] = pn_vector[i - 8]; /* ctr_preload[8:13] = PN[0:5] */
845554c0a3aSHans de Goede #else
846554c0a3aSHans de Goede for (i = 8; i < 14; i++)
847554c0a3aSHans de Goede ctr_preload[i] = pn_vector[13 - i]; /* ctr_preload[8:13] = PN[5:0] */
848554c0a3aSHans de Goede #endif
849554c0a3aSHans de Goede ctr_preload[14] = (unsigned char) (c / 256); /* Ctr */
850554c0a3aSHans de Goede ctr_preload[15] = (unsigned char) (c % 256);
851554c0a3aSHans de Goede }
852554c0a3aSHans de Goede
853554c0a3aSHans de Goede /************************************/
854554c0a3aSHans de Goede /* bitwise_xor() */
855554c0a3aSHans de Goede /* A 128 bit, bitwise exclusive or */
856554c0a3aSHans de Goede /************************************/
bitwise_xor(u8 * ina,u8 * inb,u8 * out)857554c0a3aSHans de Goede static void bitwise_xor(u8 *ina, u8 *inb, u8 *out)
858554c0a3aSHans de Goede {
859d495c550SMarco Cesati signed int i;
860554c0a3aSHans de Goede
861df94d3b2SBrother Matthew De Angelis for (i = 0; i < 16; i++)
862554c0a3aSHans de Goede out[i] = ina[i] ^ inb[i];
863554c0a3aSHans de Goede }
864554c0a3aSHans de Goede
aes_cipher(u8 * key,uint hdrlen,u8 * pframe,uint plen)865d495c550SMarco Cesati static signed int aes_cipher(u8 *key, uint hdrlen,
866554c0a3aSHans de Goede u8 *pframe, uint plen)
867554c0a3aSHans de Goede {
868554c0a3aSHans de Goede uint qc_exists, a4_exists, i, j, payload_remainder,
869554c0a3aSHans de Goede num_blocks, payload_index;
870554c0a3aSHans de Goede
871554c0a3aSHans de Goede u8 pn_vector[6];
872554c0a3aSHans de Goede u8 mic_iv[16];
873554c0a3aSHans de Goede u8 mic_header1[16];
874554c0a3aSHans de Goede u8 mic_header2[16];
875554c0a3aSHans de Goede u8 ctr_preload[16];
876554c0a3aSHans de Goede
877554c0a3aSHans de Goede /* Intermediate Buffers */
878554c0a3aSHans de Goede u8 chain_buffer[16];
879554c0a3aSHans de Goede u8 aes_out[16];
880554c0a3aSHans de Goede u8 padded_buffer[16];
881554c0a3aSHans de Goede u8 mic[8];
882554c0a3aSHans de Goede uint frtype = GetFrameType(pframe);
883554c0a3aSHans de Goede uint frsubtype = GetFrameSubType(pframe);
884554c0a3aSHans de Goede
885554c0a3aSHans de Goede frsubtype = frsubtype>>4;
886554c0a3aSHans de Goede
887554c0a3aSHans de Goede memset((void *)mic_iv, 0, 16);
888554c0a3aSHans de Goede memset((void *)mic_header1, 0, 16);
889554c0a3aSHans de Goede memset((void *)mic_header2, 0, 16);
890554c0a3aSHans de Goede memset((void *)ctr_preload, 0, 16);
891554c0a3aSHans de Goede memset((void *)chain_buffer, 0, 16);
892554c0a3aSHans de Goede memset((void *)aes_out, 0, 16);
893554c0a3aSHans de Goede memset((void *)padded_buffer, 0, 16);
894554c0a3aSHans de Goede
895554c0a3aSHans de Goede if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN))
896554c0a3aSHans de Goede a4_exists = 0;
897554c0a3aSHans de Goede else
898554c0a3aSHans de Goede a4_exists = 1;
899554c0a3aSHans de Goede
9000ba8d4b9SLarry Finger if (((frtype|frsubtype) == WIFI_DATA_CFACK) ||
901554c0a3aSHans de Goede ((frtype|frsubtype) == WIFI_DATA_CFPOLL) ||
902554c0a3aSHans de Goede ((frtype|frsubtype) == WIFI_DATA_CFACKPOLL)) {
903554c0a3aSHans de Goede qc_exists = 1;
904554c0a3aSHans de Goede if (hdrlen != WLAN_HDR_A3_QOS_LEN)
905554c0a3aSHans de Goede hdrlen += 2;
906554c0a3aSHans de Goede
907554c0a3aSHans de Goede } else if ((frtype == WIFI_DATA) && /* add for CONFIG_IEEE80211W, none 11w also can use */
908554c0a3aSHans de Goede ((frsubtype == 0x08) ||
909554c0a3aSHans de Goede (frsubtype == 0x09) ||
910554c0a3aSHans de Goede (frsubtype == 0x0a) ||
911554c0a3aSHans de Goede (frsubtype == 0x0b))) {
912554c0a3aSHans de Goede if (hdrlen != WLAN_HDR_A3_QOS_LEN)
913554c0a3aSHans de Goede hdrlen += 2;
914554c0a3aSHans de Goede
915554c0a3aSHans de Goede qc_exists = 1;
91670466c39SRoss Schmidt } else {
917554c0a3aSHans de Goede qc_exists = 0;
91870466c39SRoss Schmidt }
919554c0a3aSHans de Goede
920554c0a3aSHans de Goede pn_vector[0] = pframe[hdrlen];
921554c0a3aSHans de Goede pn_vector[1] = pframe[hdrlen+1];
922554c0a3aSHans de Goede pn_vector[2] = pframe[hdrlen+4];
923554c0a3aSHans de Goede pn_vector[3] = pframe[hdrlen+5];
924554c0a3aSHans de Goede pn_vector[4] = pframe[hdrlen+6];
925554c0a3aSHans de Goede pn_vector[5] = pframe[hdrlen+7];
926554c0a3aSHans de Goede
9275641eeecSRoss Schmidt construct_mic_iv(mic_iv,
928554c0a3aSHans de Goede qc_exists,
929554c0a3aSHans de Goede a4_exists,
930554c0a3aSHans de Goede pframe, /* message, */
931554c0a3aSHans de Goede plen,
932554c0a3aSHans de Goede pn_vector,
9335641eeecSRoss Schmidt frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */
934554c0a3aSHans de Goede
9355641eeecSRoss Schmidt construct_mic_header1(mic_header1,
936554c0a3aSHans de Goede hdrlen,
937554c0a3aSHans de Goede pframe, /* message */
9385641eeecSRoss Schmidt frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */
9395641eeecSRoss Schmidt
9405641eeecSRoss Schmidt construct_mic_header2(mic_header2,
941554c0a3aSHans de Goede pframe, /* message, */
942554c0a3aSHans de Goede a4_exists,
9435641eeecSRoss Schmidt qc_exists);
944554c0a3aSHans de Goede
945554c0a3aSHans de Goede payload_remainder = plen % 16;
946554c0a3aSHans de Goede num_blocks = plen / 16;
947554c0a3aSHans de Goede
948554c0a3aSHans de Goede /* Find start of payload */
949554c0a3aSHans de Goede payload_index = (hdrlen + 8);
950554c0a3aSHans de Goede
951554c0a3aSHans de Goede /* Calculate MIC */
952554c0a3aSHans de Goede aes128k128d(key, mic_iv, aes_out);
953554c0a3aSHans de Goede bitwise_xor(aes_out, mic_header1, chain_buffer);
954554c0a3aSHans de Goede aes128k128d(key, chain_buffer, aes_out);
955554c0a3aSHans de Goede bitwise_xor(aes_out, mic_header2, chain_buffer);
956554c0a3aSHans de Goede aes128k128d(key, chain_buffer, aes_out);
957554c0a3aSHans de Goede
958554c0a3aSHans de Goede for (i = 0; i < num_blocks; i++) {
95922b5cbd1SJavier F. Arias bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);
960554c0a3aSHans de Goede
961554c0a3aSHans de Goede payload_index += 16;
962554c0a3aSHans de Goede aes128k128d(key, chain_buffer, aes_out);
963554c0a3aSHans de Goede }
964554c0a3aSHans de Goede
965554c0a3aSHans de Goede /* Add on the final payload block if it needs padding */
966554c0a3aSHans de Goede if (payload_remainder > 0) {
967554c0a3aSHans de Goede for (j = 0; j < 16; j++)
968554c0a3aSHans de Goede padded_buffer[j] = 0x00;
96970466c39SRoss Schmidt for (j = 0; j < payload_remainder; j++)
97022b5cbd1SJavier F. Arias padded_buffer[j] = pframe[payload_index++];
97170466c39SRoss Schmidt
972554c0a3aSHans de Goede bitwise_xor(aes_out, padded_buffer, chain_buffer);
973554c0a3aSHans de Goede aes128k128d(key, chain_buffer, aes_out);
974554c0a3aSHans de Goede }
975554c0a3aSHans de Goede
976554c0a3aSHans de Goede for (j = 0 ; j < 8; j++)
977554c0a3aSHans de Goede mic[j] = aes_out[j];
978554c0a3aSHans de Goede
979554c0a3aSHans de Goede /* Insert MIC into payload */
980554c0a3aSHans de Goede for (j = 0; j < 8; j++)
98122b5cbd1SJavier F. Arias pframe[payload_index+j] = mic[j];
982554c0a3aSHans de Goede
983554c0a3aSHans de Goede payload_index = hdrlen + 8;
984554c0a3aSHans de Goede for (i = 0; i < num_blocks; i++) {
9855641eeecSRoss Schmidt construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, /* message, */
9865641eeecSRoss Schmidt pn_vector, i+1, frtype);
9875641eeecSRoss Schmidt /* add for CONFIG_IEEE80211W, none 11w also can use */
988554c0a3aSHans de Goede aes128k128d(key, ctr_preload, aes_out);
98922b5cbd1SJavier F. Arias bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);
990554c0a3aSHans de Goede for (j = 0; j < 16; j++)
99122b5cbd1SJavier F. Arias pframe[payload_index++] = chain_buffer[j];
992554c0a3aSHans de Goede }
993554c0a3aSHans de Goede
994554c0a3aSHans de Goede if (payload_remainder > 0) {
995554c0a3aSHans de Goede /* If there is a short final block, then pad it,*/
996554c0a3aSHans de Goede /* encrypt it and copy the unpadded part back */
9975641eeecSRoss Schmidt construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, /* message, */
9985641eeecSRoss Schmidt pn_vector, num_blocks+1, frtype);
9995641eeecSRoss Schmidt /* add for CONFIG_IEEE80211W, none 11w also can use */
1000554c0a3aSHans de Goede
1001554c0a3aSHans de Goede for (j = 0; j < 16; j++)
1002554c0a3aSHans de Goede padded_buffer[j] = 0x00;
10030ba8d4b9SLarry Finger for (j = 0; j < payload_remainder; j++)
100422b5cbd1SJavier F. Arias padded_buffer[j] = pframe[payload_index+j];
10050ba8d4b9SLarry Finger
1006554c0a3aSHans de Goede aes128k128d(key, ctr_preload, aes_out);
1007554c0a3aSHans de Goede bitwise_xor(aes_out, padded_buffer, chain_buffer);
1008554c0a3aSHans de Goede for (j = 0; j < payload_remainder; j++)
100922b5cbd1SJavier F. Arias pframe[payload_index++] = chain_buffer[j];
1010554c0a3aSHans de Goede }
1011554c0a3aSHans de Goede
1012554c0a3aSHans de Goede /* Encrypt the MIC */
10135641eeecSRoss Schmidt construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, /* message, */
10145641eeecSRoss Schmidt pn_vector, 0, frtype);
10155641eeecSRoss Schmidt /* add for CONFIG_IEEE80211W, none 11w also can use */
1016554c0a3aSHans de Goede
1017554c0a3aSHans de Goede for (j = 0; j < 16; j++)
1018554c0a3aSHans de Goede padded_buffer[j] = 0x00;
10190ba8d4b9SLarry Finger for (j = 0; j < 8; j++)
102022b5cbd1SJavier F. Arias padded_buffer[j] = pframe[j+hdrlen+8+plen];
1021554c0a3aSHans de Goede
1022554c0a3aSHans de Goede aes128k128d(key, ctr_preload, aes_out);
1023554c0a3aSHans de Goede bitwise_xor(aes_out, padded_buffer, chain_buffer);
1024554c0a3aSHans de Goede for (j = 0; j < 8; j++)
102522b5cbd1SJavier F. Arias pframe[payload_index++] = chain_buffer[j];
1026554c0a3aSHans de Goede
1027554c0a3aSHans de Goede return _SUCCESS;
1028554c0a3aSHans de Goede }
1029554c0a3aSHans de Goede
rtw_aes_encrypt(struct adapter * padapter,u8 * pxmitframe)1030554c0a3aSHans de Goede u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe)
1031554c0a3aSHans de Goede { /* exclude ICV */
1032554c0a3aSHans de Goede
1033554c0a3aSHans de Goede /*static*/
1034554c0a3aSHans de Goede /* unsigned char message[MAX_MSG_SIZE]; */
1035554c0a3aSHans de Goede
1036554c0a3aSHans de Goede /* Intermediate Buffers */
1037d495c550SMarco Cesati signed int curfragnum, length;
1038554c0a3aSHans de Goede u8 *pframe, *prwskey; /* *payload,*iv */
1039554c0a3aSHans de Goede u8 hw_hdr_offset = 0;
1040554c0a3aSHans de Goede struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib;
1041554c0a3aSHans de Goede struct security_priv *psecuritypriv = &padapter->securitypriv;
1042554c0a3aSHans de Goede struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
1043554c0a3aSHans de Goede
1044554c0a3aSHans de Goede u32 res = _SUCCESS;
1045554c0a3aSHans de Goede
1046cd1f1450SMichael Straube if (!((struct xmit_frame *)pxmitframe)->buf_addr)
1047554c0a3aSHans de Goede return _FAIL;
1048554c0a3aSHans de Goede
1049554c0a3aSHans de Goede hw_hdr_offset = TXDESC_OFFSET;
1050554c0a3aSHans de Goede pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset;
1051554c0a3aSHans de Goede
1052554c0a3aSHans de Goede /* 4 start to encrypt each fragment */
105307523ee1SColin Ian King if (pattrib->encrypt == _AES_) {
1054*be6cded3SRuan Jinjie if (is_multicast_ether_addr(pattrib->ra))
1055554c0a3aSHans de Goede prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey;
1056554c0a3aSHans de Goede else
1057554c0a3aSHans de Goede prwskey = pattrib->dot118021x_UncstKey.skey;
1058554c0a3aSHans de Goede
1059554c0a3aSHans de Goede for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) {
1060554c0a3aSHans de Goede if ((curfragnum+1) == pattrib->nr_frags) { /* 4 the last fragment */
1061554c0a3aSHans de Goede length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
1062554c0a3aSHans de Goede
1063554c0a3aSHans de Goede aes_cipher(prwskey, pattrib->hdrlen, pframe, length);
1064554c0a3aSHans de Goede } else {
1065554c0a3aSHans de Goede length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
1066554c0a3aSHans de Goede
1067554c0a3aSHans de Goede aes_cipher(prwskey, pattrib->hdrlen, pframe, length);
1068554c0a3aSHans de Goede pframe += pxmitpriv->frag_len;
106987fe08d7SRoss Schmidt pframe = (u8 *)round_up((SIZE_PTR)(pframe), 4);
1070554c0a3aSHans de Goede }
1071554c0a3aSHans de Goede }
1072554c0a3aSHans de Goede }
1073554c0a3aSHans de Goede return res;
1074554c0a3aSHans de Goede }
1075554c0a3aSHans de Goede
aes_decipher(u8 * key,uint hdrlen,u8 * pframe,uint plen)1076d495c550SMarco Cesati static signed int aes_decipher(u8 *key, uint hdrlen,
1077554c0a3aSHans de Goede u8 *pframe, uint plen)
1078554c0a3aSHans de Goede {
1079554c0a3aSHans de Goede static u8 message[MAX_MSG_SIZE];
1080554c0a3aSHans de Goede uint qc_exists, a4_exists, i, j, payload_remainder,
1081554c0a3aSHans de Goede num_blocks, payload_index;
1082d495c550SMarco Cesati signed int res = _SUCCESS;
1083554c0a3aSHans de Goede u8 pn_vector[6];
1084554c0a3aSHans de Goede u8 mic_iv[16];
1085554c0a3aSHans de Goede u8 mic_header1[16];
1086554c0a3aSHans de Goede u8 mic_header2[16];
1087554c0a3aSHans de Goede u8 ctr_preload[16];
1088554c0a3aSHans de Goede
1089554c0a3aSHans de Goede /* Intermediate Buffers */
1090554c0a3aSHans de Goede u8 chain_buffer[16];
1091554c0a3aSHans de Goede u8 aes_out[16];
1092554c0a3aSHans de Goede u8 padded_buffer[16];
1093554c0a3aSHans de Goede u8 mic[8];
1094554c0a3aSHans de Goede
1095554c0a3aSHans de Goede uint frtype = GetFrameType(pframe);
1096554c0a3aSHans de Goede uint frsubtype = GetFrameSubType(pframe);
1097554c0a3aSHans de Goede
1098554c0a3aSHans de Goede frsubtype = frsubtype>>4;
1099554c0a3aSHans de Goede
1100554c0a3aSHans de Goede memset((void *)mic_iv, 0, 16);
1101554c0a3aSHans de Goede memset((void *)mic_header1, 0, 16);
1102554c0a3aSHans de Goede memset((void *)mic_header2, 0, 16);
1103554c0a3aSHans de Goede memset((void *)ctr_preload, 0, 16);
1104554c0a3aSHans de Goede memset((void *)chain_buffer, 0, 16);
1105554c0a3aSHans de Goede memset((void *)aes_out, 0, 16);
1106554c0a3aSHans de Goede memset((void *)padded_buffer, 0, 16);
1107554c0a3aSHans de Goede
1108554c0a3aSHans de Goede /* start to decrypt the payload */
1109554c0a3aSHans de Goede
1110554c0a3aSHans de Goede num_blocks = (plen-8) / 16; /* plen including LLC, payload_length and mic) */
1111554c0a3aSHans de Goede
1112554c0a3aSHans de Goede payload_remainder = (plen-8) % 16;
1113554c0a3aSHans de Goede
1114554c0a3aSHans de Goede pn_vector[0] = pframe[hdrlen];
1115554c0a3aSHans de Goede pn_vector[1] = pframe[hdrlen + 1];
1116554c0a3aSHans de Goede pn_vector[2] = pframe[hdrlen + 4];
1117554c0a3aSHans de Goede pn_vector[3] = pframe[hdrlen + 5];
1118554c0a3aSHans de Goede pn_vector[4] = pframe[hdrlen + 6];
1119554c0a3aSHans de Goede pn_vector[5] = pframe[hdrlen + 7];
1120554c0a3aSHans de Goede
1121554c0a3aSHans de Goede if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN))
1122554c0a3aSHans de Goede a4_exists = 0;
1123554c0a3aSHans de Goede else
1124554c0a3aSHans de Goede a4_exists = 1;
1125554c0a3aSHans de Goede
11260ba8d4b9SLarry Finger if (((frtype|frsubtype) == WIFI_DATA_CFACK) ||
1127554c0a3aSHans de Goede ((frtype|frsubtype) == WIFI_DATA_CFPOLL) ||
1128554c0a3aSHans de Goede ((frtype|frsubtype) == WIFI_DATA_CFACKPOLL)) {
1129554c0a3aSHans de Goede qc_exists = 1;
113070466c39SRoss Schmidt if (hdrlen != WLAN_HDR_A3_QOS_LEN)
1131554c0a3aSHans de Goede hdrlen += 2;
113270466c39SRoss Schmidt
1133554c0a3aSHans de Goede } else if ((frtype == WIFI_DATA) && /* only for data packet . add for CONFIG_IEEE80211W, none 11w also can use */
1134554c0a3aSHans de Goede ((frsubtype == 0x08) ||
1135554c0a3aSHans de Goede (frsubtype == 0x09) ||
1136554c0a3aSHans de Goede (frsubtype == 0x0a) ||
1137554c0a3aSHans de Goede (frsubtype == 0x0b))) {
113870466c39SRoss Schmidt if (hdrlen != WLAN_HDR_A3_QOS_LEN)
1139554c0a3aSHans de Goede hdrlen += 2;
114070466c39SRoss Schmidt
1141554c0a3aSHans de Goede qc_exists = 1;
114270466c39SRoss Schmidt } else {
1143554c0a3aSHans de Goede qc_exists = 0;
114470466c39SRoss Schmidt }
1145554c0a3aSHans de Goede
1146554c0a3aSHans de Goede /* now, decrypt pframe with hdrlen offset and plen long */
1147554c0a3aSHans de Goede
1148554c0a3aSHans de Goede payload_index = hdrlen + 8; /* 8 is for extiv */
1149554c0a3aSHans de Goede
1150554c0a3aSHans de Goede for (i = 0; i < num_blocks; i++) {
1151e004d7acSJavier F. Arias construct_ctr_preload(ctr_preload, a4_exists,
1152e004d7acSJavier F. Arias qc_exists, pframe,
1153e004d7acSJavier F. Arias pn_vector, i + 1,
1154e004d7acSJavier F. Arias frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */
1155554c0a3aSHans de Goede
1156554c0a3aSHans de Goede aes128k128d(key, ctr_preload, aes_out);
1157554c0a3aSHans de Goede bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);
1158554c0a3aSHans de Goede
1159554c0a3aSHans de Goede for (j = 0; j < 16; j++)
1160554c0a3aSHans de Goede pframe[payload_index++] = chain_buffer[j];
1161554c0a3aSHans de Goede }
1162554c0a3aSHans de Goede
1163554c0a3aSHans de Goede if (payload_remainder > 0) {
1164554c0a3aSHans de Goede /* If there is a short final block, then pad it,*/
1165554c0a3aSHans de Goede /* encrypt it and copy the unpadded part back */
11665641eeecSRoss Schmidt construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector,
11675641eeecSRoss Schmidt num_blocks+1, frtype);
11685641eeecSRoss Schmidt /* add for CONFIG_IEEE80211W, none 11w also can use */
1169554c0a3aSHans de Goede
1170554c0a3aSHans de Goede for (j = 0; j < 16; j++)
1171554c0a3aSHans de Goede padded_buffer[j] = 0x00;
117270466c39SRoss Schmidt for (j = 0; j < payload_remainder; j++)
1173554c0a3aSHans de Goede padded_buffer[j] = pframe[payload_index+j];
117470466c39SRoss Schmidt
1175554c0a3aSHans de Goede aes128k128d(key, ctr_preload, aes_out);
1176554c0a3aSHans de Goede bitwise_xor(aes_out, padded_buffer, chain_buffer);
1177554c0a3aSHans de Goede for (j = 0; j < payload_remainder; j++)
1178554c0a3aSHans de Goede pframe[payload_index++] = chain_buffer[j];
1179554c0a3aSHans de Goede }
1180554c0a3aSHans de Goede
1181554c0a3aSHans de Goede /* start to calculate the mic */
1182554c0a3aSHans de Goede if ((hdrlen + plen+8) <= MAX_MSG_SIZE)
1183554c0a3aSHans de Goede memcpy((void *)message, pframe, (hdrlen + plen+8)); /* 8 is for ext iv len */
1184554c0a3aSHans de Goede
1185554c0a3aSHans de Goede pn_vector[0] = pframe[hdrlen];
1186554c0a3aSHans de Goede pn_vector[1] = pframe[hdrlen+1];
1187554c0a3aSHans de Goede pn_vector[2] = pframe[hdrlen+4];
1188554c0a3aSHans de Goede pn_vector[3] = pframe[hdrlen+5];
1189554c0a3aSHans de Goede pn_vector[4] = pframe[hdrlen+6];
1190554c0a3aSHans de Goede pn_vector[5] = pframe[hdrlen+7];
1191554c0a3aSHans de Goede
11925641eeecSRoss Schmidt construct_mic_iv(mic_iv, qc_exists, a4_exists, message, plen-8, pn_vector, frtype);
11935641eeecSRoss Schmidt /* add for CONFIG_IEEE80211W, none 11w also can use */
1194554c0a3aSHans de Goede
11955641eeecSRoss Schmidt construct_mic_header1(mic_header1, hdrlen, message, frtype);
11965641eeecSRoss Schmidt /* add for CONFIG_IEEE80211W, none 11w also can use */
11975641eeecSRoss Schmidt construct_mic_header2(mic_header2, message, a4_exists, qc_exists);
1198554c0a3aSHans de Goede
1199554c0a3aSHans de Goede payload_remainder = (plen-8) % 16;
1200554c0a3aSHans de Goede num_blocks = (plen-8) / 16;
1201554c0a3aSHans de Goede
1202554c0a3aSHans de Goede /* Find start of payload */
1203554c0a3aSHans de Goede payload_index = (hdrlen + 8);
1204554c0a3aSHans de Goede
1205554c0a3aSHans de Goede /* Calculate MIC */
1206554c0a3aSHans de Goede aes128k128d(key, mic_iv, aes_out);
1207554c0a3aSHans de Goede bitwise_xor(aes_out, mic_header1, chain_buffer);
1208554c0a3aSHans de Goede aes128k128d(key, chain_buffer, aes_out);
1209554c0a3aSHans de Goede bitwise_xor(aes_out, mic_header2, chain_buffer);
1210554c0a3aSHans de Goede aes128k128d(key, chain_buffer, aes_out);
1211554c0a3aSHans de Goede
1212554c0a3aSHans de Goede for (i = 0; i < num_blocks; i++) {
1213554c0a3aSHans de Goede bitwise_xor(aes_out, &message[payload_index], chain_buffer);
1214554c0a3aSHans de Goede
1215554c0a3aSHans de Goede payload_index += 16;
1216554c0a3aSHans de Goede aes128k128d(key, chain_buffer, aes_out);
1217554c0a3aSHans de Goede }
1218554c0a3aSHans de Goede
1219554c0a3aSHans de Goede /* Add on the final payload block if it needs padding */
1220554c0a3aSHans de Goede if (payload_remainder > 0) {
1221554c0a3aSHans de Goede for (j = 0; j < 16; j++)
1222554c0a3aSHans de Goede padded_buffer[j] = 0x00;
122370466c39SRoss Schmidt for (j = 0; j < payload_remainder; j++)
1224554c0a3aSHans de Goede padded_buffer[j] = message[payload_index++];
122570466c39SRoss Schmidt
1226554c0a3aSHans de Goede bitwise_xor(aes_out, padded_buffer, chain_buffer);
1227554c0a3aSHans de Goede aes128k128d(key, chain_buffer, aes_out);
1228554c0a3aSHans de Goede }
1229554c0a3aSHans de Goede
1230554c0a3aSHans de Goede for (j = 0; j < 8; j++)
1231554c0a3aSHans de Goede mic[j] = aes_out[j];
1232554c0a3aSHans de Goede
1233554c0a3aSHans de Goede /* Insert MIC into payload */
1234554c0a3aSHans de Goede for (j = 0; j < 8; j++)
1235554c0a3aSHans de Goede message[payload_index+j] = mic[j];
1236554c0a3aSHans de Goede
1237554c0a3aSHans de Goede payload_index = hdrlen + 8;
1238554c0a3aSHans de Goede for (i = 0; i < num_blocks; i++) {
12395641eeecSRoss Schmidt construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, i+1,
12405641eeecSRoss Schmidt frtype);
12415641eeecSRoss Schmidt /* add for CONFIG_IEEE80211W, none 11w also can use */
1242554c0a3aSHans de Goede aes128k128d(key, ctr_preload, aes_out);
1243554c0a3aSHans de Goede bitwise_xor(aes_out, &message[payload_index], chain_buffer);
1244554c0a3aSHans de Goede for (j = 0; j < 16; j++)
1245554c0a3aSHans de Goede message[payload_index++] = chain_buffer[j];
1246554c0a3aSHans de Goede }
1247554c0a3aSHans de Goede
1248554c0a3aSHans de Goede if (payload_remainder > 0) {
1249554c0a3aSHans de Goede /* If there is a short final block, then pad it,*/
1250554c0a3aSHans de Goede /* encrypt it and copy the unpadded part back */
12515641eeecSRoss Schmidt construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector,
12525641eeecSRoss Schmidt num_blocks+1, frtype);
12535641eeecSRoss Schmidt /* add for CONFIG_IEEE80211W, none 11w also can use */
1254554c0a3aSHans de Goede
1255554c0a3aSHans de Goede for (j = 0; j < 16; j++)
1256554c0a3aSHans de Goede padded_buffer[j] = 0x00;
125770466c39SRoss Schmidt for (j = 0; j < payload_remainder; j++)
1258554c0a3aSHans de Goede padded_buffer[j] = message[payload_index+j];
125970466c39SRoss Schmidt
1260554c0a3aSHans de Goede aes128k128d(key, ctr_preload, aes_out);
1261554c0a3aSHans de Goede bitwise_xor(aes_out, padded_buffer, chain_buffer);
1262554c0a3aSHans de Goede for (j = 0; j < payload_remainder; j++)
1263554c0a3aSHans de Goede message[payload_index++] = chain_buffer[j];
1264554c0a3aSHans de Goede }
1265554c0a3aSHans de Goede
1266554c0a3aSHans de Goede /* Encrypt the MIC */
12675641eeecSRoss Schmidt construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, 0, frtype);
12685641eeecSRoss Schmidt /* add for CONFIG_IEEE80211W, none 11w also can use */
1269554c0a3aSHans de Goede
1270554c0a3aSHans de Goede for (j = 0; j < 16; j++)
1271554c0a3aSHans de Goede padded_buffer[j] = 0x00;
127270466c39SRoss Schmidt for (j = 0; j < 8; j++)
1273554c0a3aSHans de Goede padded_buffer[j] = message[j+hdrlen+8+plen-8];
1274554c0a3aSHans de Goede
1275554c0a3aSHans de Goede aes128k128d(key, ctr_preload, aes_out);
1276554c0a3aSHans de Goede bitwise_xor(aes_out, padded_buffer, chain_buffer);
1277554c0a3aSHans de Goede for (j = 0; j < 8; j++)
1278554c0a3aSHans de Goede message[payload_index++] = chain_buffer[j];
1279554c0a3aSHans de Goede
1280554c0a3aSHans de Goede /* compare the mic */
1281554c0a3aSHans de Goede for (i = 0; i < 8; i++) {
1282709c8e49SFabio Aiuto if (pframe[hdrlen + 8 + plen - 8 + i] != message[hdrlen + 8 + plen - 8 + i])
1283554c0a3aSHans de Goede res = _FAIL;
1284554c0a3aSHans de Goede }
1285554c0a3aSHans de Goede return res;
1286554c0a3aSHans de Goede }
1287554c0a3aSHans de Goede
rtw_aes_decrypt(struct adapter * padapter,u8 * precvframe)1288554c0a3aSHans de Goede u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe)
1289554c0a3aSHans de Goede { /* exclude ICV */
1290554c0a3aSHans de Goede
1291554c0a3aSHans de Goede /*static*/
1292554c0a3aSHans de Goede /* unsigned char message[MAX_MSG_SIZE]; */
1293554c0a3aSHans de Goede
1294554c0a3aSHans de Goede /* Intermediate Buffers */
1295554c0a3aSHans de Goede
1296d495c550SMarco Cesati signed int length;
1297554c0a3aSHans de Goede u8 *pframe, *prwskey; /* *payload,*iv */
1298554c0a3aSHans de Goede struct sta_info *stainfo;
1299554c0a3aSHans de Goede struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib;
1300554c0a3aSHans de Goede struct security_priv *psecuritypriv = &padapter->securitypriv;
1301554c0a3aSHans de Goede u32 res = _SUCCESS;
1302554c0a3aSHans de Goede
1303554c0a3aSHans de Goede pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
1304554c0a3aSHans de Goede /* 4 start to encrypt each fragment */
130507523ee1SColin Ian King if (prxattrib->encrypt == _AES_) {
1306554c0a3aSHans de Goede stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]);
130734557e23SIzabela Bakollari if (stainfo) {
1308*be6cded3SRuan Jinjie if (is_multicast_ether_addr(prxattrib->ra)) {
130940d4aa0fSShreeya Patel static unsigned long start;
131040d4aa0fSShreeya Patel static u32 no_gkey_bc_cnt;
131140d4aa0fSShreeya Patel static u32 no_gkey_mc_cnt;
1312554c0a3aSHans de Goede
13133ac5add1SJohn Oldman if (!psecuritypriv->binstallGrpkey) {
1314554c0a3aSHans de Goede res = _FAIL;
1315554c0a3aSHans de Goede
1316554c0a3aSHans de Goede if (start == 0)
1317554c0a3aSHans de Goede start = jiffies;
1318554c0a3aSHans de Goede
1319554c0a3aSHans de Goede if (is_broadcast_mac_addr(prxattrib->ra))
1320554c0a3aSHans de Goede no_gkey_bc_cnt++;
1321554c0a3aSHans de Goede else
1322554c0a3aSHans de Goede no_gkey_mc_cnt++;
1323554c0a3aSHans de Goede
1324554c0a3aSHans de Goede if (jiffies_to_msecs(jiffies - start) > 1000) {
1325554c0a3aSHans de Goede if (no_gkey_bc_cnt || no_gkey_mc_cnt) {
132679df841bSFabio Aiuto netdev_dbg(padapter->pnetdev,
132779df841bSFabio Aiuto FUNC_ADPT_FMT " no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n",
132879df841bSFabio Aiuto FUNC_ADPT_ARG(padapter),
132979df841bSFabio Aiuto no_gkey_bc_cnt,
133079df841bSFabio Aiuto no_gkey_mc_cnt);
1331554c0a3aSHans de Goede }
1332554c0a3aSHans de Goede start = jiffies;
1333554c0a3aSHans de Goede no_gkey_bc_cnt = 0;
1334554c0a3aSHans de Goede no_gkey_mc_cnt = 0;
1335554c0a3aSHans de Goede }
1336554c0a3aSHans de Goede
1337554c0a3aSHans de Goede goto exit;
1338554c0a3aSHans de Goede }
1339554c0a3aSHans de Goede
1340554c0a3aSHans de Goede if (no_gkey_bc_cnt || no_gkey_mc_cnt) {
134179df841bSFabio Aiuto netdev_dbg(padapter->pnetdev,
134279df841bSFabio Aiuto FUNC_ADPT_FMT " gkey installed. no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n",
134379df841bSFabio Aiuto FUNC_ADPT_ARG(padapter),
134479df841bSFabio Aiuto no_gkey_bc_cnt,
134579df841bSFabio Aiuto no_gkey_mc_cnt);
1346554c0a3aSHans de Goede }
1347554c0a3aSHans de Goede start = 0;
1348554c0a3aSHans de Goede no_gkey_bc_cnt = 0;
1349554c0a3aSHans de Goede no_gkey_mc_cnt = 0;
1350554c0a3aSHans de Goede
1351554c0a3aSHans de Goede prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey;
1352554c0a3aSHans de Goede if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) {
1353554c0a3aSHans de Goede res = _FAIL;
1354554c0a3aSHans de Goede goto exit;
1355554c0a3aSHans de Goede }
135670466c39SRoss Schmidt } else {
1357554c0a3aSHans de Goede prwskey = &stainfo->dot118021x_UncstKey.skey[0];
135870466c39SRoss Schmidt }
1359554c0a3aSHans de Goede
1360554c0a3aSHans de Goede length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len;
1361554c0a3aSHans de Goede
1362554c0a3aSHans de Goede res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length);
1363554c0a3aSHans de Goede
1364554c0a3aSHans de Goede } else {
1365554c0a3aSHans de Goede res = _FAIL;
1366554c0a3aSHans de Goede }
1367554c0a3aSHans de Goede }
1368554c0a3aSHans de Goede exit:
1369554c0a3aSHans de Goede return res;
1370554c0a3aSHans de Goede }
1371554c0a3aSHans de Goede
rtw_BIP_verify(struct adapter * padapter,u8 * precvframe)1372554c0a3aSHans de Goede u32 rtw_BIP_verify(struct adapter *padapter, u8 *precvframe)
1373554c0a3aSHans de Goede {
1374554c0a3aSHans de Goede struct rx_pkt_attrib *pattrib = &((union recv_frame *)precvframe)->u.hdr.attrib;
1375554c0a3aSHans de Goede u8 *pframe;
1376554c0a3aSHans de Goede u8 *BIP_AAD, *p;
1377554c0a3aSHans de Goede u32 res = _FAIL;
1378554c0a3aSHans de Goede uint len, ori_len;
1379554c0a3aSHans de Goede struct ieee80211_hdr *pwlanhdr;
1380554c0a3aSHans de Goede u8 mic[16];
1381554c0a3aSHans de Goede struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
1382554c0a3aSHans de Goede __le16 le_tmp;
1383554c0a3aSHans de Goede __le64 le_tmp64;
1384554c0a3aSHans de Goede
1385554c0a3aSHans de Goede ori_len = pattrib->pkt_len-WLAN_HDR_A3_LEN+BIP_AAD_SIZE;
1386554c0a3aSHans de Goede BIP_AAD = rtw_zmalloc(ori_len);
1387554c0a3aSHans de Goede
1388e427bdd8SFabio Aiuto if (!BIP_AAD)
1389554c0a3aSHans de Goede return _FAIL;
1390709c8e49SFabio Aiuto
1391554c0a3aSHans de Goede /* PKT start */
1392554c0a3aSHans de Goede pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
1393554c0a3aSHans de Goede /* mapping to wlan header */
1394554c0a3aSHans de Goede pwlanhdr = (struct ieee80211_hdr *)pframe;
1395554c0a3aSHans de Goede /* save the frame body + MME */
1396554c0a3aSHans de Goede memcpy(BIP_AAD+BIP_AAD_SIZE, pframe+WLAN_HDR_A3_LEN, pattrib->pkt_len-WLAN_HDR_A3_LEN);
1397554c0a3aSHans de Goede /* find MME IE pointer */
139899bb7769SRoss Schmidt p = rtw_get_ie(BIP_AAD+BIP_AAD_SIZE, WLAN_EID_MMIE, &len, pattrib->pkt_len-WLAN_HDR_A3_LEN);
1399554c0a3aSHans de Goede /* Baron */
1400554c0a3aSHans de Goede if (p) {
1401554c0a3aSHans de Goede u16 keyid = 0;
1402554c0a3aSHans de Goede u64 temp_ipn = 0;
1403554c0a3aSHans de Goede /* save packet number */
1404554c0a3aSHans de Goede memcpy(&le_tmp64, p+4, 6);
1405554c0a3aSHans de Goede temp_ipn = le64_to_cpu(le_tmp64);
1406554c0a3aSHans de Goede /* BIP packet number should bigger than previous BIP packet */
1407709c8e49SFabio Aiuto if (temp_ipn <= pmlmeext->mgnt_80211w_IPN_rx)
1408554c0a3aSHans de Goede goto BIP_exit;
1409709c8e49SFabio Aiuto
1410554c0a3aSHans de Goede /* copy key index */
1411554c0a3aSHans de Goede memcpy(&le_tmp, p+2, 2);
1412554c0a3aSHans de Goede keyid = le16_to_cpu(le_tmp);
1413709c8e49SFabio Aiuto if (keyid != padapter->securitypriv.dot11wBIPKeyid)
1414554c0a3aSHans de Goede goto BIP_exit;
1415709c8e49SFabio Aiuto
1416554c0a3aSHans de Goede /* clear the MIC field of MME to zero */
1417554c0a3aSHans de Goede memset(p+2+len-8, 0, 8);
1418554c0a3aSHans de Goede
1419554c0a3aSHans de Goede /* conscruct AAD, copy frame control field */
1420554c0a3aSHans de Goede memcpy(BIP_AAD, &pwlanhdr->frame_control, 2);
1421554c0a3aSHans de Goede ClearRetry(BIP_AAD);
1422554c0a3aSHans de Goede ClearPwrMgt(BIP_AAD);
1423554c0a3aSHans de Goede ClearMData(BIP_AAD);
1424554c0a3aSHans de Goede /* conscruct AAD, copy address 1 to address 3 */
1425554c0a3aSHans de Goede memcpy(BIP_AAD+2, pwlanhdr->addr1, 18);
1426554c0a3aSHans de Goede
1427554c0a3aSHans de Goede if (omac1_aes_128(padapter->securitypriv.dot11wBIPKey[padapter->securitypriv.dot11wBIPKeyid].skey
1428554c0a3aSHans de Goede , BIP_AAD, ori_len, mic))
1429554c0a3aSHans de Goede goto BIP_exit;
1430554c0a3aSHans de Goede
1431554c0a3aSHans de Goede /* MIC field should be last 8 bytes of packet (packet without FCS) */
1432554c0a3aSHans de Goede if (!memcmp(mic, pframe+pattrib->pkt_len-8, 8)) {
1433554c0a3aSHans de Goede pmlmeext->mgnt_80211w_IPN_rx = temp_ipn;
1434554c0a3aSHans de Goede res = _SUCCESS;
143570466c39SRoss Schmidt } else {
143670466c39SRoss Schmidt }
1437554c0a3aSHans de Goede
143870466c39SRoss Schmidt } else {
1439554c0a3aSHans de Goede res = RTW_RX_HANDLED;
144070466c39SRoss Schmidt }
1441554c0a3aSHans de Goede BIP_exit:
1442554c0a3aSHans de Goede
1443554c0a3aSHans de Goede kfree(BIP_AAD);
1444554c0a3aSHans de Goede return res;
1445554c0a3aSHans de Goede }
1446554c0a3aSHans de Goede
gf_mulx(u8 * pad)1447554c0a3aSHans de Goede static void gf_mulx(u8 *pad)
1448554c0a3aSHans de Goede {
1449554c0a3aSHans de Goede int i, carry;
1450554c0a3aSHans de Goede
1451554c0a3aSHans de Goede carry = pad[0] & 0x80;
1452554c0a3aSHans de Goede for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
1453554c0a3aSHans de Goede pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
1454554c0a3aSHans de Goede
1455554c0a3aSHans de Goede pad[AES_BLOCK_SIZE - 1] <<= 1;
1456554c0a3aSHans de Goede if (carry)
1457554c0a3aSHans de Goede pad[AES_BLOCK_SIZE - 1] ^= 0x87;
1458554c0a3aSHans de Goede }
1459554c0a3aSHans de Goede
1460554c0a3aSHans de Goede /**
1461554c0a3aSHans de Goede * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
1462554c0a3aSHans de Goede * @key: 128-bit key for the hash operation
1463554c0a3aSHans de Goede * @num_elem: Number of elements in the data vector
1464554c0a3aSHans de Goede * @addr: Pointers to the data areas
1465554c0a3aSHans de Goede * @len: Lengths of the data blocks
1466554c0a3aSHans de Goede * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
1467554c0a3aSHans de Goede * Returns: 0 on success, -1 on failure
1468554c0a3aSHans de Goede *
1469554c0a3aSHans de Goede * This is a mode for using block cipher (AES in this case) for authentication.
1470554c0a3aSHans de Goede * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
1471554c0a3aSHans de Goede * (SP) 800-38B.
1472554c0a3aSHans de Goede */
omac1_aes_128_vector(u8 * key,size_t num_elem,u8 * addr[],size_t * len,u8 * mac)1473554c0a3aSHans de Goede static int omac1_aes_128_vector(u8 *key, size_t num_elem,
1474554c0a3aSHans de Goede u8 *addr[], size_t *len, u8 *mac)
1475554c0a3aSHans de Goede {
14767d40753dSFabio Aiuto struct crypto_aes_ctx ctx;
1477554c0a3aSHans de Goede u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
1478554c0a3aSHans de Goede u8 *pos, *end;
1479554c0a3aSHans de Goede size_t i, e, left, total_len;
14807d40753dSFabio Aiuto int ret;
1481554c0a3aSHans de Goede
14827d40753dSFabio Aiuto ret = aes_expandkey(&ctx, key, 16);
14837d40753dSFabio Aiuto if (ret)
1484554c0a3aSHans de Goede return -1;
1485554c0a3aSHans de Goede memset(cbc, 0, AES_BLOCK_SIZE);
1486554c0a3aSHans de Goede
1487554c0a3aSHans de Goede total_len = 0;
1488554c0a3aSHans de Goede for (e = 0; e < num_elem; e++)
1489554c0a3aSHans de Goede total_len += len[e];
1490554c0a3aSHans de Goede left = total_len;
1491554c0a3aSHans de Goede
1492554c0a3aSHans de Goede e = 0;
1493554c0a3aSHans de Goede pos = addr[0];
1494554c0a3aSHans de Goede end = pos + len[0];
1495554c0a3aSHans de Goede
1496554c0a3aSHans de Goede while (left >= AES_BLOCK_SIZE) {
1497554c0a3aSHans de Goede for (i = 0; i < AES_BLOCK_SIZE; i++) {
1498554c0a3aSHans de Goede cbc[i] ^= *pos++;
1499554c0a3aSHans de Goede if (pos >= end) {
1500554c0a3aSHans de Goede e++;
1501554c0a3aSHans de Goede pos = addr[e];
1502554c0a3aSHans de Goede end = pos + len[e];
1503554c0a3aSHans de Goede }
1504554c0a3aSHans de Goede }
1505554c0a3aSHans de Goede if (left > AES_BLOCK_SIZE)
15067d40753dSFabio Aiuto aes_encrypt(&ctx, cbc, cbc);
1507554c0a3aSHans de Goede left -= AES_BLOCK_SIZE;
1508554c0a3aSHans de Goede }
1509554c0a3aSHans de Goede
1510554c0a3aSHans de Goede memset(pad, 0, AES_BLOCK_SIZE);
15117d40753dSFabio Aiuto aes_encrypt(&ctx, pad, pad);
1512554c0a3aSHans de Goede gf_mulx(pad);
1513554c0a3aSHans de Goede
1514554c0a3aSHans de Goede if (left || total_len == 0) {
1515554c0a3aSHans de Goede for (i = 0; i < left; i++) {
1516554c0a3aSHans de Goede cbc[i] ^= *pos++;
1517554c0a3aSHans de Goede if (pos >= end) {
1518554c0a3aSHans de Goede e++;
1519554c0a3aSHans de Goede pos = addr[e];
1520554c0a3aSHans de Goede end = pos + len[e];
1521554c0a3aSHans de Goede }
1522554c0a3aSHans de Goede }
1523554c0a3aSHans de Goede cbc[left] ^= 0x80;
1524554c0a3aSHans de Goede gf_mulx(pad);
1525554c0a3aSHans de Goede }
1526554c0a3aSHans de Goede
1527554c0a3aSHans de Goede for (i = 0; i < AES_BLOCK_SIZE; i++)
1528554c0a3aSHans de Goede pad[i] ^= cbc[i];
15297d40753dSFabio Aiuto aes_encrypt(&ctx, pad, mac);
15307d40753dSFabio Aiuto memzero_explicit(&ctx, sizeof(ctx));
1531554c0a3aSHans de Goede return 0;
1532554c0a3aSHans de Goede }
1533554c0a3aSHans de Goede
1534554c0a3aSHans de Goede /**
1535554c0a3aSHans de Goede * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
1536554c0a3aSHans de Goede * @key: 128-bit key for the hash operation
1537554c0a3aSHans de Goede * @data: Data buffer for which a MAC is determined
1538554c0a3aSHans de Goede * @data_len: Length of data buffer in bytes
1539554c0a3aSHans de Goede * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
1540554c0a3aSHans de Goede * Returns: 0 on success, -1 on failure
1541554c0a3aSHans de Goede *
1542554c0a3aSHans de Goede * This is a mode for using block cipher (AES in this case) for authentication.
1543554c0a3aSHans de Goede * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
1544554c0a3aSHans de Goede * (SP) 800-38B.
1545554c0a3aSHans de Goede * modify for CONFIG_IEEE80211W */
omac1_aes_128(u8 * key,u8 * data,size_t data_len,u8 * mac)1546554c0a3aSHans de Goede int omac1_aes_128(u8 *key, u8 *data, size_t data_len, u8 *mac)
1547554c0a3aSHans de Goede {
1548554c0a3aSHans de Goede return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
1549554c0a3aSHans de Goede }
1550554c0a3aSHans de Goede
1551554c0a3aSHans de Goede /* Restore HW wep key setting according to key_mask */
rtw_sec_restore_wep_key(struct adapter * adapter)1552554c0a3aSHans de Goede void rtw_sec_restore_wep_key(struct adapter *adapter)
1553554c0a3aSHans de Goede {
1554554c0a3aSHans de Goede struct security_priv *securitypriv = &(adapter->securitypriv);
1555d495c550SMarco Cesati signed int keyid;
1556554c0a3aSHans de Goede
1557554c0a3aSHans de Goede if ((_WEP40_ == securitypriv->dot11PrivacyAlgrthm) || (_WEP104_ == securitypriv->dot11PrivacyAlgrthm)) {
1558554c0a3aSHans de Goede for (keyid = 0; keyid < 4; keyid++) {
1559554c0a3aSHans de Goede if (securitypriv->key_mask & BIT(keyid)) {
1560554c0a3aSHans de Goede if (keyid == securitypriv->dot11PrivacyKeyIndex)
1561554c0a3aSHans de Goede rtw_set_key(adapter, securitypriv, keyid, 1, false);
1562554c0a3aSHans de Goede else
1563554c0a3aSHans de Goede rtw_set_key(adapter, securitypriv, keyid, 0, false);
1564554c0a3aSHans de Goede }
1565554c0a3aSHans de Goede }
1566554c0a3aSHans de Goede }
1567554c0a3aSHans de Goede }
1568554c0a3aSHans de Goede
rtw_handle_tkip_countermeasure(struct adapter * adapter,const char * caller)1569554c0a3aSHans de Goede u8 rtw_handle_tkip_countermeasure(struct adapter *adapter, const char *caller)
1570554c0a3aSHans de Goede {
1571554c0a3aSHans de Goede struct security_priv *securitypriv = &(adapter->securitypriv);
1572554c0a3aSHans de Goede u8 status = _SUCCESS;
1573554c0a3aSHans de Goede
15743ac5add1SJohn Oldman if (securitypriv->btkip_countermeasure) {
1575554c0a3aSHans de Goede unsigned long passing_ms = jiffies_to_msecs(jiffies - securitypriv->btkip_countermeasure_time);
157622045712SRoss Schmidt
1577554c0a3aSHans de Goede if (passing_ms > 60*1000) {
157879df841bSFabio Aiuto netdev_dbg(adapter->pnetdev,
157979df841bSFabio Aiuto "%s(%s) countermeasure time:%lus > 60s\n",
158079df841bSFabio Aiuto caller, ADPT_ARG(adapter),
158179df841bSFabio Aiuto passing_ms / 1000);
1582554c0a3aSHans de Goede securitypriv->btkip_countermeasure = false;
1583554c0a3aSHans de Goede securitypriv->btkip_countermeasure_time = 0;
1584554c0a3aSHans de Goede } else {
158579df841bSFabio Aiuto netdev_dbg(adapter->pnetdev,
158679df841bSFabio Aiuto "%s(%s) countermeasure time:%lus < 60s\n",
158779df841bSFabio Aiuto caller, ADPT_ARG(adapter),
158879df841bSFabio Aiuto passing_ms / 1000);
1589554c0a3aSHans de Goede status = _FAIL;
1590554c0a3aSHans de Goede }
1591554c0a3aSHans de Goede }
1592554c0a3aSHans de Goede
1593554c0a3aSHans de Goede return status;
1594554c0a3aSHans de Goede }
1595