From 6f74677911de87f3271721073bd360806a93733f Mon Sep 17 00:00:00 2001 From: Todd Short Date: Sun, 31 Jul 2022 21:24:13 -0400 Subject: Fix AES-GCM-SIV endian issues Fixes #18911 `BSWAP`x/`GETU`xx are no-ops on big-endian. Change the byte swapper. Fix big-endian issues in the `mulx_ghash()` function Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/18920) --- .../implementations/ciphers/cipher_aes_gcm_siv.h | 24 +++++++++---------- .../ciphers/cipher_aes_gcm_siv_hw.c | 16 ++++++------- .../ciphers/cipher_aes_gcm_siv_polyval.c | 27 +++++++++++++++------- 3 files changed, 38 insertions(+), 29 deletions(-) (limited to 'providers') diff --git a/providers/implementations/ciphers/cipher_aes_gcm_siv.h b/providers/implementations/ciphers/cipher_aes_gcm_siv.h index 1224512e3a..37d1e3326b 100644 --- a/providers/implementations/ciphers/cipher_aes_gcm_siv.h +++ b/providers/implementations/ciphers/cipher_aes_gcm_siv.h @@ -58,21 +58,19 @@ const PROV_CIPHER_HW_AES_GCM_SIV *ossl_prov_cipher_hw_aes_gcm_siv(size_t keybits void ossl_polyval_ghash_init(u128 Htable[16], const uint64_t H[2]); void ossl_polyval_ghash_hash(const u128 Htable[16], uint8_t *tag, const uint8_t *inp, size_t len); -/* Define our own BSWAP8/BSWAP4, if not already defined */ -#ifndef BSWAP8 -static ossl_inline uint64_t BSWAP8(uint64_t n) +/* Define GSWAP8/GSWAP4 - used for BOTH little and big endian architectures */ +static ossl_inline uint32_t GSWAP4(uint32_t n) { - uint8_t *p = (uint8_t *)&n; - - return (uint64_t)GETU32(p) << 32 | GETU32(p + 4); + return (((n & 0x000000FF) << 24) + | ((n & 0x0000FF00) << 8) + | ((n & 0x00FF0000) >> 8) + | ((n & 0xFF000000) >> 24)); } -#endif - -#ifndef BSWAP4 -static ossl_inline uint32_t BSWAP4(uint32_t n) +static ossl_inline uint64_t GSWAP8(uint64_t n) { - uint8_t *p = (uint8_t *)&n; + uint64_t result; - return GETU32(p); + result = GSWAP4(n & 0x0FFFFFFFF); + result <<= 32; + return result | GSWAP4(n >> 32); } -#endif diff --git a/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c b/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c index 9ee5c32f4f..9887e1c3a4 100644 --- a/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c +++ b/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c @@ -64,7 +64,7 @@ static int aes_gcm_siv_initkey(void *vctx) if (IS_LITTLE_ENDIAN) { data.counter = counter; } else { - data.counter = BSWAP4(counter); + data.counter = GSWAP4(counter); } /* Block size is 16 (128 bits), but only 8 bytes are used */ out_len = BLOCK_SIZE; @@ -79,7 +79,7 @@ static int aes_gcm_siv_initkey(void *vctx) if (IS_LITTLE_ENDIAN) { data.counter = counter; } else { - data.counter = BSWAP4(counter); + data.counter = GSWAP4(counter); } /* Block size is 16 bytes (128 bits), but only 8 bytes are used */ out_len = BLOCK_SIZE; @@ -169,8 +169,8 @@ static int aes_gcm_siv_encrypt(PROV_AES_GCM_SIV_CTX *ctx, const unsigned char *i len_blk[0] = (uint64_t)ctx->aad_len * 8; len_blk[1] = (uint64_t)len * 8; } else { - len_blk[0] = BSWAP8((uint64_t)ctx->aad_len * 8); - len_blk[1] = BSWAP8((uint64_t)len * 8); + len_blk[0] = GSWAP8((uint64_t)ctx->aad_len * 8); + len_blk[1] = GSWAP8((uint64_t)len * 8); } memset(S_s, 0, TAG_SIZE); ossl_polyval_ghash_init(ctx->Htable, (const uint64_t*)ctx->msg_auth_key); @@ -235,8 +235,8 @@ static int aes_gcm_siv_decrypt(PROV_AES_GCM_SIV_CTX *ctx, const unsigned char *i len_blk[0] = (uint64_t)ctx->aad_len * 8; len_blk[1] = (uint64_t)len * 8; } else { - len_blk[0] = BSWAP8((uint64_t)ctx->aad_len * 8); - len_blk[1] = BSWAP8((uint64_t)len * 8); + len_blk[0] = GSWAP8((uint64_t)ctx->aad_len * 8); + len_blk[1] = GSWAP8((uint64_t)len * 8); } memset(S_s, 0, TAG_SIZE); ossl_polyval_ghash_init(ctx->Htable, (const uint64_t*)ctx->msg_auth_key); @@ -350,7 +350,7 @@ static int aes_gcm_siv_ctr32(PROV_AES_GCM_SIV_CTX *ctx, const unsigned char *ini memcpy(&block, init_counter, sizeof(block)); if (IS_BIG_ENDIAN) { - counter = BSWAP4(block.x32[0]); + counter = GSWAP4(block.x32[0]); } for (i = 0; i < len; i += sizeof(block)) { @@ -360,7 +360,7 @@ static int aes_gcm_siv_ctr32(PROV_AES_GCM_SIV_CTX *ctx, const unsigned char *ini block.x32[0]++; } else { counter++; - block.x32[0] = BSWAP4(counter); + block.x32[0] = GSWAP4(counter); } todo = len - i; if (todo > sizeof(keystream)) diff --git a/providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c b/providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c index 66f6ed457e..4d147f3bc4 100644 --- a/providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c +++ b/providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c @@ -22,22 +22,33 @@ static ossl_inline void mulx_ghash(uint64_t *a) { uint64_t t[2], mask; + DECLARE_IS_ENDIAN; - t[0] = BSWAP8(a[0]); - t[1] = BSWAP8(a[1]); + if (IS_LITTLE_ENDIAN) { + t[0] = GSWAP8(a[0]); + t[1] = GSWAP8(a[1]); + } else { + t[0] = a[0]; + t[1] = a[1]; + } mask = -(int64_t)(t[1] & 1) & 0xe1; mask <<= 56; - a[1] = BSWAP8((t[1] >> 1) ^ (t[0] << 63)); - a[0] = BSWAP8((t[0] >> 1) ^ mask); + if (IS_LITTLE_ENDIAN) { + a[1] = GSWAP8((t[1] >> 1) ^ (t[0] << 63)); + a[0] = GSWAP8((t[0] >> 1) ^ mask); + } else { + a[1] = (t[1] >> 1) ^ (t[0] << 63); + a[0] = (t[0] >> 1) ^ mask; + } } #define aligned64(p) (((uintptr_t)p & 0x07) == 0) static ossl_inline void byte_reverse16(uint8_t *out, const uint8_t *in) { if (aligned64(out) && aligned64(in)) { - ((uint64_t *)out)[0] = BSWAP8(((uint64_t *)in)[1]); - ((uint64_t *)out)[1] = BSWAP8(((uint64_t *)in)[0]); + ((uint64_t *)out)[0] = GSWAP8(((uint64_t *)in)[1]); + ((uint64_t *)out)[1] = GSWAP8(((uint64_t *)in)[0]); } else { int i; @@ -56,8 +67,8 @@ void ossl_polyval_ghash_init(u128 Htable[16], const uint64_t H[2]) mulx_ghash(tmp); if (IS_LITTLE_ENDIAN) { /* "H is stored in host byte order" */ - tmp[0] = BSWAP8(tmp[0]); - tmp[1] = BSWAP8(tmp[1]); + tmp[0] = GSWAP8(tmp[0]); + tmp[1] = GSWAP8(tmp[1]); } ossl_gcm_init_4bit(Htable, (u64*)tmp); -- cgit v1.2.3