1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * Galois/Counter Mode (GCM) and GMAC with AES
3e5b75505Sopenharmony_ci *
4e5b75505Sopenharmony_ci * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
5e5b75505Sopenharmony_ci *
6e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
7e5b75505Sopenharmony_ci * See README for more details.
8e5b75505Sopenharmony_ci */
9e5b75505Sopenharmony_ci
10e5b75505Sopenharmony_ci#include "includes.h"
11e5b75505Sopenharmony_ci
12e5b75505Sopenharmony_ci#include "common.h"
13e5b75505Sopenharmony_ci#include "aes.h"
14e5b75505Sopenharmony_ci#include "aes_wrap.h"
15e5b75505Sopenharmony_ci
16e5b75505Sopenharmony_cistatic void inc32(u8 *block)
17e5b75505Sopenharmony_ci{
18e5b75505Sopenharmony_ci	u32 val;
19e5b75505Sopenharmony_ci	val = WPA_GET_BE32(block + AES_BLOCK_SIZE - 4);
20e5b75505Sopenharmony_ci	val++;
21e5b75505Sopenharmony_ci	WPA_PUT_BE32(block + AES_BLOCK_SIZE - 4, val);
22e5b75505Sopenharmony_ci}
23e5b75505Sopenharmony_ci
24e5b75505Sopenharmony_ci
25e5b75505Sopenharmony_cistatic void xor_block(u8 *dst, const u8 *src)
26e5b75505Sopenharmony_ci{
27e5b75505Sopenharmony_ci	u32 *d = (u32 *) dst;
28e5b75505Sopenharmony_ci	u32 *s = (u32 *) src;
29e5b75505Sopenharmony_ci	*d++ ^= *s++;
30e5b75505Sopenharmony_ci	*d++ ^= *s++;
31e5b75505Sopenharmony_ci	*d++ ^= *s++;
32e5b75505Sopenharmony_ci	*d++ ^= *s++;
33e5b75505Sopenharmony_ci}
34e5b75505Sopenharmony_ci
35e5b75505Sopenharmony_ci
36e5b75505Sopenharmony_cistatic void shift_right_block(u8 *v)
37e5b75505Sopenharmony_ci{
38e5b75505Sopenharmony_ci	u32 val;
39e5b75505Sopenharmony_ci
40e5b75505Sopenharmony_ci	val = WPA_GET_BE32(v + 12);
41e5b75505Sopenharmony_ci	val >>= 1;
42e5b75505Sopenharmony_ci	if (v[11] & 0x01)
43e5b75505Sopenharmony_ci		val |= 0x80000000;
44e5b75505Sopenharmony_ci	WPA_PUT_BE32(v + 12, val);
45e5b75505Sopenharmony_ci
46e5b75505Sopenharmony_ci	val = WPA_GET_BE32(v + 8);
47e5b75505Sopenharmony_ci	val >>= 1;
48e5b75505Sopenharmony_ci	if (v[7] & 0x01)
49e5b75505Sopenharmony_ci		val |= 0x80000000;
50e5b75505Sopenharmony_ci	WPA_PUT_BE32(v + 8, val);
51e5b75505Sopenharmony_ci
52e5b75505Sopenharmony_ci	val = WPA_GET_BE32(v + 4);
53e5b75505Sopenharmony_ci	val >>= 1;
54e5b75505Sopenharmony_ci	if (v[3] & 0x01)
55e5b75505Sopenharmony_ci		val |= 0x80000000;
56e5b75505Sopenharmony_ci	WPA_PUT_BE32(v + 4, val);
57e5b75505Sopenharmony_ci
58e5b75505Sopenharmony_ci	val = WPA_GET_BE32(v);
59e5b75505Sopenharmony_ci	val >>= 1;
60e5b75505Sopenharmony_ci	WPA_PUT_BE32(v, val);
61e5b75505Sopenharmony_ci}
62e5b75505Sopenharmony_ci
63e5b75505Sopenharmony_ci
64e5b75505Sopenharmony_ci/* Multiplication in GF(2^128) */
65e5b75505Sopenharmony_cistatic void gf_mult(const u8 *x, const u8 *y, u8 *z)
66e5b75505Sopenharmony_ci{
67e5b75505Sopenharmony_ci	u8 v[16];
68e5b75505Sopenharmony_ci	int i, j;
69e5b75505Sopenharmony_ci
70e5b75505Sopenharmony_ci	os_memset(z, 0, 16); /* Z_0 = 0^128 */
71e5b75505Sopenharmony_ci	os_memcpy(v, y, 16); /* V_0 = Y */
72e5b75505Sopenharmony_ci
73e5b75505Sopenharmony_ci	for (i = 0; i < 16; i++) {
74e5b75505Sopenharmony_ci		for (j = 0; j < 8; j++) {
75e5b75505Sopenharmony_ci			if (x[i] & BIT(7 - j)) {
76e5b75505Sopenharmony_ci				/* Z_(i + 1) = Z_i XOR V_i */
77e5b75505Sopenharmony_ci				xor_block(z, v);
78e5b75505Sopenharmony_ci			} else {
79e5b75505Sopenharmony_ci				/* Z_(i + 1) = Z_i */
80e5b75505Sopenharmony_ci			}
81e5b75505Sopenharmony_ci
82e5b75505Sopenharmony_ci			if (v[15] & 0x01) {
83e5b75505Sopenharmony_ci				/* V_(i + 1) = (V_i >> 1) XOR R */
84e5b75505Sopenharmony_ci				shift_right_block(v);
85e5b75505Sopenharmony_ci				/* R = 11100001 || 0^120 */
86e5b75505Sopenharmony_ci				v[0] ^= 0xe1;
87e5b75505Sopenharmony_ci			} else {
88e5b75505Sopenharmony_ci				/* V_(i + 1) = V_i >> 1 */
89e5b75505Sopenharmony_ci				shift_right_block(v);
90e5b75505Sopenharmony_ci			}
91e5b75505Sopenharmony_ci		}
92e5b75505Sopenharmony_ci	}
93e5b75505Sopenharmony_ci}
94e5b75505Sopenharmony_ci
95e5b75505Sopenharmony_ci
96e5b75505Sopenharmony_cistatic void ghash_start(u8 *y)
97e5b75505Sopenharmony_ci{
98e5b75505Sopenharmony_ci	/* Y_0 = 0^128 */
99e5b75505Sopenharmony_ci	os_memset(y, 0, 16);
100e5b75505Sopenharmony_ci}
101e5b75505Sopenharmony_ci
102e5b75505Sopenharmony_ci
103e5b75505Sopenharmony_cistatic void ghash(const u8 *h, const u8 *x, size_t xlen, u8 *y)
104e5b75505Sopenharmony_ci{
105e5b75505Sopenharmony_ci	size_t m, i;
106e5b75505Sopenharmony_ci	const u8 *xpos = x;
107e5b75505Sopenharmony_ci	u8 tmp[16];
108e5b75505Sopenharmony_ci
109e5b75505Sopenharmony_ci	m = xlen / 16;
110e5b75505Sopenharmony_ci
111e5b75505Sopenharmony_ci	for (i = 0; i < m; i++) {
112e5b75505Sopenharmony_ci		/* Y_i = (Y^(i-1) XOR X_i) dot H */
113e5b75505Sopenharmony_ci		xor_block(y, xpos);
114e5b75505Sopenharmony_ci		xpos += 16;
115e5b75505Sopenharmony_ci
116e5b75505Sopenharmony_ci		/* dot operation:
117e5b75505Sopenharmony_ci		 * multiplication operation for binary Galois (finite) field of
118e5b75505Sopenharmony_ci		 * 2^128 elements */
119e5b75505Sopenharmony_ci		gf_mult(y, h, tmp);
120e5b75505Sopenharmony_ci		os_memcpy(y, tmp, 16);
121e5b75505Sopenharmony_ci	}
122e5b75505Sopenharmony_ci
123e5b75505Sopenharmony_ci	if (x + xlen > xpos) {
124e5b75505Sopenharmony_ci		/* Add zero padded last block */
125e5b75505Sopenharmony_ci		size_t last = x + xlen - xpos;
126e5b75505Sopenharmony_ci		os_memcpy(tmp, xpos, last);
127e5b75505Sopenharmony_ci		os_memset(tmp + last, 0, sizeof(tmp) - last);
128e5b75505Sopenharmony_ci
129e5b75505Sopenharmony_ci		/* Y_i = (Y^(i-1) XOR X_i) dot H */
130e5b75505Sopenharmony_ci		xor_block(y, tmp);
131e5b75505Sopenharmony_ci
132e5b75505Sopenharmony_ci		/* dot operation:
133e5b75505Sopenharmony_ci		 * multiplication operation for binary Galois (finite) field of
134e5b75505Sopenharmony_ci		 * 2^128 elements */
135e5b75505Sopenharmony_ci		gf_mult(y, h, tmp);
136e5b75505Sopenharmony_ci		os_memcpy(y, tmp, 16);
137e5b75505Sopenharmony_ci	}
138e5b75505Sopenharmony_ci
139e5b75505Sopenharmony_ci	/* Return Y_m */
140e5b75505Sopenharmony_ci}
141e5b75505Sopenharmony_ci
142e5b75505Sopenharmony_ci
143e5b75505Sopenharmony_cistatic void aes_gctr(void *aes, const u8 *icb, const u8 *x, size_t xlen, u8 *y)
144e5b75505Sopenharmony_ci{
145e5b75505Sopenharmony_ci	size_t i, n, last;
146e5b75505Sopenharmony_ci	u8 cb[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE];
147e5b75505Sopenharmony_ci	const u8 *xpos = x;
148e5b75505Sopenharmony_ci	u8 *ypos = y;
149e5b75505Sopenharmony_ci
150e5b75505Sopenharmony_ci	if (xlen == 0)
151e5b75505Sopenharmony_ci		return;
152e5b75505Sopenharmony_ci
153e5b75505Sopenharmony_ci	n = xlen / 16;
154e5b75505Sopenharmony_ci
155e5b75505Sopenharmony_ci	os_memcpy(cb, icb, AES_BLOCK_SIZE);
156e5b75505Sopenharmony_ci	/* Full blocks */
157e5b75505Sopenharmony_ci	for (i = 0; i < n; i++) {
158e5b75505Sopenharmony_ci		aes_encrypt(aes, cb, ypos);
159e5b75505Sopenharmony_ci		xor_block(ypos, xpos);
160e5b75505Sopenharmony_ci		xpos += AES_BLOCK_SIZE;
161e5b75505Sopenharmony_ci		ypos += AES_BLOCK_SIZE;
162e5b75505Sopenharmony_ci		inc32(cb);
163e5b75505Sopenharmony_ci	}
164e5b75505Sopenharmony_ci
165e5b75505Sopenharmony_ci	last = x + xlen - xpos;
166e5b75505Sopenharmony_ci	if (last) {
167e5b75505Sopenharmony_ci		/* Last, partial block */
168e5b75505Sopenharmony_ci		aes_encrypt(aes, cb, tmp);
169e5b75505Sopenharmony_ci		for (i = 0; i < last; i++)
170e5b75505Sopenharmony_ci			*ypos++ = *xpos++ ^ tmp[i];
171e5b75505Sopenharmony_ci	}
172e5b75505Sopenharmony_ci}
173e5b75505Sopenharmony_ci
174e5b75505Sopenharmony_ci
175e5b75505Sopenharmony_cistatic void * aes_gcm_init_hash_subkey(const u8 *key, size_t key_len, u8 *H)
176e5b75505Sopenharmony_ci{
177e5b75505Sopenharmony_ci	void *aes;
178e5b75505Sopenharmony_ci
179e5b75505Sopenharmony_ci	aes = aes_encrypt_init(key, key_len);
180e5b75505Sopenharmony_ci	if (aes == NULL)
181e5b75505Sopenharmony_ci		return NULL;
182e5b75505Sopenharmony_ci
183e5b75505Sopenharmony_ci	/* Generate hash subkey H = AES_K(0^128) */
184e5b75505Sopenharmony_ci	os_memset(H, 0, AES_BLOCK_SIZE);
185e5b75505Sopenharmony_ci	aes_encrypt(aes, H, H);
186e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_EXCESSIVE, "Hash subkey H for GHASH",
187e5b75505Sopenharmony_ci			H, AES_BLOCK_SIZE);
188e5b75505Sopenharmony_ci	return aes;
189e5b75505Sopenharmony_ci}
190e5b75505Sopenharmony_ci
191e5b75505Sopenharmony_ci
192e5b75505Sopenharmony_cistatic void aes_gcm_prepare_j0(const u8 *iv, size_t iv_len, const u8 *H, u8 *J0)
193e5b75505Sopenharmony_ci{
194e5b75505Sopenharmony_ci	u8 len_buf[16];
195e5b75505Sopenharmony_ci
196e5b75505Sopenharmony_ci	if (iv_len == 12) {
197e5b75505Sopenharmony_ci		/* Prepare block J_0 = IV || 0^31 || 1 [len(IV) = 96] */
198e5b75505Sopenharmony_ci		os_memcpy(J0, iv, iv_len);
199e5b75505Sopenharmony_ci		os_memset(J0 + iv_len, 0, AES_BLOCK_SIZE - iv_len);
200e5b75505Sopenharmony_ci		J0[AES_BLOCK_SIZE - 1] = 0x01;
201e5b75505Sopenharmony_ci	} else {
202e5b75505Sopenharmony_ci		/*
203e5b75505Sopenharmony_ci		 * s = 128 * ceil(len(IV)/128) - len(IV)
204e5b75505Sopenharmony_ci		 * J_0 = GHASH_H(IV || 0^(s+64) || [len(IV)]_64)
205e5b75505Sopenharmony_ci		 */
206e5b75505Sopenharmony_ci		ghash_start(J0);
207e5b75505Sopenharmony_ci		ghash(H, iv, iv_len, J0);
208e5b75505Sopenharmony_ci		WPA_PUT_BE64(len_buf, 0);
209e5b75505Sopenharmony_ci		WPA_PUT_BE64(len_buf + 8, iv_len * 8);
210e5b75505Sopenharmony_ci		ghash(H, len_buf, sizeof(len_buf), J0);
211e5b75505Sopenharmony_ci	}
212e5b75505Sopenharmony_ci}
213e5b75505Sopenharmony_ci
214e5b75505Sopenharmony_ci
215e5b75505Sopenharmony_cistatic void aes_gcm_gctr(void *aes, const u8 *J0, const u8 *in, size_t len,
216e5b75505Sopenharmony_ci			 u8 *out)
217e5b75505Sopenharmony_ci{
218e5b75505Sopenharmony_ci	u8 J0inc[AES_BLOCK_SIZE];
219e5b75505Sopenharmony_ci
220e5b75505Sopenharmony_ci	if (len == 0)
221e5b75505Sopenharmony_ci		return;
222e5b75505Sopenharmony_ci
223e5b75505Sopenharmony_ci	os_memcpy(J0inc, J0, AES_BLOCK_SIZE);
224e5b75505Sopenharmony_ci	inc32(J0inc);
225e5b75505Sopenharmony_ci	aes_gctr(aes, J0inc, in, len, out);
226e5b75505Sopenharmony_ci}
227e5b75505Sopenharmony_ci
228e5b75505Sopenharmony_ci
229e5b75505Sopenharmony_cistatic void aes_gcm_ghash(const u8 *H, const u8 *aad, size_t aad_len,
230e5b75505Sopenharmony_ci			  const u8 *crypt, size_t crypt_len, u8 *S)
231e5b75505Sopenharmony_ci{
232e5b75505Sopenharmony_ci	u8 len_buf[16];
233e5b75505Sopenharmony_ci
234e5b75505Sopenharmony_ci	/*
235e5b75505Sopenharmony_ci	 * u = 128 * ceil[len(C)/128] - len(C)
236e5b75505Sopenharmony_ci	 * v = 128 * ceil[len(A)/128] - len(A)
237e5b75505Sopenharmony_ci	 * S = GHASH_H(A || 0^v || C || 0^u || [len(A)]64 || [len(C)]64)
238e5b75505Sopenharmony_ci	 * (i.e., zero padded to block size A || C and lengths of each in bits)
239e5b75505Sopenharmony_ci	 */
240e5b75505Sopenharmony_ci	ghash_start(S);
241e5b75505Sopenharmony_ci	ghash(H, aad, aad_len, S);
242e5b75505Sopenharmony_ci	ghash(H, crypt, crypt_len, S);
243e5b75505Sopenharmony_ci	WPA_PUT_BE64(len_buf, aad_len * 8);
244e5b75505Sopenharmony_ci	WPA_PUT_BE64(len_buf + 8, crypt_len * 8);
245e5b75505Sopenharmony_ci	ghash(H, len_buf, sizeof(len_buf), S);
246e5b75505Sopenharmony_ci
247e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_EXCESSIVE, "S = GHASH_H(...)", S, 16);
248e5b75505Sopenharmony_ci}
249e5b75505Sopenharmony_ci
250e5b75505Sopenharmony_ci
251e5b75505Sopenharmony_ci/**
252e5b75505Sopenharmony_ci * aes_gcm_ae - GCM-AE_K(IV, P, A)
253e5b75505Sopenharmony_ci */
254e5b75505Sopenharmony_ciint aes_gcm_ae(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len,
255e5b75505Sopenharmony_ci	       const u8 *plain, size_t plain_len,
256e5b75505Sopenharmony_ci	       const u8 *aad, size_t aad_len, u8 *crypt, u8 *tag)
257e5b75505Sopenharmony_ci{
258e5b75505Sopenharmony_ci	u8 H[AES_BLOCK_SIZE];
259e5b75505Sopenharmony_ci	u8 J0[AES_BLOCK_SIZE];
260e5b75505Sopenharmony_ci	u8 S[16];
261e5b75505Sopenharmony_ci	void *aes;
262e5b75505Sopenharmony_ci
263e5b75505Sopenharmony_ci	aes = aes_gcm_init_hash_subkey(key, key_len, H);
264e5b75505Sopenharmony_ci	if (aes == NULL)
265e5b75505Sopenharmony_ci		return -1;
266e5b75505Sopenharmony_ci
267e5b75505Sopenharmony_ci	aes_gcm_prepare_j0(iv, iv_len, H, J0);
268e5b75505Sopenharmony_ci
269e5b75505Sopenharmony_ci	/* C = GCTR_K(inc_32(J_0), P) */
270e5b75505Sopenharmony_ci	aes_gcm_gctr(aes, J0, plain, plain_len, crypt);
271e5b75505Sopenharmony_ci
272e5b75505Sopenharmony_ci	aes_gcm_ghash(H, aad, aad_len, crypt, plain_len, S);
273e5b75505Sopenharmony_ci
274e5b75505Sopenharmony_ci	/* T = MSB_t(GCTR_K(J_0, S)) */
275e5b75505Sopenharmony_ci	aes_gctr(aes, J0, S, sizeof(S), tag);
276e5b75505Sopenharmony_ci
277e5b75505Sopenharmony_ci	/* Return (C, T) */
278e5b75505Sopenharmony_ci
279e5b75505Sopenharmony_ci	aes_encrypt_deinit(aes);
280e5b75505Sopenharmony_ci
281e5b75505Sopenharmony_ci	return 0;
282e5b75505Sopenharmony_ci}
283e5b75505Sopenharmony_ci
284e5b75505Sopenharmony_ci
285e5b75505Sopenharmony_ci/**
286e5b75505Sopenharmony_ci * aes_gcm_ad - GCM-AD_K(IV, C, A, T)
287e5b75505Sopenharmony_ci */
288e5b75505Sopenharmony_ciint aes_gcm_ad(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len,
289e5b75505Sopenharmony_ci	       const u8 *crypt, size_t crypt_len,
290e5b75505Sopenharmony_ci	       const u8 *aad, size_t aad_len, const u8 *tag, u8 *plain)
291e5b75505Sopenharmony_ci{
292e5b75505Sopenharmony_ci	u8 H[AES_BLOCK_SIZE];
293e5b75505Sopenharmony_ci	u8 J0[AES_BLOCK_SIZE];
294e5b75505Sopenharmony_ci	u8 S[16], T[16];
295e5b75505Sopenharmony_ci	void *aes;
296e5b75505Sopenharmony_ci
297e5b75505Sopenharmony_ci	aes = aes_gcm_init_hash_subkey(key, key_len, H);
298e5b75505Sopenharmony_ci	if (aes == NULL)
299e5b75505Sopenharmony_ci		return -1;
300e5b75505Sopenharmony_ci
301e5b75505Sopenharmony_ci	aes_gcm_prepare_j0(iv, iv_len, H, J0);
302e5b75505Sopenharmony_ci
303e5b75505Sopenharmony_ci	/* P = GCTR_K(inc_32(J_0), C) */
304e5b75505Sopenharmony_ci	aes_gcm_gctr(aes, J0, crypt, crypt_len, plain);
305e5b75505Sopenharmony_ci
306e5b75505Sopenharmony_ci	aes_gcm_ghash(H, aad, aad_len, crypt, crypt_len, S);
307e5b75505Sopenharmony_ci
308e5b75505Sopenharmony_ci	/* T' = MSB_t(GCTR_K(J_0, S)) */
309e5b75505Sopenharmony_ci	aes_gctr(aes, J0, S, sizeof(S), T);
310e5b75505Sopenharmony_ci
311e5b75505Sopenharmony_ci	aes_encrypt_deinit(aes);
312e5b75505Sopenharmony_ci
313e5b75505Sopenharmony_ci	if (os_memcmp_const(tag, T, 16) != 0) {
314e5b75505Sopenharmony_ci		wpa_printf(MSG_EXCESSIVE, "GCM: Tag mismatch");
315e5b75505Sopenharmony_ci		return -1;
316e5b75505Sopenharmony_ci	}
317e5b75505Sopenharmony_ci
318e5b75505Sopenharmony_ci	return 0;
319e5b75505Sopenharmony_ci}
320e5b75505Sopenharmony_ci
321e5b75505Sopenharmony_ci
322e5b75505Sopenharmony_ciint aes_gmac(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len,
323e5b75505Sopenharmony_ci	     const u8 *aad, size_t aad_len, u8 *tag)
324e5b75505Sopenharmony_ci{
325e5b75505Sopenharmony_ci	return aes_gcm_ae(key, key_len, iv, iv_len, NULL, 0, aad, aad_len, NULL,
326e5b75505Sopenharmony_ci			  tag);
327e5b75505Sopenharmony_ci}
328