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:
@@ -30,6 +30,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
set_property(TARGET tinyaes_tests APPEND_STRING PROPERTY LINK_FLAGS
|
||||
" -Wl,-z,relro,-z,now -Wl,-z,noexecstack")
|
||||
endif()
|
||||
# macOS: -bind_at_load is deprecated on modern macOS (eager binding is the default)
|
||||
if(MINGW)
|
||||
set_property(TARGET tinyaes_tests APPEND_STRING PROPERTY LINK_FLAGS
|
||||
" -Wl,--nxcompat -Wl,--dynamicbase -Wl,--high-entropy-va")
|
||||
|
||||
@@ -12,7 +12,7 @@ TEST(cbc_aes128_encrypt)
|
||||
{
|
||||
std::vector<uint8_t> ct;
|
||||
auto result = tinyaes::cbc_encrypt(VEC(cbc_128_key), VEC(cbc_128_iv), VEC(cbc_128_plain), ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(ct, VEC(cbc_128_cipher));
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ TEST(cbc_aes128_decrypt)
|
||||
{
|
||||
std::vector<uint8_t> pt;
|
||||
auto result = tinyaes::cbc_decrypt(VEC(cbc_128_key), VEC(cbc_128_iv), VEC(cbc_128_cipher), pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, VEC(cbc_128_plain));
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ TEST(cbc_aes192_encrypt)
|
||||
{
|
||||
std::vector<uint8_t> ct;
|
||||
auto result = tinyaes::cbc_encrypt(VEC(cbc_192_key), VEC(cbc_192_iv), VEC(cbc_192_plain), ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(ct, VEC(cbc_192_cipher));
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ TEST(cbc_aes192_decrypt)
|
||||
{
|
||||
std::vector<uint8_t> pt;
|
||||
auto result = tinyaes::cbc_decrypt(VEC(cbc_192_key), VEC(cbc_192_iv), VEC(cbc_192_cipher), pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, VEC(cbc_192_plain));
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ TEST(cbc_aes256_encrypt)
|
||||
{
|
||||
std::vector<uint8_t> ct;
|
||||
auto result = tinyaes::cbc_encrypt(VEC(cbc_256_key), VEC(cbc_256_iv), VEC(cbc_256_plain), ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(ct, VEC(cbc_256_cipher));
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ TEST(cbc_aes256_decrypt)
|
||||
{
|
||||
std::vector<uint8_t> pt;
|
||||
auto result = tinyaes::cbc_decrypt(VEC(cbc_256_key), VEC(cbc_256_iv), VEC(cbc_256_cipher), pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, VEC(cbc_256_plain));
|
||||
}
|
||||
|
||||
@@ -64,18 +64,66 @@ TEST(cbc_roundtrip_pkcs7)
|
||||
std::vector<uint8_t> ct, pt;
|
||||
|
||||
auto result = tinyaes::cbc_encrypt_pkcs7(key, iv, plaintext, ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(ct.size() == 16); // 5 bytes + 11 padding = 16
|
||||
|
||||
result = tinyaes::cbc_decrypt_pkcs7(key, iv, ct, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, plaintext);
|
||||
}
|
||||
|
||||
TEST(cbc_invalid_iv_size)
|
||||
{
|
||||
std::vector<uint8_t> key(16, 0), iv(15, 0), pt(16, 0), ct;
|
||||
ASSERT_TRUE(tinyaes::cbc_encrypt(key, iv, pt, ct) == tinyaes::Result::InvalidInput);
|
||||
ASSERT_TRUE(tinyaes::cbc_encrypt(key, iv, pt, ct) == tinyaes::Result::InvalidIVSize);
|
||||
}
|
||||
|
||||
TEST(cbc_non_block_aligned_no_padding)
|
||||
{
|
||||
std::vector<uint8_t> key(16, 0), iv(16, 0), pt(17, 0), ct;
|
||||
ASSERT_TRUE(tinyaes::cbc_encrypt(key, iv, pt, ct) == tinyaes::Result::InvalidInputSize);
|
||||
}
|
||||
|
||||
TEST(cbc_multi_block_roundtrip_no_padding)
|
||||
{
|
||||
std::vector<uint8_t> key(16, 0x42);
|
||||
std::vector<uint8_t> iv(16, 0x00);
|
||||
std::vector<uint8_t> plaintext(64, 0x55); // 4 blocks
|
||||
std::vector<uint8_t> ct, pt;
|
||||
|
||||
auto result = tinyaes::cbc_encrypt(key, iv, plaintext, ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(ct.size() == 64);
|
||||
|
||||
result = tinyaes::cbc_decrypt(key, iv, ct, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, plaintext);
|
||||
}
|
||||
|
||||
TEST(cbc_auto_iv_roundtrip)
|
||||
{
|
||||
std::vector<uint8_t> key(16, 0x42);
|
||||
std::vector<uint8_t> plaintext = {0x48, 0x65, 0x6c, 0x6c, 0x6f};
|
||||
std::vector<uint8_t> iv_ct, pt;
|
||||
|
||||
auto result = tinyaes::cbc_encrypt_pkcs7(key, plaintext, iv_ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(iv_ct.size() >= 32); // 16 IV + at least 16 ciphertext
|
||||
|
||||
result = tinyaes::cbc_decrypt_pkcs7(key, iv_ct, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, plaintext);
|
||||
}
|
||||
|
||||
TEST(cbc_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(16, 0x55);
|
||||
std::vector<uint8_t> ct;
|
||||
|
||||
auto result = tinyaes::cbc_encrypt(key, iv, plaintext, ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::InvalidKeySize);
|
||||
}
|
||||
|
||||
#undef VEC
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -12,7 +12,7 @@ TEST(ecb_aes128_encrypt)
|
||||
{
|
||||
std::vector<uint8_t> ct;
|
||||
auto result = tinyaes::ecb_encrypt(VEC(ecb_128_key), VEC(ecb_128_plain), ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(ct, VEC(ecb_128_cipher));
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ TEST(ecb_aes128_decrypt)
|
||||
{
|
||||
std::vector<uint8_t> pt;
|
||||
auto result = tinyaes::ecb_decrypt(VEC(ecb_128_key), VEC(ecb_128_cipher), pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, VEC(ecb_128_plain));
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ TEST(ecb_aes192_encrypt)
|
||||
{
|
||||
std::vector<uint8_t> ct;
|
||||
auto result = tinyaes::ecb_encrypt(VEC(ecb_192_key), VEC(ecb_192_plain), ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(ct, VEC(ecb_192_cipher));
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ TEST(ecb_aes192_decrypt)
|
||||
{
|
||||
std::vector<uint8_t> pt;
|
||||
auto result = tinyaes::ecb_decrypt(VEC(ecb_192_key), VEC(ecb_192_cipher), pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, VEC(ecb_192_plain));
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ TEST(ecb_aes256_encrypt)
|
||||
{
|
||||
std::vector<uint8_t> ct;
|
||||
auto result = tinyaes::ecb_encrypt(VEC(ecb_256_key), VEC(ecb_256_plain), ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(ct, VEC(ecb_256_cipher));
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ TEST(ecb_aes256_decrypt)
|
||||
{
|
||||
std::vector<uint8_t> pt;
|
||||
auto result = tinyaes::ecb_decrypt(VEC(ecb_256_key), VEC(ecb_256_cipher), pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, VEC(ecb_256_plain));
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ TEST(ecb_aes128_multi_block)
|
||||
{
|
||||
std::vector<uint8_t> ct;
|
||||
auto result = tinyaes::ecb_encrypt(VEC(ecb_128_multi_key), VEC(ecb_128_multi_plain), ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(ct, VEC(ecb_128_multi_cipher));
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ TEST(ecb_aes128_multi_block_decrypt)
|
||||
{
|
||||
std::vector<uint8_t> pt;
|
||||
auto result = tinyaes::ecb_decrypt(VEC(ecb_128_multi_key), VEC(ecb_128_multi_cipher), pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, VEC(ecb_128_multi_plain));
|
||||
}
|
||||
|
||||
@@ -81,13 +81,13 @@ TEST(ecb_invalid_key_size)
|
||||
TEST(ecb_non_block_aligned)
|
||||
{
|
||||
std::vector<uint8_t> key(16, 0), pt(17, 0), ct;
|
||||
ASSERT_TRUE(tinyaes::ecb_encrypt(key, pt, ct) == tinyaes::Result::InvalidInput);
|
||||
ASSERT_TRUE(tinyaes::ecb_encrypt(key, pt, ct) == tinyaes::Result::InvalidInputSize);
|
||||
}
|
||||
|
||||
TEST(ecb_empty_input)
|
||||
{
|
||||
std::vector<uint8_t> key(16, 0), pt, ct;
|
||||
ASSERT_TRUE(tinyaes::ecb_encrypt(key, pt, ct) == tinyaes::Result::InvalidInput);
|
||||
ASSERT_TRUE(tinyaes::ecb_encrypt(key, pt, ct) == tinyaes::Result::InvalidInputSize);
|
||||
}
|
||||
|
||||
#undef VEC
|
||||
|
||||
@@ -13,7 +13,7 @@ TEST(gcm_tc1_aes128_no_plaintext_no_aad)
|
||||
{
|
||||
std::vector<uint8_t> ct, tag;
|
||||
auto result = tinyaes::gcm_encrypt(VEC(gcm_tc1_key), VEC(gcm_tc1_iv), EMPTY_VEC, EMPTY_VEC, ct, tag);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(ct.empty());
|
||||
ASSERT_EQ(tag, VEC(gcm_tc1_tag));
|
||||
}
|
||||
@@ -22,7 +22,7 @@ TEST(gcm_tc2_aes128_16byte_plaintext)
|
||||
{
|
||||
std::vector<uint8_t> ct, tag;
|
||||
auto result = tinyaes::gcm_encrypt(VEC(gcm_tc2_key), VEC(gcm_tc2_iv), EMPTY_VEC, VEC(gcm_tc2_plain), ct, tag);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(ct, VEC(gcm_tc2_cipher));
|
||||
ASSERT_EQ(tag, VEC(gcm_tc2_tag));
|
||||
}
|
||||
@@ -31,7 +31,7 @@ TEST(gcm_tc3_aes128_64byte_plaintext)
|
||||
{
|
||||
std::vector<uint8_t> ct, tag;
|
||||
auto result = tinyaes::gcm_encrypt(VEC(gcm_tc3_key), VEC(gcm_tc3_iv), EMPTY_VEC, VEC(gcm_tc3_plain), ct, tag);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(ct, VEC(gcm_tc3_cipher));
|
||||
ASSERT_EQ(tag, VEC(gcm_tc3_tag));
|
||||
}
|
||||
@@ -41,7 +41,7 @@ TEST(gcm_tc4_aes128_with_aad)
|
||||
std::vector<uint8_t> ct, tag;
|
||||
auto result =
|
||||
tinyaes::gcm_encrypt(VEC(gcm_tc4_key), VEC(gcm_tc4_iv), VEC(gcm_tc4_aad), VEC(gcm_tc4_plain), ct, tag);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(ct, VEC(gcm_tc4_cipher));
|
||||
ASSERT_EQ(tag, VEC(gcm_tc4_tag));
|
||||
}
|
||||
@@ -50,7 +50,7 @@ TEST(gcm_tc13_aes256_no_plaintext_no_aad)
|
||||
{
|
||||
std::vector<uint8_t> ct, tag;
|
||||
auto result = tinyaes::gcm_encrypt(VEC(gcm_tc13_key), VEC(gcm_tc13_iv), EMPTY_VEC, EMPTY_VEC, ct, tag);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(ct.empty());
|
||||
ASSERT_EQ(tag, VEC(gcm_tc13_tag));
|
||||
}
|
||||
@@ -59,7 +59,7 @@ TEST(gcm_tc14_aes256_16byte_plaintext)
|
||||
{
|
||||
std::vector<uint8_t> ct, tag;
|
||||
auto result = tinyaes::gcm_encrypt(VEC(gcm_tc14_key), VEC(gcm_tc14_iv), EMPTY_VEC, VEC(gcm_tc14_plain), ct, tag);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(ct, VEC(gcm_tc14_cipher));
|
||||
ASSERT_EQ(tag, VEC(gcm_tc14_tag));
|
||||
}
|
||||
@@ -69,7 +69,7 @@ TEST(gcm_tc2_decrypt_verify)
|
||||
std::vector<uint8_t> pt;
|
||||
auto result =
|
||||
tinyaes::gcm_decrypt(VEC(gcm_tc2_key), VEC(gcm_tc2_iv), EMPTY_VEC, VEC(gcm_tc2_cipher), VEC(gcm_tc2_tag), pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, VEC(gcm_tc2_plain));
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ TEST(gcm_tc3_decrypt_verify)
|
||||
std::vector<uint8_t> pt;
|
||||
auto result =
|
||||
tinyaes::gcm_decrypt(VEC(gcm_tc3_key), VEC(gcm_tc3_iv), EMPTY_VEC, VEC(gcm_tc3_cipher), VEC(gcm_tc3_tag), pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, VEC(gcm_tc3_plain));
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ TEST(gcm_tc4_decrypt_verify)
|
||||
std::vector<uint8_t> pt;
|
||||
auto result = tinyaes::gcm_decrypt(VEC(gcm_tc4_key), VEC(gcm_tc4_iv), VEC(gcm_tc4_aad), VEC(gcm_tc4_cipher),
|
||||
VEC(gcm_tc4_tag), pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, VEC(gcm_tc4_plain));
|
||||
}
|
||||
|
||||
@@ -100,12 +100,128 @@ TEST(gcm_roundtrip)
|
||||
std::vector<uint8_t> ct, tag, pt;
|
||||
|
||||
auto result = tinyaes::gcm_encrypt(key, iv, aad, plaintext, ct, tag);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
|
||||
result = tinyaes::gcm_decrypt(key, iv, aad, ct, tag, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, plaintext);
|
||||
}
|
||||
|
||||
TEST(gcm_invalid_nonce_size)
|
||||
{
|
||||
std::vector<uint8_t> key(16, 0x42);
|
||||
std::vector<uint8_t> iv; // empty
|
||||
std::vector<uint8_t> plaintext = {0x01};
|
||||
std::vector<uint8_t> ct, tag;
|
||||
|
||||
auto result = tinyaes::gcm_encrypt(key, iv, EMPTY_VEC, plaintext, ct, tag);
|
||||
ASSERT_TRUE(result == tinyaes::Result::InvalidIVSize);
|
||||
}
|
||||
|
||||
TEST(gcm_combined_ct_tag_roundtrip)
|
||||
{
|
||||
std::vector<uint8_t> key(16, 0x42);
|
||||
std::vector<uint8_t> nonce(12, 0x01);
|
||||
std::vector<uint8_t> aad = {0xAA, 0xBB};
|
||||
std::vector<uint8_t> plaintext = {0x48, 0x65, 0x6c, 0x6c, 0x6f};
|
||||
std::vector<uint8_t> ct_tag, pt;
|
||||
|
||||
auto result = tinyaes::gcm_encrypt(key, nonce, plaintext, aad, ct_tag);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(ct_tag.size() == 21); // 5 ct + 16 tag
|
||||
|
||||
result = tinyaes::gcm_decrypt(key, nonce, ct_tag, aad, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, plaintext);
|
||||
}
|
||||
|
||||
TEST(gcm_auto_nonce_roundtrip)
|
||||
{
|
||||
std::vector<uint8_t> key(16, 0x42);
|
||||
std::vector<uint8_t> aad = {0xCC};
|
||||
std::vector<uint8_t> plaintext = {0x48, 0x65, 0x6c, 0x6c, 0x6f};
|
||||
std::vector<uint8_t> nonce_ct_tag, pt;
|
||||
|
||||
auto result = tinyaes::gcm_encrypt(key, plaintext, aad, nonce_ct_tag);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(nonce_ct_tag.size() == 33); // 12 nonce + 5 ct + 16 tag
|
||||
|
||||
result = tinyaes::gcm_decrypt(key, nonce_ct_tag, aad, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, plaintext);
|
||||
}
|
||||
|
||||
TEST(gcm_invalid_key_size)
|
||||
{
|
||||
std::vector<uint8_t> key(15, 0x42); // invalid: not 16/24/32
|
||||
std::vector<uint8_t> iv(12, 0x01);
|
||||
std::vector<uint8_t> plaintext = {0x01};
|
||||
std::vector<uint8_t> ct, tag;
|
||||
|
||||
auto result = tinyaes::gcm_encrypt(key, iv, EMPTY_VEC, plaintext, ct, tag);
|
||||
ASSERT_TRUE(result == tinyaes::Result::InvalidKeySize);
|
||||
}
|
||||
|
||||
TEST(gcm_aad_only_no_plaintext)
|
||||
{
|
||||
std::vector<uint8_t> key(16, 0x42);
|
||||
std::vector<uint8_t> iv(12, 0x01);
|
||||
std::vector<uint8_t> aad = {0xAA, 0xBB, 0xCC, 0xDD};
|
||||
std::vector<uint8_t> ct, tag, pt;
|
||||
|
||||
auto result = tinyaes::gcm_encrypt(key, iv, aad, EMPTY_VEC, ct, tag);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(ct.empty());
|
||||
ASSERT_TRUE(tag.size() == 16);
|
||||
|
||||
// Decrypt with correct AAD
|
||||
result = tinyaes::gcm_decrypt(key, iv, aad, ct, tag, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(pt.empty());
|
||||
|
||||
// Tampered AAD must fail
|
||||
std::vector<uint8_t> bad_aad = aad;
|
||||
bad_aad[0] ^= 0x01;
|
||||
result = tinyaes::gcm_decrypt(key, iv, bad_aad, ct, tag, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::AuthenticationFailed);
|
||||
}
|
||||
|
||||
TEST(gcm_tc7_aes192_no_plaintext_no_aad)
|
||||
{
|
||||
std::vector<uint8_t> ct, tag;
|
||||
auto result = tinyaes::gcm_encrypt(VEC(gcm_tc7_key), VEC(gcm_tc7_iv), EMPTY_VEC, EMPTY_VEC, ct, tag);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(ct.empty());
|
||||
ASSERT_EQ(tag, VEC(gcm_tc7_tag));
|
||||
}
|
||||
|
||||
TEST(gcm_tc8_aes192_16byte_plaintext)
|
||||
{
|
||||
std::vector<uint8_t> ct, tag;
|
||||
auto result = tinyaes::gcm_encrypt(VEC(gcm_tc8_key), VEC(gcm_tc8_iv), EMPTY_VEC, VEC(gcm_tc8_plain), ct, tag);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(ct, VEC(gcm_tc8_cipher));
|
||||
ASSERT_EQ(tag, VEC(gcm_tc8_tag));
|
||||
}
|
||||
|
||||
TEST(gcm_tc8_decrypt_verify)
|
||||
{
|
||||
std::vector<uint8_t> pt;
|
||||
auto result =
|
||||
tinyaes::gcm_decrypt(VEC(gcm_tc8_key), VEC(gcm_tc8_iv), EMPTY_VEC, VEC(gcm_tc8_cipher), VEC(gcm_tc8_tag), pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, VEC(gcm_tc8_plain));
|
||||
}
|
||||
|
||||
TEST(gcm_tc8_tampered_tag)
|
||||
{
|
||||
std::vector<uint8_t> bad_tag = VEC(gcm_tc8_tag);
|
||||
bad_tag[0] ^= 0x01;
|
||||
std::vector<uint8_t> pt;
|
||||
auto result =
|
||||
tinyaes::gcm_decrypt(VEC(gcm_tc8_key), VEC(gcm_tc8_iv), EMPTY_VEC, VEC(gcm_tc8_cipher), bad_tag, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::AuthenticationFailed);
|
||||
}
|
||||
|
||||
#undef VEC
|
||||
#undef EMPTY_VEC
|
||||
|
||||
@@ -35,7 +35,7 @@ TEST(gcm_auth_fail_tampered_ciphertext)
|
||||
|
||||
std::vector<uint8_t> pt;
|
||||
auto result = tinyaes::gcm_decrypt(make_key(), make_iv(), {}, ct, tag, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::AuthFailed);
|
||||
ASSERT_TRUE(result == tinyaes::Result::AuthenticationFailed);
|
||||
ASSERT_TRUE(pt.empty());
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ TEST(gcm_auth_fail_tampered_tag)
|
||||
|
||||
std::vector<uint8_t> pt;
|
||||
auto result = tinyaes::gcm_decrypt(make_key(), make_iv(), {}, ct, tag, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::AuthFailed);
|
||||
ASSERT_TRUE(result == tinyaes::Result::AuthenticationFailed);
|
||||
ASSERT_TRUE(pt.empty());
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ TEST(gcm_auth_fail_tampered_aad)
|
||||
|
||||
std::vector<uint8_t> pt;
|
||||
auto result = tinyaes::gcm_decrypt(make_key(), make_iv(), bad_aad, ct, tag, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::AuthFailed);
|
||||
ASSERT_TRUE(result == tinyaes::Result::AuthenticationFailed);
|
||||
ASSERT_TRUE(pt.empty());
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ TEST(gcm_auth_fail_wrong_key)
|
||||
|
||||
std::vector<uint8_t> pt;
|
||||
auto result = tinyaes::gcm_decrypt(wrong_key, make_iv(), {}, ct, tag, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::AuthFailed);
|
||||
ASSERT_TRUE(result == tinyaes::Result::AuthenticationFailed);
|
||||
ASSERT_TRUE(pt.empty());
|
||||
}
|
||||
|
||||
@@ -92,6 +92,6 @@ TEST(gcm_auth_fail_wrong_iv)
|
||||
|
||||
std::vector<uint8_t> pt;
|
||||
auto result = tinyaes::gcm_decrypt(make_key(), wrong_iv, {}, ct, tag, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::AuthFailed);
|
||||
ASSERT_TRUE(result == tinyaes::Result::AuthenticationFailed);
|
||||
ASSERT_TRUE(pt.empty());
|
||||
}
|
||||
|
||||
@@ -75,10 +75,10 @@ namespace test
|
||||
{
|
||||
std::fprintf(stderr, "%s:%d: ASSERT_EQ failed\n got: ", file, line);
|
||||
for (auto x : a)
|
||||
std::fprintf(stderr, "%02x", x);
|
||||
std::fprintf(stderr, "%02x", static_cast<unsigned>(x));
|
||||
std::fprintf(stderr, "\n expected: ");
|
||||
for (auto x : b)
|
||||
std::fprintf(stderr, "%02x", x);
|
||||
std::fprintf(stderr, "%02x", static_cast<unsigned>(x));
|
||||
std::fprintf(stderr, "\n");
|
||||
fail_count()++;
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@ TEST(pkcs7_full_block_padding)
|
||||
std::vector<uint8_t> ct, pt;
|
||||
|
||||
auto result = tinyaes::cbc_encrypt_pkcs7(key, iv, plaintext, ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(ct.size() == 32); // 16 data + 16 padding
|
||||
|
||||
result = tinyaes::cbc_decrypt_pkcs7(key, iv, ct, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, plaintext);
|
||||
}
|
||||
|
||||
@@ -29,11 +29,11 @@ TEST(pkcs7_single_byte)
|
||||
std::vector<uint8_t> ct, pt;
|
||||
|
||||
auto result = tinyaes::cbc_encrypt_pkcs7(key, iv, plaintext, ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(ct.size() == 16); // 1 + 15 padding
|
||||
|
||||
result = tinyaes::cbc_decrypt_pkcs7(key, iv, ct, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, plaintext);
|
||||
}
|
||||
|
||||
@@ -45,11 +45,11 @@ TEST(pkcs7_empty_plaintext)
|
||||
std::vector<uint8_t> ct, pt;
|
||||
|
||||
auto result = tinyaes::cbc_encrypt_pkcs7(key, iv, plaintext, ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(ct.size() == 16); // Full block of padding (0x10)
|
||||
|
||||
result = tinyaes::cbc_decrypt_pkcs7(key, iv, ct, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, plaintext);
|
||||
}
|
||||
|
||||
@@ -61,11 +61,11 @@ TEST(pkcs7_15_byte_plaintext)
|
||||
std::vector<uint8_t> ct, pt;
|
||||
|
||||
auto result = tinyaes::cbc_encrypt_pkcs7(key, iv, plaintext, ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(ct.size() == 16); // 15 + 1 padding byte
|
||||
|
||||
result = tinyaes::cbc_decrypt_pkcs7(key, iv, ct, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_EQ(pt, plaintext);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ TEST(pkcs7_invalid_padding_rejected)
|
||||
std::vector<uint8_t> ct, pt;
|
||||
|
||||
auto result = tinyaes::cbc_encrypt_pkcs7(key, iv, plaintext, ct);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Success);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
|
||||
// Flip a bit in the last block (padding block)
|
||||
ct.back() ^= 0x01;
|
||||
@@ -88,3 +88,25 @@ TEST(pkcs7_invalid_padding_rejected)
|
||||
result = tinyaes::cbc_decrypt_pkcs7(key, iv, ct, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::InvalidPadding);
|
||||
}
|
||||
|
||||
TEST(pkcs7_multi_position_corruption)
|
||||
{
|
||||
// Encrypt a known 16-byte plaintext, then corrupt each of the 16 positions
|
||||
// in the padding block and verify InvalidPadding for each
|
||||
std::vector<uint8_t> key(16, 0xEE);
|
||||
std::vector<uint8_t> iv(16, 0x00);
|
||||
std::vector<uint8_t> plaintext(16, 0x42);
|
||||
std::vector<uint8_t> ct_orig, pt;
|
||||
|
||||
auto result = tinyaes::cbc_encrypt_pkcs7(key, iv, plaintext, ct_orig);
|
||||
ASSERT_TRUE(result == tinyaes::Result::Ok);
|
||||
ASSERT_TRUE(ct_orig.size() == 32); // 16 data + 16 padding block
|
||||
|
||||
for (size_t i = 0; i < 16; ++i)
|
||||
{
|
||||
std::vector<uint8_t> ct = ct_orig;
|
||||
ct[16 + i] ^= 0x01; // corrupt position i of the padding block
|
||||
result = tinyaes::cbc_decrypt_pkcs7(key, iv, ct, pt);
|
||||
ASSERT_TRUE(result == tinyaes::Result::InvalidPadding);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,37 @@ static const uint8_t gcm_tc4_tag[] = {
|
||||
0x5b,0xc9,0x4f,0xbc,0x32,0x21,0xa5,0xdb,0x94,0xfa,0xe9,0x5a,0xe7,0x12,0x1a,0x47
|
||||
};
|
||||
|
||||
// Test Case 7: AES-192, no plaintext, no AAD
|
||||
static const uint8_t gcm_tc7_key[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
};
|
||||
static const uint8_t gcm_tc7_iv[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
};
|
||||
// No plaintext, no AAD, no ciphertext
|
||||
static const uint8_t gcm_tc7_tag[] = {
|
||||
0xcd,0x33,0xb2,0x8a,0xc7,0x73,0xf7,0x4b,0xa0,0x0e,0xd1,0xf3,0x12,0x57,0x24,0x35
|
||||
};
|
||||
|
||||
// Test Case 8: AES-192, 16 bytes plaintext, no AAD
|
||||
static const uint8_t gcm_tc8_key[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
};
|
||||
static const uint8_t gcm_tc8_iv[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
};
|
||||
static const uint8_t gcm_tc8_plain[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
};
|
||||
static const uint8_t gcm_tc8_cipher[] = {
|
||||
0x98,0xe7,0x24,0x7c,0x07,0xf0,0xfe,0x41,0x1c,0x26,0x7e,0x43,0x84,0xb0,0xf6,0x00
|
||||
};
|
||||
static const uint8_t gcm_tc8_tag[] = {
|
||||
0x2f,0xf5,0x8d,0x80,0x03,0x39,0x27,0xab,0x8e,0xf4,0xd4,0x58,0x75,0x14,0xf0,0xfb
|
||||
};
|
||||
|
||||
// Test Case 13: AES-256, no plaintext, no AAD
|
||||
static const uint8_t gcm_tc13_key[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
|
||||
Reference in New Issue
Block a user