Fix ARM CE byte ordering, expand C/C++ API, and harden build

ARM backends: fix round key byte-swap on little-endian (vrev32q_u8),
rewrite decrypt to pre-process middle keys with InvMixColumns, fix
GHASH PMULL reflect and reduction ordering.

API: add nonce/IV-generating convenience overloads for CTR, CBC, and
GCM (library generates and prepends nonce, appends tag). Add C API
for IV/nonce generation. Rename error codes (TINYAES_OK, Result::Ok,
Result::AuthenticationFailed, etc.).

Build: add MinGW GCC AVX-512 debug alignment fix, harden bench/fuzz
CMake targets (warnings-as-errors, linker hardening), align with
tinysha CMake conventions. Add README.

Tests: expand coverage for nonce-generating API overloads, add NIST
GCM test vectors, improve fuzz target differential testing.
This commit is contained in:
Brandon Lehmann
2026-02-24 21:57:00 -05:00
parent cc49624c7a
commit b4df5d078a
30 changed files with 1646 additions and 277 deletions

View File

@@ -12,7 +12,7 @@ TEST(ctr_aes128_encrypt)
{
std::vector<uint8_t> ct;
auto result = tinyaes::ctr_crypt(VEC(ctr_128_key), VEC(ctr_128_iv), VEC(ctr_128_plain), ct);
ASSERT_TRUE(result == tinyaes::Result::Success);
ASSERT_TRUE(result == tinyaes::Result::Ok);
ASSERT_EQ(ct, VEC(ctr_128_cipher));
}
@@ -20,7 +20,7 @@ TEST(ctr_aes128_decrypt)
{
std::vector<uint8_t> pt;
auto result = tinyaes::ctr_crypt(VEC(ctr_128_key), VEC(ctr_128_iv), VEC(ctr_128_cipher), pt);
ASSERT_TRUE(result == tinyaes::Result::Success);
ASSERT_TRUE(result == tinyaes::Result::Ok);
ASSERT_EQ(pt, VEC(ctr_128_plain));
}
@@ -28,7 +28,7 @@ TEST(ctr_aes192_encrypt)
{
std::vector<uint8_t> ct;
auto result = tinyaes::ctr_crypt(VEC(ctr_192_key), VEC(ctr_192_iv), VEC(ctr_192_plain), ct);
ASSERT_TRUE(result == tinyaes::Result::Success);
ASSERT_TRUE(result == tinyaes::Result::Ok);
ASSERT_EQ(ct, VEC(ctr_192_cipher));
}
@@ -36,7 +36,7 @@ TEST(ctr_aes256_encrypt)
{
std::vector<uint8_t> ct;
auto result = tinyaes::ctr_crypt(VEC(ctr_256_key), VEC(ctr_256_iv), VEC(ctr_256_plain), ct);
ASSERT_TRUE(result == tinyaes::Result::Success);
ASSERT_TRUE(result == tinyaes::Result::Ok);
ASSERT_EQ(ct, VEC(ctr_256_cipher));
}
@@ -49,12 +49,12 @@ TEST(ctr_partial_block)
std::vector<uint8_t> ct, pt;
auto result = tinyaes::ctr_crypt(key, iv, plaintext, ct);
ASSERT_TRUE(result == tinyaes::Result::Success);
ASSERT_TRUE(result == tinyaes::Result::Ok);
ASSERT_TRUE(ct.size() == 7);
// Decrypt should recover original
result = tinyaes::ctr_crypt(key, iv, ct, pt);
ASSERT_TRUE(result == tinyaes::Result::Success);
ASSERT_TRUE(result == tinyaes::Result::Ok);
ASSERT_EQ(pt, plaintext);
}
@@ -66,12 +66,76 @@ TEST(ctr_roundtrip_multi_block)
std::vector<uint8_t> ct, pt;
auto result = tinyaes::ctr_crypt(key, iv, plaintext, ct);
ASSERT_TRUE(result == tinyaes::Result::Success);
ASSERT_TRUE(result == tinyaes::Result::Ok);
ASSERT_TRUE(ct.size() == 100);
result = tinyaes::ctr_crypt(key, iv, ct, pt);
ASSERT_TRUE(result == tinyaes::Result::Success);
ASSERT_TRUE(result == tinyaes::Result::Ok);
ASSERT_EQ(pt, plaintext);
}
TEST(ctr_zero_length_plaintext)
{
std::vector<uint8_t> key(16, 0x42);
std::vector<uint8_t> iv(16, 0x00);
std::vector<uint8_t> plaintext;
std::vector<uint8_t> ct;
auto result = tinyaes::ctr_crypt(key, iv, plaintext, ct);
ASSERT_TRUE(result == tinyaes::Result::InvalidInputSize);
}
TEST(ctr_invalid_nonce_size)
{
std::vector<uint8_t> key(16, 0x42);
std::vector<uint8_t> nonce(10, 0x00); // wrong size
std::vector<uint8_t> plaintext = {0x01, 0x02, 0x03};
std::vector<uint8_t> ct;
auto result = tinyaes::ctr_encrypt(key, nonce, plaintext, ct);
ASSERT_TRUE(result == tinyaes::Result::InvalidNonceSize);
}
TEST(ctr_nonce_encrypt_decrypt_roundtrip)
{
std::vector<uint8_t> key(16, 0x42);
std::vector<uint8_t> nonce(12, 0x01);
std::vector<uint8_t> plaintext = {0x48, 0x65, 0x6c, 0x6c, 0x6f};
std::vector<uint8_t> ct, pt;
auto result = tinyaes::ctr_encrypt(key, nonce, plaintext, ct);
ASSERT_TRUE(result == tinyaes::Result::Ok);
ASSERT_TRUE(ct.size() == 5);
result = tinyaes::ctr_decrypt(key, nonce, ct, pt);
ASSERT_TRUE(result == tinyaes::Result::Ok);
ASSERT_EQ(pt, plaintext);
}
TEST(ctr_auto_nonce_roundtrip)
{
std::vector<uint8_t> key(16, 0x42);
std::vector<uint8_t> plaintext = {0x48, 0x65, 0x6c, 0x6c, 0x6f};
std::vector<uint8_t> nonce_ct, pt;
auto result = tinyaes::ctr_encrypt(key, plaintext, nonce_ct);
ASSERT_TRUE(result == tinyaes::Result::Ok);
ASSERT_TRUE(nonce_ct.size() == 17); // 12 nonce + 5 ciphertext
result = tinyaes::ctr_decrypt(key, nonce_ct, pt);
ASSERT_TRUE(result == tinyaes::Result::Ok);
ASSERT_EQ(pt, plaintext);
}
TEST(ctr_invalid_key_size)
{
std::vector<uint8_t> key(15, 0x42); // invalid: not 16/24/32
std::vector<uint8_t> iv(16, 0x00);
std::vector<uint8_t> plaintext = {0x01, 0x02, 0x03};
std::vector<uint8_t> ct;
auto result = tinyaes::ctr_crypt(key, iv, plaintext, ct);
ASSERT_TRUE(result == tinyaes::Result::InvalidKeySize);
}
#undef VEC