Browse Source

Ensure that AES key is always correctly aligned

Aligning a `struct` member via `attribute(align(<n>))` is not guaranteed
to work.
Change the approach to use an opaque buffer and always manually align
the start pointers of the keys.

c.f. https://github.com/DCIT/perl-CryptX/issues/95

Signed-off-by: Steffen Jaeckel <[email protected]>
Steffen Jaeckel 2 years ago
parent
commit
fcdb5c4b30

+ 5 - 1
src/ciphers/aes/aes.c

@@ -96,7 +96,7 @@ static ulong32 setup_mix2(ulong32 temp)
 int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
 {
     int i;
-    ulong32 temp, *rk;
+    ulong32 temp, *rk, *K;
 #ifndef ENCRYPT_ONLY
     ulong32 *rrk;
 #endif
@@ -112,6 +112,10 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
     }
 
     skey->rijndael.Nr = 10 + ((keylen/8)-2)*2;
+    K = LTC_ALIGN_BUF(skey->rijndael.K, 16);
+    skey->rijndael.eK = K;
+    K += 60;
+    skey->rijndael.dK = K;
 
     /* setup the forward key */
     i                 = 0;

+ 5 - 1
src/ciphers/aes/aesni.c

@@ -46,7 +46,7 @@ int aesni_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_
 {
    int i;
    __m128i temp;
-   ulong32 *rk;
+   ulong32 *rk, *K;
    ulong32 *rrk;
    LTC_ARGCHK(key != NULL);
    LTC_ARGCHK(skey != NULL);
@@ -60,6 +60,10 @@ int aesni_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_
    }
 
    skey->rijndael.Nr = keylen / 4 + 6;
+   K = LTC_ALIGN_BUF(skey->rijndael.K, 16);
+   skey->rijndael.eK = K;
+   K += 60;
+   skey->rijndael.dK = K;
 
    /* setup the forward key */
    i = 0;

+ 1 - 1
src/headers/tomcrypt_cfg.h

@@ -209,7 +209,7 @@ LTC_EXPORT int   LTC_CALL XSTRCMP(const char *s1, const char *s2);
    typedef unsigned __int64 ulong64;
    typedef __int64 long64;
 #else
-   #define CONST64(n) n ## ULL
+   #define CONST64(n) n ## uLL
    typedef unsigned long long ulong64;
    typedef long long long64;
 #endif

+ 3 - 2
src/headers/tomcrypt_cipher.h

@@ -35,9 +35,10 @@ struct saferp_key {
 
 #ifdef LTC_RIJNDAEL
 struct rijndael_key {
-   ulong32 eK[60] LTC_ALIGN(16);
-   ulong32 dK[60] LTC_ALIGN(16);
+   ulong32 *eK;
+   ulong32 *dK;
    int Nr;
+   unsigned char K[(60 + 60 + 4) * sizeof(ulong32)];
 };
 #endif
 

+ 15 - 0
src/headers/tomcrypt_private.h

@@ -9,6 +9,21 @@
 
 #define LTC_PAD_MASK       (0xF000U)
 
+#if defined(ENDIAN_64BITWORD)
+   #define CONSTPTR(n) CONST64(n)
+#else
+   #define CONSTPTR(n) n ## uL
+#endif
+
+/* Poor-man's `uintptr_t` since we can't use stdint.h
+ * c.f. https://github.com/DCIT/perl-CryptX/issues/95#issuecomment-1745280962 */
+typedef size_t ltc_uintptr;
+
+/* Aligns a `unsigned char` buffer `buf` to `n` bytes and returns that aligned address.
+ * Make sure that the buffer that is passed is huge enough.
+ */
+#define LTC_ALIGN_BUF(buf, n) ((void*)((ltc_uintptr)&(buf)[n - 1] & (~(CONSTPTR(n) - CONSTPTR(1)))))
+
 /* `NULL` as defined by the standard is not guaranteed to be of a pointer
  * type. In order to make sure that in vararg API's a pointer type is used,
  * define our own version and use that one internally.