Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/net80211/ieee80211_crypto_gcm.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2012, Jouni Malinen <[email protected]>
5
* All rights reserved.
6
*
7
* Galois/Counter Mode (GCM) and GMAC with AES
8
*
9
* Originally sourced from hostapd 2.11 (src/crypto/aes-gcm.c).
10
*
11
* Redistribution and use in source and binary forms, with or without
12
* modification, are permitted provided that the following conditions
13
* are met:
14
* 1. Redistributions of source code must retain the above copyright
15
* notice, this list of conditions and the following disclaimer.
16
* 2. Redistributions in binary form must reproduce the above copyright
17
* notice, this list of conditions and the following disclaimer in the
18
* documentation and/or other materials provided with the distribution.
19
*
20
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
*/
31
32
#include "opt_wlan.h"
33
34
#include <sys/param.h>
35
#include <sys/systm.h>
36
#include <sys/kernel.h>
37
38
#include <crypto/rijndael/rijndael.h>
39
#include <net80211/ieee80211_crypto_gcm.h>
40
41
#define AES_BLOCK_LEN 16
42
43
#define BIT(x) (1U << (x))
44
45
static __inline void
46
xor_block(uint8_t *b, const uint8_t *a, size_t len)
47
{
48
int i;
49
for (i = 0; i < len; i++)
50
b[i] ^= a[i];
51
}
52
53
static inline
54
void WPA_PUT_BE64(uint8_t *a, uint64_t val)
55
{
56
a[0] = val >> 56;
57
a[1] = val >> 48;
58
a[2] = val >> 40;
59
a[3] = val >> 32;
60
a[4] = val >> 24;
61
a[5] = val >> 16;
62
a[6] = val >> 8;
63
a[7] = val & 0xff;
64
}
65
66
static inline void
67
WPA_PUT_BE32(uint8_t *a, uint32_t val)
68
{
69
a[0] = (val >> 24) & 0xff;
70
a[1] = (val >> 16) & 0xff;
71
a[2] = (val >> 8) & 0xff;
72
a[3] = val & 0xff;
73
}
74
75
static inline uint32_t
76
WPA_GET_BE32(const uint8_t *a)
77
{
78
return (((uint32_t) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]);
79
}
80
81
static void
82
inc32(uint8_t *block)
83
{
84
uint32_t val;
85
86
val = WPA_GET_BE32(block + AES_BLOCK_LEN - 4);
87
val++;
88
WPA_PUT_BE32(block + AES_BLOCK_LEN - 4, val);
89
}
90
91
static void
92
shift_right_block(uint8_t *v)
93
{
94
uint32_t val;
95
96
val = WPA_GET_BE32(v + 12);
97
val >>= 1;
98
if (v[11] & 0x01)
99
val |= 0x80000000;
100
WPA_PUT_BE32(v + 12, val);
101
102
val = WPA_GET_BE32(v + 8);
103
val >>= 1;
104
if (v[7] & 0x01)
105
val |= 0x80000000;
106
WPA_PUT_BE32(v + 8, val);
107
108
val = WPA_GET_BE32(v + 4);
109
val >>= 1;
110
if (v[3] & 0x01)
111
val |= 0x80000000;
112
WPA_PUT_BE32(v + 4, val);
113
114
val = WPA_GET_BE32(v);
115
val >>= 1;
116
WPA_PUT_BE32(v, val);
117
}
118
119
120
/* Multiplication in GF(2^128) */
121
static void
122
gf_mult(const uint8_t *x, const uint8_t *y, uint8_t *z)
123
{
124
uint8_t v[16];
125
int i, j;
126
127
memset(z, 0, 16); /* Z_0 = 0^128 */
128
memcpy(v, y, 16); /* V_0 = Y */
129
130
for (i = 0; i < 16; i++) {
131
for (j = 0; j < 8; j++) {
132
if (x[i] & BIT(7 - j)) {
133
/* Z_(i + 1) = Z_i XOR V_i */
134
xor_block(z, v, AES_BLOCK_LEN);
135
} else {
136
/* Z_(i + 1) = Z_i */
137
}
138
139
if (v[15] & 0x01) {
140
/* V_(i + 1) = (V_i >> 1) XOR R */
141
shift_right_block(v);
142
/* R = 11100001 || 0^120 */
143
v[0] ^= 0xe1;
144
} else {
145
/* V_(i + 1) = V_i >> 1 */
146
shift_right_block(v);
147
}
148
}
149
}
150
}
151
152
static void
153
ghash_start(uint8_t *y)
154
{
155
/* Y_0 = 0^128 */
156
memset(y, 0, 16);
157
}
158
159
static void
160
ghash(const uint8_t *h, const uint8_t *x, size_t xlen, uint8_t *y)
161
{
162
size_t m, i;
163
const uint8_t *xpos = x;
164
uint8_t tmp[16];
165
166
m = xlen / 16;
167
168
for (i = 0; i < m; i++) {
169
/* Y_i = (Y^(i-1) XOR X_i) dot H */
170
xor_block(y, xpos, AES_BLOCK_LEN);
171
xpos += 16;
172
173
/* dot operation:
174
* multiplication operation for binary Galois (finite) field of
175
* 2^128 elements */
176
gf_mult(y, h, tmp);
177
memcpy(y, tmp, 16);
178
}
179
180
if (x + xlen > xpos) {
181
/* Add zero padded last block */
182
size_t last = x + xlen - xpos;
183
memcpy(tmp, xpos, last);
184
memset(tmp + last, 0, sizeof(tmp) - last);
185
186
/* Y_i = (Y^(i-1) XOR X_i) dot H */
187
xor_block(y, tmp, AES_BLOCK_LEN);
188
189
/* dot operation:
190
* multiplication operation for binary Galois (finite) field of
191
* 2^128 elements */
192
gf_mult(y, h, tmp);
193
memcpy(y, tmp, 16);
194
}
195
196
/* Return Y_m */
197
}
198
199
/*
200
* Execute the GCTR call with the counter block icb
201
* on payload x (size len), output into y.
202
*/
203
static void
204
aes_gctr(rijndael_ctx *aes, const uint8_t *icb,
205
const uint8_t *x, size_t xlen, uint8_t *y)
206
{
207
size_t i, n, last;
208
uint8_t cb[AES_BLOCK_LEN], tmp[AES_BLOCK_LEN];
209
const uint8_t *xpos = x;
210
uint8_t *ypos = y;
211
212
if (xlen == 0)
213
return;
214
215
n = xlen / 16;
216
217
memcpy(cb, icb, AES_BLOCK_LEN);
218
219
/* Full blocks */
220
for (i = 0; i < n; i++) {
221
rijndael_encrypt(aes, cb, ypos);
222
xor_block(ypos, xpos, AES_BLOCK_LEN);
223
xpos += AES_BLOCK_LEN;
224
ypos += AES_BLOCK_LEN;
225
inc32(cb);
226
}
227
228
last = x + xlen - xpos;
229
if (last) {
230
/* Last, partial block */
231
rijndael_encrypt(aes, cb, tmp);
232
for (i = 0; i < last; i++)
233
*ypos++ = *xpos++ ^ tmp[i];
234
}
235
}
236
237
static void
238
aes_gcm_init_hash_subkey(rijndael_ctx *aes, uint8_t *H)
239
{
240
/* Generate hash subkey H = AES_K(0^128) */
241
memset(H, 0, AES_BLOCK_LEN);
242
243
rijndael_encrypt(aes, H, H);
244
}
245
246
static void
247
aes_gcm_prepare_j0(const uint8_t *iv, size_t iv_len, const uint8_t *H,
248
uint8_t *J0)
249
{
250
uint8_t len_buf[16];
251
252
if (iv_len == 12) {
253
/* Prepare block J_0 = IV || 0^31 || 1 [len(IV) = 96] */
254
memcpy(J0, iv, iv_len);
255
memset(J0 + iv_len, 0, AES_BLOCK_LEN - iv_len);
256
J0[AES_BLOCK_LEN - 1] = 0x01;
257
} else {
258
/*
259
* s = 128 * ceil(len(IV)/128) - len(IV)
260
* J_0 = GHASH_H(IV || 0^(s+64) || [len(IV)]_64)
261
*/
262
ghash_start(J0);
263
ghash(H, iv, iv_len, J0);
264
WPA_PUT_BE64(len_buf, 0);
265
WPA_PUT_BE64(len_buf + 8, iv_len * 8);
266
ghash(H, len_buf, sizeof(len_buf), J0);
267
}
268
}
269
270
static void
271
aes_gcm_gctr(rijndael_ctx *aes, const uint8_t *J0, const uint8_t *in,
272
size_t len, uint8_t *out)
273
{
274
uint8_t J0inc[AES_BLOCK_LEN];
275
276
if (len == 0)
277
return;
278
279
memcpy(J0inc, J0, AES_BLOCK_LEN);
280
inc32(J0inc);
281
282
aes_gctr(aes, J0inc, in, len, out);
283
}
284
285
static void
286
aes_gcm_ghash(const uint8_t *H, const uint8_t *aad, size_t aad_len,
287
const uint8_t *crypt, size_t crypt_len, uint8_t *S)
288
{
289
uint8_t len_buf[16];
290
291
/*
292
* u = 128 * ceil[len(C)/128] - len(C)
293
* v = 128 * ceil[len(A)/128] - len(A)
294
* S = GHASH_H(A || 0^v || C || 0^u || [len(A)]64 || [len(C)]64)
295
* (i.e., zero padded to block size A || C and lengths of each in bits)
296
*/
297
ghash_start(S);
298
ghash(H, aad, aad_len, S);
299
ghash(H, crypt, crypt_len, S);
300
WPA_PUT_BE64(len_buf, aad_len * 8);
301
WPA_PUT_BE64(len_buf + 8, crypt_len * 8);
302
ghash(H, len_buf, sizeof(len_buf), S);
303
}
304
305
/**
306
* aes_gcm_ae - GCM-AE_K(IV, P, A)
307
*/
308
void
309
ieee80211_crypto_aes_gcm_ae(rijndael_ctx *aes, const uint8_t *iv, size_t iv_len,
310
const uint8_t *plain, size_t plain_len,
311
const uint8_t *aad, size_t aad_len, uint8_t *crypt, uint8_t *tag)
312
{
313
uint8_t H[AES_BLOCK_LEN];
314
uint8_t J0[AES_BLOCK_LEN];
315
uint8_t S[GCMP_MIC_LEN];
316
317
aes_gcm_init_hash_subkey(aes, H);
318
319
aes_gcm_prepare_j0(iv, iv_len, H, J0);
320
321
/* C = GCTR_K(inc_32(J_0), P) */
322
aes_gcm_gctr(aes, J0, plain, plain_len, crypt);
323
324
aes_gcm_ghash(H, aad, aad_len, crypt, plain_len, S);
325
326
/* T = MSB_t(GCTR_K(J_0, S)) */
327
aes_gctr(aes, J0, S, sizeof(S), tag);
328
329
/* Return (C, T) */
330
}
331
332
/**
333
* aes_gcm_ad - GCM-AD_K(IV, C, A, T)
334
*
335
* Return 0 if OK, -1 if decrypt failure.
336
*/
337
int
338
ieee80211_crypto_aes_gcm_ad(rijndael_ctx *aes, const uint8_t *iv, size_t iv_len,
339
const uint8_t *crypt, size_t crypt_len,
340
const uint8_t *aad, size_t aad_len, const uint8_t *tag, uint8_t *plain)
341
{
342
uint8_t H[AES_BLOCK_LEN];
343
uint8_t J0[AES_BLOCK_LEN];
344
uint8_t S[16], T[GCMP_MIC_LEN];
345
346
aes_gcm_init_hash_subkey(aes, H);
347
348
aes_gcm_prepare_j0(iv, iv_len, H, J0);
349
350
/* P = GCTR_K(inc_32(J_0), C) */
351
aes_gcm_gctr(aes, J0, crypt, crypt_len, plain);
352
353
aes_gcm_ghash(H, aad, aad_len, crypt, crypt_len, S);
354
355
/* T' = MSB_t(GCTR_K(J_0, S)) */
356
aes_gctr(aes, J0, S, sizeof(S), T);
357
358
if (memcmp(tag, T, 16) != 0) {
359
return (-1);
360
}
361
362
return (0);
363
}
364
365