Support arbitrary IV length with AES-GCM
Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
c2372d7cf0
commit
af0963fab4
4 changed files with 68 additions and 37 deletions
|
@ -173,17 +173,16 @@ static void aes_gctr(void *aes, const u8 *icb, const u8 *x, size_t xlen, u8 *y)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* aes_128_gcm_ae - GCM-AE_K(IV, P, A) with len(IV) = 96
|
* aes_128_gcm_ae - GCM-AE_K(IV, P, A)
|
||||||
*/
|
*/
|
||||||
int aes_128_gcm_ae(const u8 *key, const u8 *iv,
|
int aes_128_gcm_ae(const u8 *key, const u8 *iv, size_t iv_len,
|
||||||
const u8 *plain, size_t plain_len,
|
const u8 *plain, size_t plain_len,
|
||||||
const u8 *aad, size_t aad_len, u8 *crypt, u8 *tag)
|
const u8 *aad, size_t aad_len, u8 *crypt, u8 *tag)
|
||||||
{
|
{
|
||||||
u8 H[AES_BLOCK_SIZE];
|
u8 H[AES_BLOCK_SIZE];
|
||||||
u8 J0[AES_BLOCK_SIZE];
|
u8 J0[AES_BLOCK_SIZE], J0inc[AES_BLOCK_SIZE];
|
||||||
u8 S[16], len_buf[16];
|
u8 S[16], len_buf[16];
|
||||||
void *aes;
|
void *aes;
|
||||||
size_t iv_len = 12;
|
|
||||||
|
|
||||||
aes = aes_encrypt_init(key, 16);
|
aes = aes_encrypt_init(key, 16);
|
||||||
if (aes == NULL)
|
if (aes == NULL)
|
||||||
|
@ -194,14 +193,27 @@ int aes_128_gcm_ae(const u8 *key, const u8 *iv,
|
||||||
aes_encrypt(aes, H, H);
|
aes_encrypt(aes, H, H);
|
||||||
wpa_hexdump_key(MSG_EXCESSIVE, "Hash subkey H for GHASH", H, sizeof(H));
|
wpa_hexdump_key(MSG_EXCESSIVE, "Hash subkey H for GHASH", H, sizeof(H));
|
||||||
|
|
||||||
|
if (iv_len == 12) {
|
||||||
/* 2. Prepare block J_0 = IV || 0^31 || 1 [len(IV) = 96] */
|
/* 2. Prepare block J_0 = IV || 0^31 || 1 [len(IV) = 96] */
|
||||||
os_memcpy(J0, iv, iv_len);
|
os_memcpy(J0, iv, iv_len);
|
||||||
os_memset(J0 + iv_len, 0, AES_BLOCK_SIZE - iv_len);
|
os_memset(J0 + iv_len, 0, AES_BLOCK_SIZE - iv_len);
|
||||||
J0[AES_BLOCK_SIZE - 1] = 0x01;
|
J0[AES_BLOCK_SIZE - 1] = 0x01;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* s = 128 * ceil(len(IV)/128) - len(IV)
|
||||||
|
* J_0 = GHASH_H(IV || 0^(s+64) || [len(IV)]_64)
|
||||||
|
*/
|
||||||
|
ghash_start(J0);
|
||||||
|
ghash(H, iv, iv_len, J0);
|
||||||
|
WPA_PUT_BE64(len_buf, 0);
|
||||||
|
WPA_PUT_BE64(len_buf + 8, iv_len * 8);
|
||||||
|
ghash(H, len_buf, sizeof(len_buf), J0);
|
||||||
|
}
|
||||||
|
|
||||||
/* 3. C = GCTR_K(inc_32(J_0), P) */
|
/* 3. C = GCTR_K(inc_32(J_0), P) */
|
||||||
inc32(J0);
|
os_memcpy(J0inc, J0, AES_BLOCK_SIZE);
|
||||||
aes_gctr(aes, J0, plain, plain_len, crypt);
|
inc32(J0inc);
|
||||||
|
aes_gctr(aes, J0inc, plain, plain_len, crypt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 4. u = 128 * ceil[len(C)/128] - len(C)
|
* 4. u = 128 * ceil[len(C)/128] - len(C)
|
||||||
|
@ -219,7 +231,6 @@ int aes_128_gcm_ae(const u8 *key, const u8 *iv,
|
||||||
wpa_hexdump_key(MSG_EXCESSIVE, "S = GHASH_H(...)", S, 16);
|
wpa_hexdump_key(MSG_EXCESSIVE, "S = GHASH_H(...)", S, 16);
|
||||||
|
|
||||||
/* 6. T = MSB_t(GCTR_K(J_0, S)) */
|
/* 6. T = MSB_t(GCTR_K(J_0, S)) */
|
||||||
J0[AES_BLOCK_SIZE - 1] = 0x01;
|
|
||||||
aes_gctr(aes, J0, S, sizeof(S), tag);
|
aes_gctr(aes, J0, S, sizeof(S), tag);
|
||||||
|
|
||||||
/* 7. Return (C, T) */
|
/* 7. Return (C, T) */
|
||||||
|
@ -231,17 +242,16 @@ int aes_128_gcm_ae(const u8 *key, const u8 *iv,
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* aes_128_gcm_ad - GCM-AD_K(IV, C, A, T) with len(IV) = 96
|
* aes_128_gcm_ad - GCM-AD_K(IV, C, A, T)
|
||||||
*/
|
*/
|
||||||
int aes_128_gcm_ad(const u8 *key, const u8 *iv,
|
int aes_128_gcm_ad(const u8 *key, const u8 *iv, size_t iv_len,
|
||||||
const u8 *crypt, size_t crypt_len,
|
const u8 *crypt, size_t crypt_len,
|
||||||
const u8 *aad, size_t aad_len, const u8 *tag, u8 *plain)
|
const u8 *aad, size_t aad_len, const u8 *tag, u8 *plain)
|
||||||
{
|
{
|
||||||
u8 H[AES_BLOCK_SIZE];
|
u8 H[AES_BLOCK_SIZE];
|
||||||
u8 J0[AES_BLOCK_SIZE];
|
u8 J0[AES_BLOCK_SIZE], J0inc[AES_BLOCK_SIZE];
|
||||||
u8 S[16], T[16], len_buf[16];
|
u8 S[16], T[16], len_buf[16];
|
||||||
void *aes;
|
void *aes;
|
||||||
size_t iv_len = 12;
|
|
||||||
|
|
||||||
aes = aes_encrypt_init(key, 16);
|
aes = aes_encrypt_init(key, 16);
|
||||||
if (aes == NULL)
|
if (aes == NULL)
|
||||||
|
@ -252,14 +262,27 @@ int aes_128_gcm_ad(const u8 *key, const u8 *iv,
|
||||||
aes_encrypt(aes, H, H);
|
aes_encrypt(aes, H, H);
|
||||||
wpa_hexdump_key(MSG_EXCESSIVE, "Hash subkey H for GHASH", H, sizeof(H));
|
wpa_hexdump_key(MSG_EXCESSIVE, "Hash subkey H for GHASH", H, sizeof(H));
|
||||||
|
|
||||||
|
if (iv_len == 12) {
|
||||||
/* 3. Prepare block J_0 = IV || 0^31 || 1 [len(IV) = 96] */
|
/* 3. Prepare block J_0 = IV || 0^31 || 1 [len(IV) = 96] */
|
||||||
os_memcpy(J0, iv, iv_len);
|
os_memcpy(J0, iv, iv_len);
|
||||||
os_memset(J0 + iv_len, 0, AES_BLOCK_SIZE - iv_len);
|
os_memset(J0 + iv_len, 0, AES_BLOCK_SIZE - iv_len);
|
||||||
J0[AES_BLOCK_SIZE - 1] = 0x01;
|
J0[AES_BLOCK_SIZE - 1] = 0x01;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* s = 128 * ceil(len(IV)/128) - len(IV)
|
||||||
|
* J_0 = GHASH_H(IV || 0^(s+64) || [len(IV)]_64)
|
||||||
|
*/
|
||||||
|
ghash_start(J0);
|
||||||
|
ghash(H, iv, iv_len, J0);
|
||||||
|
WPA_PUT_BE64(len_buf, 0);
|
||||||
|
WPA_PUT_BE64(len_buf + 8, iv_len * 8);
|
||||||
|
ghash(H, len_buf, sizeof(len_buf), J0);
|
||||||
|
}
|
||||||
|
|
||||||
/* 4. C = GCTR_K(inc_32(J_0), C) */
|
/* 4. C = GCTR_K(inc_32(J_0), C) */
|
||||||
inc32(J0);
|
os_memcpy(J0inc, J0, AES_BLOCK_SIZE);
|
||||||
aes_gctr(aes, J0, crypt, crypt_len, plain);
|
inc32(J0inc);
|
||||||
|
aes_gctr(aes, J0inc, crypt, crypt_len, plain);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 5. u = 128 * ceil[len(C)/128] - len(C)
|
* 5. u = 128 * ceil[len(C)/128] - len(C)
|
||||||
|
@ -277,7 +300,6 @@ int aes_128_gcm_ad(const u8 *key, const u8 *iv,
|
||||||
wpa_hexdump_key(MSG_EXCESSIVE, "S = GHASH_H(...)", S, 16);
|
wpa_hexdump_key(MSG_EXCESSIVE, "S = GHASH_H(...)", S, 16);
|
||||||
|
|
||||||
/* 7. T' = MSB_t(GCTR_K(J_0, S)) */
|
/* 7. T' = MSB_t(GCTR_K(J_0, S)) */
|
||||||
J0[AES_BLOCK_SIZE - 1] = 0x01;
|
|
||||||
aes_gctr(aes, J0, S, sizeof(S), T);
|
aes_gctr(aes, J0, S, sizeof(S), T);
|
||||||
|
|
||||||
aes_encrypt_deinit(aes);
|
aes_encrypt_deinit(aes);
|
||||||
|
|
|
@ -39,11 +39,11 @@ int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
|
||||||
size_t data_len);
|
size_t data_len);
|
||||||
int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
|
int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
|
||||||
size_t data_len);
|
size_t data_len);
|
||||||
int __must_check aes_128_gcm_ae(const u8 *key, const u8 *iv,
|
int __must_check aes_128_gcm_ae(const u8 *key, const u8 *iv, size_t iv_len,
|
||||||
const u8 *plain, size_t plain_len,
|
const u8 *plain, size_t plain_len,
|
||||||
const u8 *aad, size_t aad_len,
|
const u8 *aad, size_t aad_len,
|
||||||
u8 *crypt, u8 *tag);
|
u8 *crypt, u8 *tag);
|
||||||
int __must_check aes_128_gcm_ad(const u8 *key, const u8 *iv,
|
int __must_check aes_128_gcm_ad(const u8 *key, const u8 *iv, size_t iv_len,
|
||||||
const u8 *crypt, size_t crypt_len,
|
const u8 *crypt, size_t crypt_len,
|
||||||
const u8 *aad, size_t aad_len, const u8 *tag,
|
const u8 *aad, size_t aad_len, const u8 *tag,
|
||||||
u8 *plain);
|
u8 *plain);
|
||||||
|
|
|
@ -210,7 +210,6 @@ static const struct gcm_test_vector gcm_tests[] = {
|
||||||
"42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091",
|
"42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091",
|
||||||
"5bc94fbc3221a5db94fae95ae7121a47"
|
"5bc94fbc3221a5db94fae95ae7121a47"
|
||||||
},
|
},
|
||||||
#if 0 /* Unsupported IV length */
|
|
||||||
{
|
{
|
||||||
/* Test Case 5 */
|
/* Test Case 5 */
|
||||||
"feffe9928665731c6d6a8f9467308308",
|
"feffe9928665731c6d6a8f9467308308",
|
||||||
|
@ -220,7 +219,15 @@ static const struct gcm_test_vector gcm_tests[] = {
|
||||||
"61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598",
|
"61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598",
|
||||||
"3612d2e79e3b0785561be14aaca2fccb"
|
"3612d2e79e3b0785561be14aaca2fccb"
|
||||||
},
|
},
|
||||||
#endif
|
{
|
||||||
|
/* Test Case 6 */
|
||||||
|
"feffe9928665731c6d6a8f9467308308",
|
||||||
|
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||||
|
"feedfacedeadbeeffeedfacedeadbeefabaddad2",
|
||||||
|
"9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
|
||||||
|
"8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5",
|
||||||
|
"619cc5aefffe0bfa462af43c1699d050"
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -228,9 +235,9 @@ static int test_gcm(void)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int i;
|
int i;
|
||||||
u8 k[16], aad[32], iv[12], t[16], tag[16];
|
u8 k[16], aad[32], iv[64], t[16], tag[16];
|
||||||
u8 p[64], c[64], tmp[64];
|
u8 p[64], c[64], tmp[64];
|
||||||
size_t p_len, aad_len;
|
size_t p_len, aad_len, iv_len;
|
||||||
|
|
||||||
for (i = 0; i < sizeof(gcm_tests) / sizeof(gcm_tests[0]); i++) {
|
for (i = 0; i < sizeof(gcm_tests) / sizeof(gcm_tests[0]); i++) {
|
||||||
const struct gcm_test_vector *tc = &gcm_tests[i];
|
const struct gcm_test_vector *tc = &gcm_tests[i];
|
||||||
|
@ -255,7 +262,8 @@ static int test_gcm(void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hexstr2bin(tc->iv, iv, sizeof(iv))) {
|
iv_len = os_strlen(tc->iv) / 2;
|
||||||
|
if (hexstr2bin(tc->iv, iv, iv_len)) {
|
||||||
printf("Invalid GCM test vector %d (iv)\n", i);
|
printf("Invalid GCM test vector %d (iv)\n", i);
|
||||||
ret++;
|
ret++;
|
||||||
continue;
|
continue;
|
||||||
|
@ -273,8 +281,8 @@ static int test_gcm(void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aes_128_gcm_ae(k, iv, p, p_len, aad, aad_len, tmp, tag) < 0)
|
if (aes_128_gcm_ae(k, iv, iv_len, p, p_len, aad, aad_len, tmp,
|
||||||
{
|
tag) < 0) {
|
||||||
printf("GCM-AE failed (test case %d)\n", i);
|
printf("GCM-AE failed (test case %d)\n", i);
|
||||||
ret++;
|
ret++;
|
||||||
continue;
|
continue;
|
||||||
|
@ -286,11 +294,12 @@ static int test_gcm(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (os_memcmp(tag, t, sizeof(tag)) != 0) {
|
if (os_memcmp(tag, t, sizeof(tag)) != 0) {
|
||||||
printf("GCM-AD tag mismatch (test case %d)\n", i);
|
printf("GCM-AE tag mismatch (test case %d)\n", i);
|
||||||
ret++;
|
ret++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aes_128_gcm_ad(k, iv, c, p_len, aad, aad_len, t, tmp) < 0) {
|
if (aes_128_gcm_ad(k, iv, iv_len, c, p_len, aad, aad_len, t,
|
||||||
|
tmp) < 0) {
|
||||||
printf("GCM-AD failed (test case %d)\n", i);
|
printf("GCM-AD failed (test case %d)\n", i);
|
||||||
ret++;
|
ret++;
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -95,8 +95,8 @@ u8 * gcmp_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
|
||||||
wpa_hexdump(MSG_EXCESSIVE, "GCMP AAD", aad, aad_len);
|
wpa_hexdump(MSG_EXCESSIVE, "GCMP AAD", aad, aad_len);
|
||||||
wpa_hexdump(MSG_EXCESSIVE, "GCMP nonce", nonce, sizeof(nonce));
|
wpa_hexdump(MSG_EXCESSIVE, "GCMP nonce", nonce, sizeof(nonce));
|
||||||
|
|
||||||
if (aes_128_gcm_ad(tk, nonce, m, mlen, aad, aad_len, m + mlen, plain) <
|
if (aes_128_gcm_ad(tk, nonce, sizeof(nonce), m, mlen, aad, aad_len,
|
||||||
0) {
|
m + mlen, plain) < 0) {
|
||||||
u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
|
u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
|
||||||
wpa_printf(MSG_INFO, "Invalid GCMP frame: A1=" MACSTR
|
wpa_printf(MSG_INFO, "Invalid GCMP frame: A1=" MACSTR
|
||||||
" A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
|
" A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
|
||||||
|
@ -146,8 +146,8 @@ u8 * gcmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
|
||||||
wpa_hexdump(MSG_EXCESSIVE, "GCMP AAD", aad, aad_len);
|
wpa_hexdump(MSG_EXCESSIVE, "GCMP AAD", aad, aad_len);
|
||||||
wpa_hexdump(MSG_EXCESSIVE, "GCMP nonce", nonce, sizeof(nonce));
|
wpa_hexdump(MSG_EXCESSIVE, "GCMP nonce", nonce, sizeof(nonce));
|
||||||
|
|
||||||
if (aes_128_gcm_ae(tk, nonce, frame + hdrlen, plen, aad, aad_len,
|
if (aes_128_gcm_ae(tk, nonce, sizeof(nonce), frame + hdrlen, plen, aad,
|
||||||
pos, pos + plen) < 0) {
|
aad_len, pos, pos + plen) < 0) {
|
||||||
os_free(crypt);
|
os_free(crypt);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue