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