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