Skip to content

Commit

Permalink
Fix AES on PPCBE (32-bit and 64-bit). (aws#1213)
Browse files Browse the repository at this point in the history
- Only compact_block and uncompact_block functions handled the input and output and were the only ones needing change.
- It was deemed unnecessary to create the correct order of key rounds in AES_KEY. The order of each 2 subsequent 32-bit round keys is flipped, but because they get read again into 64-bit words where they are re-ordered correctly, the calculations proceed successfully.
- In aes_nohw_compact_block, we opted to reduce the work done in the case of the little-endian build by
using macros to restrict the use of load_u64 only in the case of big-endian build, though it would have worked correctly in little-endian build.
- Support for PPCBE32 is included.
  • Loading branch information
nebeid authored Oct 27, 2023
1 parent 04fa153 commit 8836748
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 20 deletions.
12 changes: 5 additions & 7 deletions crypto/endian_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,10 @@ TEST(EndianTest, BN_bn2bin_padded) {

TEST(EndianTest, AES) {
// Initialize the key and message buffers with zeros
uint8_t key[AES_BLOCK_SIZE] = {0};
key[0] = 0xaa;
key[1] = 0xbb;
uint8_t message[AES_BLOCK_SIZE] = {0};
message[0] = 0xcc;
message[1] = 0xdd;
uint8_t key[16] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33,
0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x50};
uint8_t message[AES_BLOCK_SIZE] = {0x50, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99};

// Allocate buffer to store the encrypted message
uint8_t encrypted_message[AES_BLOCK_SIZE];
Expand All @@ -286,7 +284,7 @@ TEST(EndianTest, AES) {
AES_encrypt(message, encrypted_message, &aes_key);

const uint8_t known_value_bytes[AES_BLOCK_SIZE] = {
0xf6, 0x8a, 0x88, 0x76, 0x05, 0x23, 0xd4, 0x14, 0x7e, 0x5a, 0xb8, 0x52, 0x8f, 0x56, 0x62, 0x3e
0x5e, 0x3e, 0x8e, 0x76, 0xf4, 0xf2, 0x7d, 0x41, 0x35, 0x86, 0x96, 0xb5, 0x57, 0x2d, 0xd5, 0xc6
};
EXPECT_EQ(Bytes(known_value_bytes), Bytes(encrypted_message));
}
Expand Down
24 changes: 18 additions & 6 deletions crypto/fipsmodule/aes/aes_nohw.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,15 +349,27 @@ static inline void aes_nohw_compact_block(aes_word_t out[AES_NOHW_BLOCK_WORDS],
#if defined(OPENSSL_SSE2)
// No conversions needed.
#elif defined(OPENSSL_64_BIT)
#if defined(OPENSSL_BIG_ENDIAN)
uint64_t a0 = aes_nohw_compact_word(CRYPTO_load_u64_le(&out[0]));
uint64_t a1 = aes_nohw_compact_word(CRYPTO_load_u64_le(&out[1]));
#else
uint64_t a0 = aes_nohw_compact_word(out[0]);
uint64_t a1 = aes_nohw_compact_word(out[1]);
#endif
out[0] = (a0 & UINT64_C(0x00000000ffffffff)) | (a1 << 32);
out[1] = (a1 & UINT64_C(0xffffffff00000000)) | (a0 >> 32);
#else
#if defined(OPENSSL_BIG_ENDIAN)
uint32_t a0 = aes_nohw_compact_word(CRYPTO_load_u32_le(&out[0]));
uint32_t a1 = aes_nohw_compact_word(CRYPTO_load_u32_le(&out[1]));
uint32_t a2 = aes_nohw_compact_word(CRYPTO_load_u32_le(&out[2]));
uint32_t a3 = aes_nohw_compact_word(CRYPTO_load_u32_le(&out[3]));
#else
uint32_t a0 = aes_nohw_compact_word(out[0]);
uint32_t a1 = aes_nohw_compact_word(out[1]);
uint32_t a2 = aes_nohw_compact_word(out[2]);
uint32_t a3 = aes_nohw_compact_word(out[3]);
#endif
// Note clang, when building for ARM Thumb2, will sometimes miscompile
// expressions such as (a0 & 0x0000ff00) << 8, particularly when building
// without optimizations. This bug was introduced in
Expand All @@ -381,8 +393,8 @@ static inline void aes_nohw_uncompact_block(
aes_nohw_uncompact_word((a0 & UINT64_C(0x00000000ffffffff)) | (a1 << 32));
uint64_t b1 =
aes_nohw_uncompact_word((a1 & UINT64_C(0xffffffff00000000)) | (a0 >> 32));
memcpy(out, &b0, 8);
memcpy(out + 8, &b1, 8);
CRYPTO_store_u64_le(&out[0], b0);
CRYPTO_store_u64_le(&out[8], b1);
#else
uint32_t a0 = in[0];
uint32_t a1 = in[1];
Expand All @@ -403,10 +415,10 @@ static inline void aes_nohw_uncompact_block(
b1 = aes_nohw_uncompact_word(b1);
b2 = aes_nohw_uncompact_word(b2);
b3 = aes_nohw_uncompact_word(b3);
memcpy(out, &b0, 4);
memcpy(out + 4, &b1, 4);
memcpy(out + 8, &b2, 4);
memcpy(out + 12, &b3, 4);
CRYPTO_store_u32_le(&out[0], b0);
CRYPTO_store_u32_le(&out[4], b1);
CRYPTO_store_u32_le(&out[8], b2);
CRYPTO_store_u32_le(&out[12], b3);
#endif
}

Expand Down
4 changes: 2 additions & 2 deletions crypto/fipsmodule/cipher/aead.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,8 @@ int EVP_AEAD_get_iv_from_ipv4_nanosecs(
return 0;
}

OPENSSL_memcpy(out_iv, &ipv4_address, sizeof(ipv4_address));
OPENSSL_memcpy(out_iv + sizeof(ipv4_address), &nanosecs, sizeof(nanosecs));
CRYPTO_store_u32_le(&out_iv[0], ipv4_address);
CRYPTO_store_u64_le(&out_iv[sizeof(ipv4_address)], nanosecs);

return 1;
}
Expand Down
29 changes: 26 additions & 3 deletions crypto/fipsmodule/modes/xts.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ size_t CRYPTO_xts128_encrypt(const XTS128_CONTEXT *ctx,
uint8_t *out, size_t len, int enc) {
union {
uint64_t u[2];
uint32_t d[4];
uint8_t c[16];
} tweak, scratch;
unsigned int i;
Expand Down Expand Up @@ -91,10 +90,22 @@ size_t CRYPTO_xts128_encrypt(const XTS128_CONTEXT *ctx,

unsigned int carry, res;

res = 0x87 & (((int)tweak.d[3]) >> 31);
#if defined(OPENSSL_BIG_ENDIAN)
uint64_t tweak_u0, tweak_u1;
tweak_u0 = CRYPTO_load_u64_le(&tweak.u[0]);
tweak_u1 = CRYPTO_load_u64_le(&tweak.u[1]);
res = 0x87 & (((int64_t)tweak_u1) >> 63);
carry = (unsigned int)(tweak_u0 >> 63);
tweak_u0 = (tweak_u0 << 1) ^ res;
tweak_u1 = (tweak_u1 << 1) | carry;
CRYPTO_store_u64_le(&tweak.u[0], tweak_u0);
CRYPTO_store_u64_le(&tweak.u[1], tweak_u1);
#else
res = 0x87 & (((int64_t)tweak.u[1]) >> 63);
carry = (unsigned int)(tweak.u[0] >> 63);
tweak.u[0] = (tweak.u[0] << 1) ^ res;
tweak.u[1] = (tweak.u[1] << 1) | carry;
#endif
}
if (enc) {
for (i = 0; i < len; ++i) {
Expand All @@ -116,10 +127,22 @@ size_t CRYPTO_xts128_encrypt(const XTS128_CONTEXT *ctx,

unsigned int carry, res;

res = 0x87 & (((int)tweak.d[3]) >> 31);
#if defined(OPENSSL_BIG_ENDIAN)
uint64_t tweak_u0, tweak_u1;
tweak_u0 = CRYPTO_load_u64_le(&tweak.u[0]);
tweak_u1 = CRYPTO_load_u64_le(&tweak.u[1]);
res = 0x87 & (((int64_t)tweak_u1) >> 63);
carry = (unsigned int)(tweak_u0 >> 63);
tweak_u0 = (tweak_u0 << 1) ^ res;
tweak_u1 = (tweak_u1 << 1) | carry;
CRYPTO_store_u64_le(&tweak1.u[0], tweak_u0);
CRYPTO_store_u64_le(&tweak1.u[1], tweak_u1);
#else
res = 0x87 & (((int64_t)tweak.u[1]) >> 63);
carry = (unsigned int)(tweak.u[0] >> 63);
tweak1.u[0] = (tweak.u[0] << 1) ^ res;
tweak1.u[1] = (tweak.u[1] << 1) | carry;
#endif
OPENSSL_memcpy(scratch.c, inp, 16);
scratch.u[0] ^= tweak1.u[0];
scratch.u[1] ^= tweak1.u[1];
Expand Down
4 changes: 2 additions & 2 deletions include/openssl/aead.h
Original file line number Diff line number Diff line change
Expand Up @@ -466,8 +466,8 @@ OPENSSL_EXPORT int EVP_AEAD_CTX_tag_len(const EVP_AEAD_CTX *ctx,

// EVP_AEAD_get_iv_from_ipv4_nanosecs computes a deterministic IV compliant with
// NIST SP 800-38D, built from an IPv4 address and the number of nanoseconds
// since boot, writing it to |out_iv|. It returns one on success or zero for
// error.
// since boot, writing it to |out_iv| (in little endian).
// It returns one on success or zero for error.
//
// This is not a general-purpose API, you should not be using it unless you
// specifically know you need to use this.
Expand Down

0 comments on commit 8836748

Please sign in to comment.