]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Fix AES-GCM-SIV endian issues
authorTodd Short <todd.short@me.com>
Mon, 1 Aug 2022 01:24:13 +0000 (21:24 -0400)
committerTomas Mraz <tomas@openssl.org>
Mon, 1 Aug 2022 08:23:57 +0000 (10:23 +0200)
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 <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18920)

providers/implementations/ciphers/cipher_aes_gcm_siv.h
providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c
providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c

index 1224512e3a74e3d1ce808e359fcf142652c3df9a..37d1e3326b18037828087eff6915fc911e952df7 100644 (file)
@@ -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
index 9ee5c32f4fde00a8f1b52892f7e5036c9aa314e3..9887e1c3a468a57d73fb8d5201f8c532495beb9c 100644 (file)
@@ -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))
index 66f6ed457ec133234d65bfbf539bce024d4cf051..4d147f3bc4fc46472fe270f83bfc9fd601b3ddc8 100644 (file)
 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);