wlantest: Allow GHASH update calls to avoid extra allocation
There is no need to allocate a temporary buffer and build GHASH input data into it. Instead, ghash() is trivial to split into update part that can be called separately for each segment. Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
b4a5fcb286
commit
be87d3c345
1 changed files with 39 additions and 70 deletions
109
wlantest/gcmp.c
109
wlantest/gcmp.c
|
@ -94,6 +94,13 @@ static void gf_mult(const u8 *x, const u8 *y, u8 *z)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ghash_start(u8 *y)
|
||||||
|
{
|
||||||
|
/* Y_0 = 0^128 */
|
||||||
|
os_memset(y, 0, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void ghash(const u8 *h, const u8 *x, size_t xlen, u8 *y)
|
static void ghash(const u8 *h, const u8 *x, size_t xlen, u8 *y)
|
||||||
{
|
{
|
||||||
size_t m, i;
|
size_t m, i;
|
||||||
|
@ -102,8 +109,6 @@ static void ghash(const u8 *h, const u8 *x, size_t xlen, u8 *y)
|
||||||
|
|
||||||
m = xlen / 16;
|
m = xlen / 16;
|
||||||
|
|
||||||
/* Y_0 = 0^128 */
|
|
||||||
os_memset(y, 0, 16);
|
|
||||||
for (i = 0; i < m; i++) {
|
for (i = 0; i < m; i++) {
|
||||||
/* Y_i = (Y^(i-1) XOR X_i) dot H */
|
/* Y_i = (Y^(i-1) XOR X_i) dot H */
|
||||||
xor_block(y, xpos);
|
xor_block(y, xpos);
|
||||||
|
@ -116,6 +121,22 @@ static void ghash(const u8 *h, const u8 *x, size_t xlen, u8 *y)
|
||||||
os_memcpy(y, tmp, 16);
|
os_memcpy(y, tmp, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (x + xlen > xpos) {
|
||||||
|
/* Add zero padded last block */
|
||||||
|
size_t last = x + xlen - xpos;
|
||||||
|
os_memcpy(tmp, xpos, last);
|
||||||
|
os_memset(tmp + last, 0, sizeof(tmp) - last);
|
||||||
|
|
||||||
|
/* Y_i = (Y^(i-1) XOR X_i) dot H */
|
||||||
|
xor_block(y, tmp);
|
||||||
|
|
||||||
|
/* dot operation:
|
||||||
|
* multiplication operation for binary Galois (finite) field of
|
||||||
|
* 2^128 elements */
|
||||||
|
gf_mult(y, h, tmp);
|
||||||
|
os_memcpy(y, tmp, 16);
|
||||||
|
}
|
||||||
|
|
||||||
/* Return Y_m */
|
/* Return Y_m */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,12 +181,10 @@ static int aes_gcm_ae(const u8 *key, const u8 *iv,
|
||||||
const u8 *aad, size_t aad_len,
|
const u8 *aad, size_t aad_len,
|
||||||
u8 *crypt, u8 *tag)
|
u8 *crypt, u8 *tag)
|
||||||
{
|
{
|
||||||
u8 *auth, *apos;
|
|
||||||
u8 H[AES_BLOCK_SIZE];
|
u8 H[AES_BLOCK_SIZE];
|
||||||
u8 J0[AES_BLOCK_SIZE];
|
u8 J0[AES_BLOCK_SIZE];
|
||||||
u8 S[16];
|
u8 S[16], len_buf[16];
|
||||||
void *aes;
|
void *aes;
|
||||||
size_t padlen;
|
|
||||||
size_t iv_len = 12;
|
size_t iv_len = 12;
|
||||||
|
|
||||||
aes = aes_encrypt_init(key, 16);
|
aes = aes_encrypt_init(key, 16);
|
||||||
|
@ -192,38 +211,14 @@ static int aes_gcm_ae(const u8 *key, const u8 *iv,
|
||||||
* 5. S = GHASH_H(A || 0^v || C || 0^u || [len(A)]64 || [len(C)]64)
|
* 5. S = GHASH_H(A || 0^v || C || 0^u || [len(A)]64 || [len(C)]64)
|
||||||
* (i.e., zero padded to block size A || C and lengths of each in bits)
|
* (i.e., zero padded to block size A || C and lengths of each in bits)
|
||||||
*/
|
*/
|
||||||
auth = os_malloc(32 + 16 + plain_len + 8 + 8);
|
ghash_start(S);
|
||||||
if (auth == NULL) {
|
ghash(H, aad, aad_len, S);
|
||||||
aes_encrypt_deinit(aes);
|
ghash(H, crypt, plain_len, S);
|
||||||
return -1;
|
WPA_PUT_BE64(len_buf, aad_len * 8);
|
||||||
}
|
WPA_PUT_BE64(len_buf + 8, plain_len * 8);
|
||||||
|
ghash(H, len_buf, sizeof(len_buf), S);
|
||||||
|
|
||||||
apos = auth;
|
|
||||||
|
|
||||||
/* Zero-padded AAD */
|
|
||||||
os_memcpy(apos, aad, aad_len);
|
|
||||||
apos += aad_len;
|
|
||||||
padlen = (16 - aad_len % 16) % 16;
|
|
||||||
os_memset(apos, 0, padlen);
|
|
||||||
apos += padlen;
|
|
||||||
|
|
||||||
/* Zero-padded C */
|
|
||||||
os_memcpy(apos, crypt, plain_len);
|
|
||||||
apos += plain_len;
|
|
||||||
padlen = (16 - plain_len % 16) % 16;
|
|
||||||
os_memset(apos, 0, padlen);
|
|
||||||
apos += padlen;
|
|
||||||
|
|
||||||
/* Length of AAD and C in bits */
|
|
||||||
WPA_PUT_BE64(apos, aad_len * 8);
|
|
||||||
apos += 8;
|
|
||||||
WPA_PUT_BE64(apos, plain_len * 8);
|
|
||||||
apos += 8;
|
|
||||||
|
|
||||||
wpa_hexdump_key(MSG_EXCESSIVE, "GHASH_H input", auth, apos - auth);
|
|
||||||
ghash(H, auth, apos - auth, S);
|
|
||||||
wpa_hexdump_key(MSG_EXCESSIVE, "S = GHASH_H(...)", S, 16);
|
wpa_hexdump_key(MSG_EXCESSIVE, "S = GHASH_H(...)", S, 16);
|
||||||
os_free(auth);
|
|
||||||
|
|
||||||
/* 6. T = MSB_t(GCTR_K(J_0, S)) */
|
/* 6. T = MSB_t(GCTR_K(J_0, S)) */
|
||||||
J0[AES_BLOCK_SIZE - 1] = 0x01;
|
J0[AES_BLOCK_SIZE - 1] = 0x01;
|
||||||
|
@ -245,12 +240,10 @@ static int aes_gcm_ad(const u8 *key, const u8 *iv,
|
||||||
const u8 *aad, size_t aad_len, const u8 *tag,
|
const u8 *aad, size_t aad_len, const u8 *tag,
|
||||||
u8 *plain)
|
u8 *plain)
|
||||||
{
|
{
|
||||||
u8 *auth, *apos;
|
|
||||||
u8 H[AES_BLOCK_SIZE];
|
u8 H[AES_BLOCK_SIZE];
|
||||||
u8 J0[AES_BLOCK_SIZE];
|
u8 J0[AES_BLOCK_SIZE];
|
||||||
u8 S[16], T[16];
|
u8 S[16], T[16], len_buf[16];
|
||||||
void *aes;
|
void *aes;
|
||||||
size_t padlen;
|
|
||||||
size_t iv_len = 12;
|
size_t iv_len = 12;
|
||||||
|
|
||||||
aes = aes_encrypt_init(key, 16);
|
aes = aes_encrypt_init(key, 16);
|
||||||
|
@ -260,7 +253,7 @@ static int aes_gcm_ad(const u8 *key, const u8 *iv,
|
||||||
/* 2. Generate hash subkey H = AES_K(0^128) */
|
/* 2. Generate hash subkey H = AES_K(0^128) */
|
||||||
os_memset(H, 0, sizeof(H));
|
os_memset(H, 0, sizeof(H));
|
||||||
aes_encrypt(aes, H, H);
|
aes_encrypt(aes, H, H);
|
||||||
wpa_hexdump(MSG_EXCESSIVE, "Hash subkey H for GHASH", H, sizeof(H));
|
wpa_hexdump_key(MSG_EXCESSIVE, "Hash subkey H for GHASH", H, sizeof(H));
|
||||||
|
|
||||||
/* 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);
|
||||||
|
@ -277,38 +270,14 @@ static int aes_gcm_ad(const u8 *key, const u8 *iv,
|
||||||
* 6. S = GHASH_H(A || 0^v || C || 0^u || [len(A)]64 || [len(C)]64)
|
* 6. S = GHASH_H(A || 0^v || C || 0^u || [len(A)]64 || [len(C)]64)
|
||||||
* (i.e., zero padded to block size A || C and lengths of each in bits)
|
* (i.e., zero padded to block size A || C and lengths of each in bits)
|
||||||
*/
|
*/
|
||||||
auth = os_malloc(32 + 16 + crypt_len + 8 + 8);
|
ghash_start(S);
|
||||||
if (auth == NULL) {
|
ghash(H, aad, aad_len, S);
|
||||||
aes_encrypt_deinit(aes);
|
ghash(H, crypt, crypt_len, S);
|
||||||
return -1;
|
WPA_PUT_BE64(len_buf, aad_len * 8);
|
||||||
}
|
WPA_PUT_BE64(len_buf + 8, crypt_len * 8);
|
||||||
|
ghash(H, len_buf, sizeof(len_buf), S);
|
||||||
|
|
||||||
apos = auth;
|
wpa_hexdump_key(MSG_EXCESSIVE, "S = GHASH_H(...)", S, 16);
|
||||||
|
|
||||||
/* Zero-padded AAD */
|
|
||||||
os_memcpy(apos, aad, aad_len);
|
|
||||||
apos += aad_len;
|
|
||||||
padlen = (16 - aad_len % 16) % 16;
|
|
||||||
os_memset(apos, 0, padlen);
|
|
||||||
apos += padlen;
|
|
||||||
|
|
||||||
/* Zero-padded C */
|
|
||||||
os_memcpy(apos, crypt, crypt_len);
|
|
||||||
apos += crypt_len;
|
|
||||||
padlen = (16 - crypt_len % 16) % 16;
|
|
||||||
os_memset(apos, 0, padlen);
|
|
||||||
apos += padlen;
|
|
||||||
|
|
||||||
/* Length of AAD and C in bits */
|
|
||||||
WPA_PUT_BE64(apos, aad_len * 8);
|
|
||||||
apos += 8;
|
|
||||||
WPA_PUT_BE64(apos, crypt_len * 8);
|
|
||||||
apos += 8;
|
|
||||||
|
|
||||||
wpa_hexdump(MSG_EXCESSIVE, "GHASH_H input", auth, apos - auth);
|
|
||||||
ghash(H, auth, apos - auth, S);
|
|
||||||
wpa_hexdump(MSG_EXCESSIVE, "S = GHASH_H(...)", S, 16);
|
|
||||||
os_free(auth);
|
|
||||||
|
|
||||||
/* 7. T' = MSB_t(GCTR_K(J_0, S)) */
|
/* 7. T' = MSB_t(GCTR_K(J_0, S)) */
|
||||||
J0[AES_BLOCK_SIZE - 1] = 0x01;
|
J0[AES_BLOCK_SIZE - 1] = 0x01;
|
||||||
|
|
Loading…
Reference in a new issue