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

@@ -106,6 +106,18 @@ namespace tinyaes
const std::vector<uint8_t> &ciphertext,
std::vector<uint8_t> &plaintext);
// CBC encrypt with PKCS#7 — library generates IV, prepended to ciphertext
Result cbc_encrypt_pkcs7(
const std::vector<uint8_t> &key,
const std::vector<uint8_t> &plaintext,
std::vector<uint8_t> &iv_and_ciphertext);
// CBC decrypt with PKCS#7 — IV is first 16 bytes of input
Result cbc_decrypt_pkcs7(
const std::vector<uint8_t> &key,
const std::vector<uint8_t> &iv_and_ciphertext,
std::vector<uint8_t> &plaintext);
} // namespace tinyaes
#endif

View File

@@ -56,12 +56,14 @@
#define TINYAES_GCM_IV_SIZE 12
// C error codes
#define TINYAES_SUCCESS 0
#define TINYAES_ERROR_INVALID_KEY_SIZE (-1)
#define TINYAES_ERROR_INVALID_INPUT (-2)
#define TINYAES_ERROR_INVALID_PADDING (-3)
#define TINYAES_ERROR_AUTH_FAILED (-4)
#define TINYAES_ERROR_BUFFER_TOO_SMALL (-5)
#define TINYAES_OK 0
#define TINYAES_INVALID_KEY_SIZE (-1)
#define TINYAES_INVALID_IV_SIZE (-2)
#define TINYAES_INVALID_NONCE_SIZE (-3)
#define TINYAES_INVALID_INPUT_SIZE (-4)
#define TINYAES_INVALID_PADDING (-5)
#define TINYAES_AUTH_FAILED (-6)
#define TINYAES_INTERNAL_ERROR (-7)
#ifdef __cplusplus
extern "C"
@@ -70,6 +72,10 @@ extern "C"
TINYAES_EXPORT int tinyaes_constant_time_equal(const uint8_t *a, const uint8_t *b, size_t len);
TINYAES_EXPORT int tinyaes_generate_iv(uint8_t out[16]);
TINYAES_EXPORT int tinyaes_generate_nonce(uint8_t out[12]);
#ifdef __cplusplus
}
#endif
@@ -81,12 +87,14 @@ namespace tinyaes
enum class Result
{
Success = 0,
Ok = 0,
InvalidKeySize = -1,
InvalidInput = -2,
InvalidPadding = -3,
AuthFailed = -4,
BufferTooSmall = -5
InvalidIVSize = -2,
InvalidNonceSize = -3,
InvalidInputSize = -4,
InvalidPadding = -5,
AuthenticationFailed = -6,
InternalError = -7
};
void secure_zero(void *ptr, size_t len);
@@ -102,6 +110,10 @@ namespace tinyaes
int generate_iv(uint8_t *out, size_t len);
std::vector<uint8_t> generate_iv();
std::vector<uint8_t> generate_nonce();
} // namespace tinyaes
#endif

View File

@@ -33,7 +33,7 @@ extern "C"
{
#endif
// CTR encrypt/decrypt (symmetric operation)
// CTR encrypt/decrypt (symmetric operation) — raw 16-byte IV
TINYAES_EXPORT int tinyaes_ctr_crypt(
const uint8_t *key,
size_t key_len,
@@ -43,6 +43,26 @@ extern "C"
uint8_t *output,
size_t output_len);
// CTR encrypt — 12-byte nonce (counter starts at 1)
TINYAES_EXPORT int tinyaes_ctr_encrypt(
const uint8_t *key,
size_t key_len,
const uint8_t *nonce,
const uint8_t *plaintext,
size_t plaintext_len,
uint8_t *ciphertext,
size_t ciphertext_len);
// CTR decrypt — 12-byte nonce
TINYAES_EXPORT int tinyaes_ctr_decrypt(
const uint8_t *key,
size_t key_len,
const uint8_t *nonce,
const uint8_t *ciphertext,
size_t ciphertext_len,
uint8_t *plaintext,
size_t plaintext_len);
#ifdef __cplusplus
}
#endif
@@ -61,6 +81,32 @@ namespace tinyaes
const std::vector<uint8_t> &input,
std::vector<uint8_t> &output);
// CTR encrypt — caller provides nonce (12 bytes, counter starts at 1)
Result ctr_encrypt(
const std::vector<uint8_t> &key,
const std::vector<uint8_t> &nonce,
const std::vector<uint8_t> &plaintext,
std::vector<uint8_t> &ciphertext);
// CTR encrypt — library generates nonce, prepended to output
Result ctr_encrypt(
const std::vector<uint8_t> &key,
const std::vector<uint8_t> &plaintext,
std::vector<uint8_t> &nonce_and_ciphertext);
// CTR decrypt — caller provides nonce
Result ctr_decrypt(
const std::vector<uint8_t> &key,
const std::vector<uint8_t> &nonce,
const std::vector<uint8_t> &ciphertext,
std::vector<uint8_t> &plaintext);
// CTR decrypt — nonce is first 12 bytes of input
Result ctr_decrypt(
const std::vector<uint8_t> &key,
const std::vector<uint8_t> &nonce_and_ciphertext,
std::vector<uint8_t> &plaintext);
} // namespace tinyaes
#endif

View File

@@ -86,6 +86,36 @@ namespace tinyaes
const std::vector<uint8_t> &tag,
std::vector<uint8_t> &plaintext);
// GCM encrypt — caller provides nonce, tag appended to ciphertext
Result gcm_encrypt(
const std::vector<uint8_t> &key,
const std::vector<uint8_t> &nonce,
const std::vector<uint8_t> &plaintext,
const std::vector<uint8_t> &aad,
std::vector<uint8_t> &ciphertext_and_tag);
// GCM encrypt — library generates nonce, output is nonce||ciphertext||tag
Result gcm_encrypt(
const std::vector<uint8_t> &key,
const std::vector<uint8_t> &plaintext,
const std::vector<uint8_t> &aad,
std::vector<uint8_t> &nonce_ciphertext_tag);
// GCM decrypt — caller provides nonce, input is ciphertext||tag
Result gcm_decrypt(
const std::vector<uint8_t> &key,
const std::vector<uint8_t> &nonce,
const std::vector<uint8_t> &ciphertext_and_tag,
const std::vector<uint8_t> &aad,
std::vector<uint8_t> &plaintext);
// GCM decrypt — nonce is first 12 bytes of input, rest is ciphertext||tag
Result gcm_decrypt(
const std::vector<uint8_t> &key,
const std::vector<uint8_t> &nonce_ciphertext_tag,
const std::vector<uint8_t> &aad,
std::vector<uint8_t> &plaintext);
} // namespace tinyaes
#endif