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:
@@ -48,6 +48,14 @@ namespace tinyaes
|
||||
// Note: ARM AES instructions combine SubBytes+ShiftRows (vaese) and MixColumns (vaesmc)
|
||||
// The key XOR is done separately (veorq).
|
||||
|
||||
// Round keys are stored as big-endian uint32_t by the portable key expansion.
|
||||
// On little-endian ARM64, the bytes within each 32-bit word are reversed in memory.
|
||||
// vrev32q_u8 restores the original byte order expected by the ARM AES instructions.
|
||||
static inline uint8x16_t load_rk(const uint8_t *rk8)
|
||||
{
|
||||
return vrev32q_u8(vld1q_u8(rk8));
|
||||
}
|
||||
|
||||
void aes_encrypt_block_arm_ce(const uint32_t *rk, int rounds, const uint8_t in[16], uint8_t out[16])
|
||||
{
|
||||
const uint8_t *rk8 = reinterpret_cast<const uint8_t *>(rk);
|
||||
@@ -57,15 +65,15 @@ namespace tinyaes
|
||||
// So we need: vaese(block, key[i]) then vaesmcq for MixColumns
|
||||
for (int i = 0; i < rounds - 1; ++i)
|
||||
{
|
||||
uint8x16_t key = vld1q_u8(rk8 + i * 16);
|
||||
uint8x16_t key = load_rk(rk8 + i * 16);
|
||||
block = vaeseq_u8(block, key);
|
||||
block = vaesmcq_u8(block);
|
||||
}
|
||||
// Last round: no MixColumns
|
||||
uint8x16_t key_last = vld1q_u8(rk8 + (rounds - 1) * 16);
|
||||
uint8x16_t key_last = load_rk(rk8 + (rounds - 1) * 16);
|
||||
block = vaeseq_u8(block, key_last);
|
||||
// Final AddRoundKey
|
||||
uint8x16_t key_final = vld1q_u8(rk8 + rounds * 16);
|
||||
uint8x16_t key_final = load_rk(rk8 + rounds * 16);
|
||||
block = veorq_u8(block, key_final);
|
||||
|
||||
vst1q_u8(out, block);
|
||||
@@ -76,19 +84,22 @@ namespace tinyaes
|
||||
const uint8_t *rk8 = reinterpret_cast<const uint8_t *>(rk);
|
||||
uint8x16_t block = vld1q_u8(in);
|
||||
|
||||
// Decryption uses inverse round keys in reverse order
|
||||
for (int i = rounds; i > 1; --i)
|
||||
// ARM AESD places AddRoundKey before InvSubBytes, but standard AES
|
||||
// places it after. Since InvSubBytes is nonlinear, the middle round
|
||||
// keys must be pre-processed with InvMixColumns to compensate.
|
||||
// First round key (rk[rounds]) and last round key (rk[0]) are used as-is.
|
||||
block = vaesdq_u8(block, load_rk(rk8 + rounds * 16));
|
||||
block = vaesimcq_u8(block);
|
||||
|
||||
for (int i = rounds - 1; i > 1; --i)
|
||||
{
|
||||
uint8x16_t key = vld1q_u8(rk8 + i * 16);
|
||||
block = vaesdq_u8(block, key);
|
||||
block = vaesdq_u8(block, vaesimcq_u8(load_rk(rk8 + i * 16)));
|
||||
block = vaesimcq_u8(block);
|
||||
}
|
||||
// Last round: no InvMixColumns
|
||||
uint8x16_t key_1 = vld1q_u8(rk8 + 16);
|
||||
block = vaesdq_u8(block, key_1);
|
||||
// Last round: key needs InvMixColumns, but no InvMixColumns on state
|
||||
block = vaesdq_u8(block, vaesimcq_u8(load_rk(rk8 + 16)));
|
||||
// Final AddRoundKey
|
||||
uint8x16_t key_0 = vld1q_u8(rk8);
|
||||
block = veorq_u8(block, key_0);
|
||||
block = veorq_u8(block, load_rk(rk8));
|
||||
|
||||
vst1q_u8(out, block);
|
||||
}
|
||||
@@ -104,13 +115,13 @@ namespace tinyaes
|
||||
|
||||
for (int r = 0; r < rounds - 1; ++r)
|
||||
{
|
||||
uint8x16_t key = vld1q_u8(rk8 + r * 16);
|
||||
uint8x16_t key = load_rk(rk8 + r * 16);
|
||||
block = vaeseq_u8(block, key);
|
||||
block = vaesmcq_u8(block);
|
||||
}
|
||||
uint8x16_t key_last = vld1q_u8(rk8 + (rounds - 1) * 16);
|
||||
uint8x16_t key_last = load_rk(rk8 + (rounds - 1) * 16);
|
||||
block = vaeseq_u8(block, key_last);
|
||||
uint8x16_t key_final = vld1q_u8(rk8 + rounds * 16);
|
||||
uint8x16_t key_final = load_rk(rk8 + rounds * 16);
|
||||
block = veorq_u8(block, key_final);
|
||||
|
||||
// XOR with plaintext
|
||||
|
||||
@@ -44,15 +44,16 @@ namespace tinyaes
|
||||
{
|
||||
|
||||
// GF(2^128) multiplication using PMULL (carry-less multiply)
|
||||
// Inputs/outputs are in standard bit order (vrbitq_u8 applied):
|
||||
// lane 0 = x^0..x^63 (low), lane 1 = x^64..x^127 (high)
|
||||
static inline uint8x16_t gf128_mul_pmull(uint8x16_t a, uint8x16_t b)
|
||||
{
|
||||
// Reflect byte order for GCM convention
|
||||
poly64_t a_lo = vgetq_lane_p64(vreinterpretq_p64_u8(a), 0);
|
||||
poly64_t a_hi = vgetq_lane_p64(vreinterpretq_p64_u8(a), 1);
|
||||
poly64_t b_lo = vgetq_lane_p64(vreinterpretq_p64_u8(b), 0);
|
||||
poly64_t b_hi = vgetq_lane_p64(vreinterpretq_p64_u8(b), 1);
|
||||
|
||||
// Karatsuba multiplication
|
||||
// Karatsuba multiplication: A(x)*B(x) where A = a_hi*x^64 + a_lo
|
||||
poly128_t lo = vmull_p64(a_lo, b_lo);
|
||||
poly128_t hi = vmull_p64(a_hi, b_hi);
|
||||
poly128_t mid0 = vmull_p64(a_lo, b_hi);
|
||||
@@ -62,35 +63,42 @@ namespace tinyaes
|
||||
uint8x16_t hi_v = vreinterpretq_u8_p128(hi);
|
||||
uint8x16_t mid = veorq_u8(vreinterpretq_u8_p128(mid0), vreinterpretq_u8_p128(mid1));
|
||||
|
||||
// Combine: shift mid and XOR into lo/hi
|
||||
uint8x16_t mid_lo = vextq_u8(vdupq_n_u8(0), mid, 8);
|
||||
uint8x16_t mid_hi = vextq_u8(mid, vdupq_n_u8(0), 8);
|
||||
// Combine mid*x^64 into [hi_v : lo_v]
|
||||
uint8x16_t mid_lo = vextq_u8(vdupq_n_u8(0), mid, 8); // mid << 64
|
||||
uint8x16_t mid_hi = vextq_u8(mid, vdupq_n_u8(0), 8); // mid >> 64
|
||||
lo_v = veorq_u8(lo_v, mid_lo);
|
||||
hi_v = veorq_u8(hi_v, mid_hi);
|
||||
|
||||
// Reduction modulo x^128 + x^7 + x^2 + x + 1
|
||||
// Using the reflected reduction polynomial 0xC2...01
|
||||
poly64_t r = (poly64_t)0xC200000000000000ULL;
|
||||
poly128_t t1 = vmull_p64(vgetq_lane_p64(vreinterpretq_p64_u8(hi_v), 0), r);
|
||||
uint8x16_t f = veorq_u8(lo_v, vreinterpretq_u8_p128(t1));
|
||||
uint8x16_t f_swap = vextq_u8(f, f, 8);
|
||||
poly128_t t2 = vmull_p64(vgetq_lane_p64(vreinterpretq_p64_u8(f_swap), 0), r);
|
||||
// 256-bit product = [D3:D2:D1:D0] where hi_v=[D3:D2], lo_v=[D1:D0]
|
||||
// Reduction modulo p(x) = x^128 + x^7 + x^2 + x + 1
|
||||
// Since x^128 ≡ x^7+x^2+x+1, let q = 0x87
|
||||
poly64_t q = (poly64_t)0x87ULL;
|
||||
|
||||
return veorq_u8(veorq_u8(f_swap, vreinterpretq_u8_p128(t2)), hi_v);
|
||||
// Step 1: Reduce D3 — D3*x^192 ≡ (D3*q)*x^64
|
||||
poly128_t t1 = vmull_p64(vgetq_lane_p64(vreinterpretq_p64_u8(hi_v), 1), q);
|
||||
uint8x16_t t1_v = vreinterpretq_u8_p128(t1);
|
||||
lo_v = veorq_u8(lo_v, vextq_u8(vdupq_n_u8(0), t1_v, 8)); // D1 ^= T1_lo
|
||||
hi_v = veorq_u8(hi_v, vextq_u8(t1_v, vdupq_n_u8(0), 8)); // D2 ^= T1_hi
|
||||
|
||||
// Step 2: Reduce D2' — D2'*x^128 ≡ D2'*q
|
||||
poly128_t t2 = vmull_p64(vgetq_lane_p64(vreinterpretq_p64_u8(hi_v), 0), q);
|
||||
lo_v = veorq_u8(lo_v, vreinterpretq_u8_p128(t2));
|
||||
|
||||
return lo_v;
|
||||
}
|
||||
|
||||
void ghash_arm_ce(const uint8_t H[16], const uint8_t *data, size_t data_len, uint8_t Y[16])
|
||||
{
|
||||
// GCM uses big-endian bit reflection; ARM PMULL operates on reflected bits
|
||||
// The byte reversal handles the endianness conversion
|
||||
uint8x16_t rev_mask = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
|
||||
uint8x16_t h = vqtbl1q_u8(vld1q_u8(H), rev_mask);
|
||||
uint8x16_t y = vqtbl1q_u8(vld1q_u8(Y), rev_mask);
|
||||
// GCM uses MSB-first bit ordering (bit 7 of byte 0 = x^0), but ARM PMULL
|
||||
// uses LSB-first (bit 0 = x^0). vrbitq_u8 reverses bits within each byte
|
||||
// to convert between these conventions.
|
||||
uint8x16_t h = vrbitq_u8(vld1q_u8(H));
|
||||
uint8x16_t y = vrbitq_u8(vld1q_u8(Y));
|
||||
|
||||
size_t full_blocks = data_len / 16;
|
||||
for (size_t i = 0; i < full_blocks; ++i)
|
||||
{
|
||||
uint8x16_t d = vqtbl1q_u8(vld1q_u8(data + i * 16), rev_mask);
|
||||
uint8x16_t d = vrbitq_u8(vld1q_u8(data + i * 16));
|
||||
y = veorq_u8(y, d);
|
||||
y = gf128_mul_pmull(y, h);
|
||||
}
|
||||
@@ -100,12 +108,12 @@ namespace tinyaes
|
||||
{
|
||||
uint8_t padded[16] = {0};
|
||||
std::memcpy(padded, data + full_blocks * 16, remainder);
|
||||
uint8x16_t d = vqtbl1q_u8(vld1q_u8(padded), rev_mask);
|
||||
uint8x16_t d = vrbitq_u8(vld1q_u8(padded));
|
||||
y = veorq_u8(y, d);
|
||||
y = gf128_mul_pmull(y, h);
|
||||
}
|
||||
|
||||
vst1q_u8(Y, vqtbl1q_u8(y, rev_mask));
|
||||
vst1q_u8(Y, vrbitq_u8(y));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
112
src/cbc.cpp
112
src/cbc.cpp
@@ -42,9 +42,9 @@ namespace tinyaes
|
||||
if (rounds == 0)
|
||||
return Result::InvalidKeySize;
|
||||
if (iv.size() != 16)
|
||||
return Result::InvalidInput;
|
||||
return Result::InvalidIVSize;
|
||||
if (plaintext.empty() || (plaintext.size() % 16) != 0)
|
||||
return Result::InvalidInput;
|
||||
return Result::InvalidInputSize;
|
||||
|
||||
uint32_t rk[internal::AES_MAX_RK_WORDS];
|
||||
auto key_expand = internal::get_key_expand();
|
||||
@@ -69,7 +69,7 @@ namespace tinyaes
|
||||
|
||||
secure_zero(rk, sizeof(rk));
|
||||
secure_zero(block, sizeof(block));
|
||||
return Result::Success;
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
Result cbc_decrypt(
|
||||
@@ -82,9 +82,9 @@ namespace tinyaes
|
||||
if (rounds == 0)
|
||||
return Result::InvalidKeySize;
|
||||
if (iv.size() != 16)
|
||||
return Result::InvalidInput;
|
||||
return Result::InvalidIVSize;
|
||||
if (ciphertext.empty() || (ciphertext.size() % 16) != 0)
|
||||
return Result::InvalidInput;
|
||||
return Result::InvalidInputSize;
|
||||
|
||||
uint32_t rk[internal::AES_MAX_RK_WORDS];
|
||||
auto key_expand = internal::get_key_expand();
|
||||
@@ -107,7 +107,7 @@ namespace tinyaes
|
||||
}
|
||||
|
||||
secure_zero(rk, sizeof(rk));
|
||||
return Result::Success;
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
// PKCS#7 padding: append N bytes of value N where N = 16 - (len % 16)
|
||||
@@ -121,7 +121,7 @@ namespace tinyaes
|
||||
size_t pad_len = 16 - (plaintext.size() % 16);
|
||||
std::vector<uint8_t> padded(plaintext.size() + pad_len);
|
||||
std::memcpy(padded.data(), plaintext.data(), plaintext.size());
|
||||
std::memset(padded.data() + plaintext.size(), static_cast<int>(pad_len), pad_len);
|
||||
std::memset(padded.data() + plaintext.size(), static_cast<unsigned char>(pad_len), pad_len);
|
||||
|
||||
auto result = cbc_encrypt(key, iv, padded, ciphertext);
|
||||
secure_zero(padded.data(), padded.size());
|
||||
@@ -137,34 +137,74 @@ namespace tinyaes
|
||||
{
|
||||
std::vector<uint8_t> decrypted;
|
||||
auto result = cbc_decrypt(key, iv, ciphertext, decrypted);
|
||||
if (result != Result::Success)
|
||||
if (result != Result::Ok)
|
||||
return result;
|
||||
|
||||
if (decrypted.empty())
|
||||
return Result::InvalidPadding;
|
||||
|
||||
// Constant-time PKCS#7 validation: scan entire last block
|
||||
// Fully constant-time PKCS#7 validation: always scan all 16 bytes of last block
|
||||
uint8_t pad_val = decrypted.back();
|
||||
if (pad_val == 0 || pad_val > 16)
|
||||
return Result::InvalidPadding;
|
||||
|
||||
// Verify all padding bytes match (constant-time)
|
||||
volatile uint8_t bad = 0;
|
||||
size_t start = decrypted.size() - pad_val;
|
||||
for (size_t i = start; i < decrypted.size(); ++i)
|
||||
// Range check via arithmetic (no branches):
|
||||
// bad_range is 0xFF if pad_val is out of [1..16], 0x00 otherwise
|
||||
uint8_t bad_range = static_cast<uint8_t>(((pad_val - 1) >> 8) | ((16 - pad_val) >> 8));
|
||||
|
||||
// Always scan exactly 16 bytes of the last block
|
||||
const uint8_t *last_block = decrypted.data() + decrypted.size() - 16;
|
||||
volatile uint8_t bad_pad = 0;
|
||||
for (unsigned j = 0; j < 16; ++j)
|
||||
{
|
||||
bad |= static_cast<uint8_t>(decrypted[i] ^ pad_val);
|
||||
// should_be_pad is 0xFF when byte j is in the padding region, 0x00 otherwise
|
||||
// Padding region: positions where (j + pad_val >= 16), i.e. j >= 16 - pad_val
|
||||
uint8_t should_be_pad = static_cast<uint8_t>((15 - j - pad_val) >> 8);
|
||||
bad_pad |= static_cast<uint8_t>(should_be_pad & (last_block[j] ^ pad_val));
|
||||
}
|
||||
|
||||
uint8_t bad = static_cast<uint8_t>(bad_range | bad_pad);
|
||||
if (bad != 0)
|
||||
{
|
||||
secure_zero(decrypted.data(), decrypted.size());
|
||||
return Result::InvalidPadding;
|
||||
}
|
||||
|
||||
size_t start = decrypted.size() - pad_val;
|
||||
plaintext.assign(decrypted.begin(), decrypted.begin() + static_cast<ptrdiff_t>(start));
|
||||
secure_zero(decrypted.data(), decrypted.size());
|
||||
return Result::Success;
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
Result cbc_encrypt_pkcs7(
|
||||
const std::vector<uint8_t> &key,
|
||||
const std::vector<uint8_t> &plaintext,
|
||||
std::vector<uint8_t> &iv_and_ciphertext)
|
||||
{
|
||||
auto iv = generate_iv();
|
||||
if (iv.empty())
|
||||
return Result::InternalError;
|
||||
|
||||
std::vector<uint8_t> ct;
|
||||
auto result = cbc_encrypt_pkcs7(key, iv, plaintext, ct);
|
||||
if (result != Result::Ok)
|
||||
return result;
|
||||
|
||||
iv_and_ciphertext.resize(16 + ct.size());
|
||||
std::memcpy(iv_and_ciphertext.data(), iv.data(), 16);
|
||||
std::memcpy(iv_and_ciphertext.data() + 16, ct.data(), ct.size());
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
Result cbc_decrypt_pkcs7(
|
||||
const std::vector<uint8_t> &key,
|
||||
const std::vector<uint8_t> &iv_and_ciphertext,
|
||||
std::vector<uint8_t> &plaintext)
|
||||
{
|
||||
if (iv_and_ciphertext.size() < 32)
|
||||
return Result::InvalidInputSize;
|
||||
|
||||
std::vector<uint8_t> iv(iv_and_ciphertext.begin(), iv_and_ciphertext.begin() + 16);
|
||||
std::vector<uint8_t> ct(iv_and_ciphertext.begin() + 16, iv_and_ciphertext.end());
|
||||
return cbc_decrypt_pkcs7(key, iv, ct, plaintext);
|
||||
}
|
||||
|
||||
} // namespace tinyaes
|
||||
@@ -180,9 +220,9 @@ extern "C" int tinyaes_cbc_encrypt(
|
||||
size_t ciphertext_len)
|
||||
{
|
||||
if (!key || !iv || !plaintext || !ciphertext)
|
||||
return TINYAES_ERROR_INVALID_INPUT;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
if (ciphertext_len < plaintext_len)
|
||||
return TINYAES_ERROR_BUFFER_TOO_SMALL;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
|
||||
std::vector<uint8_t> k(key, key + key_len);
|
||||
std::vector<uint8_t> v(iv, iv + 16);
|
||||
@@ -191,12 +231,13 @@ extern "C" int tinyaes_cbc_encrypt(
|
||||
|
||||
auto result = tinyaes::cbc_encrypt(k, v, pt, ct);
|
||||
tinyaes::secure_zero(k.data(), k.size());
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
|
||||
if (result != tinyaes::Result::Success)
|
||||
if (result != tinyaes::Result::Ok)
|
||||
return static_cast<int>(result);
|
||||
|
||||
std::memcpy(ciphertext, ct.data(), ct.size());
|
||||
return TINYAES_SUCCESS;
|
||||
return TINYAES_OK;
|
||||
}
|
||||
|
||||
extern "C" int tinyaes_cbc_decrypt(
|
||||
@@ -209,9 +250,9 @@ extern "C" int tinyaes_cbc_decrypt(
|
||||
size_t plaintext_len)
|
||||
{
|
||||
if (!key || !iv || !ciphertext || !plaintext)
|
||||
return TINYAES_ERROR_INVALID_INPUT;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
if (plaintext_len < ciphertext_len)
|
||||
return TINYAES_ERROR_BUFFER_TOO_SMALL;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
|
||||
std::vector<uint8_t> k(key, key + key_len);
|
||||
std::vector<uint8_t> v(iv, iv + 16);
|
||||
@@ -221,11 +262,15 @@ extern "C" int tinyaes_cbc_decrypt(
|
||||
auto result = tinyaes::cbc_decrypt(k, v, ct, pt);
|
||||
tinyaes::secure_zero(k.data(), k.size());
|
||||
|
||||
if (result != tinyaes::Result::Success)
|
||||
if (result != tinyaes::Result::Ok)
|
||||
{
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
return static_cast<int>(result);
|
||||
}
|
||||
|
||||
std::memcpy(plaintext, pt.data(), pt.size());
|
||||
return TINYAES_SUCCESS;
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
return TINYAES_OK;
|
||||
}
|
||||
|
||||
extern "C" int tinyaes_cbc_encrypt_pkcs7(
|
||||
@@ -238,13 +283,13 @@ extern "C" int tinyaes_cbc_encrypt_pkcs7(
|
||||
size_t *ciphertext_len)
|
||||
{
|
||||
if (!key || !iv || !plaintext || !ciphertext || !ciphertext_len)
|
||||
return TINYAES_ERROR_INVALID_INPUT;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
|
||||
size_t padded_len = plaintext_len + (16 - (plaintext_len % 16));
|
||||
if (*ciphertext_len < padded_len)
|
||||
{
|
||||
*ciphertext_len = padded_len;
|
||||
return TINYAES_ERROR_BUFFER_TOO_SMALL;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> k(key, key + key_len);
|
||||
@@ -254,13 +299,14 @@ extern "C" int tinyaes_cbc_encrypt_pkcs7(
|
||||
|
||||
auto result = tinyaes::cbc_encrypt_pkcs7(k, v, pt, ct);
|
||||
tinyaes::secure_zero(k.data(), k.size());
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
|
||||
if (result != tinyaes::Result::Success)
|
||||
if (result != tinyaes::Result::Ok)
|
||||
return static_cast<int>(result);
|
||||
|
||||
std::memcpy(ciphertext, ct.data(), ct.size());
|
||||
*ciphertext_len = ct.size();
|
||||
return TINYAES_SUCCESS;
|
||||
return TINYAES_OK;
|
||||
}
|
||||
|
||||
extern "C" int tinyaes_cbc_decrypt_pkcs7(
|
||||
@@ -273,7 +319,7 @@ extern "C" int tinyaes_cbc_decrypt_pkcs7(
|
||||
size_t *plaintext_len)
|
||||
{
|
||||
if (!key || !iv || !ciphertext || !plaintext || !plaintext_len)
|
||||
return TINYAES_ERROR_INVALID_INPUT;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
|
||||
std::vector<uint8_t> k(key, key + key_len);
|
||||
std::vector<uint8_t> v(iv, iv + 16);
|
||||
@@ -283,18 +329,18 @@ extern "C" int tinyaes_cbc_decrypt_pkcs7(
|
||||
auto result = tinyaes::cbc_decrypt_pkcs7(k, v, ct, pt);
|
||||
tinyaes::secure_zero(k.data(), k.size());
|
||||
|
||||
if (result != tinyaes::Result::Success)
|
||||
if (result != tinyaes::Result::Ok)
|
||||
return static_cast<int>(result);
|
||||
|
||||
if (*plaintext_len < pt.size())
|
||||
{
|
||||
*plaintext_len = pt.size();
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
return TINYAES_ERROR_BUFFER_TOO_SMALL;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
}
|
||||
|
||||
std::memcpy(plaintext, pt.data(), pt.size());
|
||||
*plaintext_len = pt.size();
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
return TINYAES_SUCCESS;
|
||||
return TINYAES_OK;
|
||||
}
|
||||
|
||||
144
src/ctr.cpp
144
src/ctr.cpp
@@ -43,9 +43,9 @@ namespace tinyaes
|
||||
if (rounds == 0)
|
||||
return Result::InvalidKeySize;
|
||||
if (iv.size() != 16)
|
||||
return Result::InvalidInput;
|
||||
return Result::InvalidIVSize;
|
||||
if (input.empty())
|
||||
return Result::InvalidInput;
|
||||
return Result::InvalidInputSize;
|
||||
|
||||
uint32_t rk[internal::AES_MAX_RK_WORDS];
|
||||
auto key_expand = internal::get_key_expand();
|
||||
@@ -83,7 +83,73 @@ namespace tinyaes
|
||||
|
||||
secure_zero(rk, sizeof(rk));
|
||||
secure_zero(ctr, sizeof(ctr));
|
||||
return Result::Success;
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
// Build a 16-byte IV from 12-byte nonce + 4-byte counter starting at 1
|
||||
static std::vector<uint8_t> nonce_to_iv(const std::vector<uint8_t> &nonce)
|
||||
{
|
||||
std::vector<uint8_t> iv(16, 0);
|
||||
std::memcpy(iv.data(), nonce.data(), 12);
|
||||
iv[15] = 1; // big-endian counter = 1
|
||||
return iv;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (nonce.size() != 12)
|
||||
return Result::InvalidNonceSize;
|
||||
auto iv = nonce_to_iv(nonce);
|
||||
return ctr_crypt(key, iv, plaintext, ciphertext);
|
||||
}
|
||||
|
||||
Result ctr_encrypt(
|
||||
const std::vector<uint8_t> &key,
|
||||
const std::vector<uint8_t> &plaintext,
|
||||
std::vector<uint8_t> &nonce_and_ciphertext)
|
||||
{
|
||||
auto nonce = generate_nonce();
|
||||
if (nonce.empty())
|
||||
return Result::InternalError;
|
||||
|
||||
std::vector<uint8_t> ct;
|
||||
auto result = ctr_encrypt(key, nonce, plaintext, ct);
|
||||
if (result != Result::Ok)
|
||||
return result;
|
||||
|
||||
nonce_and_ciphertext.resize(12 + ct.size());
|
||||
std::memcpy(nonce_and_ciphertext.data(), nonce.data(), 12);
|
||||
std::memcpy(nonce_and_ciphertext.data() + 12, ct.data(), ct.size());
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (nonce.size() != 12)
|
||||
return Result::InvalidNonceSize;
|
||||
auto iv = nonce_to_iv(nonce);
|
||||
return ctr_crypt(key, iv, ciphertext, plaintext);
|
||||
}
|
||||
|
||||
Result ctr_decrypt(
|
||||
const std::vector<uint8_t> &key,
|
||||
const std::vector<uint8_t> &nonce_and_ciphertext,
|
||||
std::vector<uint8_t> &plaintext)
|
||||
{
|
||||
if (nonce_and_ciphertext.size() < 13)
|
||||
return Result::InvalidInputSize;
|
||||
|
||||
std::vector<uint8_t> nonce(nonce_and_ciphertext.begin(), nonce_and_ciphertext.begin() + 12);
|
||||
std::vector<uint8_t> ct(nonce_and_ciphertext.begin() + 12, nonce_and_ciphertext.end());
|
||||
return ctr_decrypt(key, nonce, ct, plaintext);
|
||||
}
|
||||
|
||||
} // namespace tinyaes
|
||||
@@ -98,9 +164,9 @@ extern "C" int tinyaes_ctr_crypt(
|
||||
size_t output_len)
|
||||
{
|
||||
if (!key || !iv || !input || !output)
|
||||
return TINYAES_ERROR_INVALID_INPUT;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
if (output_len < input_len)
|
||||
return TINYAES_ERROR_BUFFER_TOO_SMALL;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
|
||||
std::vector<uint8_t> k(key, key + key_len);
|
||||
std::vector<uint8_t> v(iv, iv + 16);
|
||||
@@ -109,10 +175,74 @@ extern "C" int tinyaes_ctr_crypt(
|
||||
|
||||
auto result = tinyaes::ctr_crypt(k, v, in, out);
|
||||
tinyaes::secure_zero(k.data(), k.size());
|
||||
tinyaes::secure_zero(in.data(), in.size());
|
||||
|
||||
if (result != tinyaes::Result::Success)
|
||||
if (result != tinyaes::Result::Ok)
|
||||
return static_cast<int>(result);
|
||||
|
||||
std::memcpy(output, out.data(), out.size());
|
||||
return TINYAES_SUCCESS;
|
||||
return TINYAES_OK;
|
||||
}
|
||||
|
||||
extern "C" 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)
|
||||
{
|
||||
if (!key || !nonce || !plaintext || !ciphertext)
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
if (ciphertext_len < plaintext_len)
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
|
||||
std::vector<uint8_t> k(key, key + key_len);
|
||||
std::vector<uint8_t> n(nonce, nonce + 12);
|
||||
std::vector<uint8_t> pt(plaintext, plaintext + plaintext_len);
|
||||
std::vector<uint8_t> ct;
|
||||
|
||||
auto result = tinyaes::ctr_encrypt(k, n, pt, ct);
|
||||
tinyaes::secure_zero(k.data(), k.size());
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
|
||||
if (result != tinyaes::Result::Ok)
|
||||
return static_cast<int>(result);
|
||||
|
||||
std::memcpy(ciphertext, ct.data(), ct.size());
|
||||
return TINYAES_OK;
|
||||
}
|
||||
|
||||
extern "C" 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)
|
||||
{
|
||||
if (!key || !nonce || !ciphertext || !plaintext)
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
if (plaintext_len < ciphertext_len)
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
|
||||
std::vector<uint8_t> k(key, key + key_len);
|
||||
std::vector<uint8_t> n(nonce, nonce + 12);
|
||||
std::vector<uint8_t> ct(ciphertext, ciphertext + ciphertext_len);
|
||||
std::vector<uint8_t> pt;
|
||||
|
||||
auto result = tinyaes::ctr_decrypt(k, n, ct, pt);
|
||||
tinyaes::secure_zero(k.data(), k.size());
|
||||
|
||||
if (result != tinyaes::Result::Ok)
|
||||
{
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
return static_cast<int>(result);
|
||||
}
|
||||
|
||||
std::memcpy(plaintext, pt.data(), pt.size());
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
return TINYAES_OK;
|
||||
}
|
||||
|
||||
29
src/ecb.cpp
29
src/ecb.cpp
@@ -41,7 +41,7 @@ namespace tinyaes
|
||||
if (rounds == 0)
|
||||
return Result::InvalidKeySize;
|
||||
if (plaintext.empty() || (plaintext.size() % 16) != 0)
|
||||
return Result::InvalidInput;
|
||||
return Result::InvalidInputSize;
|
||||
|
||||
uint32_t rk[internal::AES_MAX_RK_WORDS];
|
||||
auto key_expand = internal::get_key_expand();
|
||||
@@ -56,7 +56,7 @@ namespace tinyaes
|
||||
}
|
||||
|
||||
secure_zero(rk, sizeof(rk));
|
||||
return Result::Success;
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
Result ecb_decrypt(
|
||||
@@ -68,7 +68,7 @@ namespace tinyaes
|
||||
if (rounds == 0)
|
||||
return Result::InvalidKeySize;
|
||||
if (ciphertext.empty() || (ciphertext.size() % 16) != 0)
|
||||
return Result::InvalidInput;
|
||||
return Result::InvalidInputSize;
|
||||
|
||||
uint32_t rk[internal::AES_MAX_RK_WORDS];
|
||||
auto key_expand = internal::get_key_expand();
|
||||
@@ -83,7 +83,7 @@ namespace tinyaes
|
||||
}
|
||||
|
||||
secure_zero(rk, sizeof(rk));
|
||||
return Result::Success;
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
} // namespace tinyaes
|
||||
@@ -97,9 +97,9 @@ extern "C" int tinyaes_ecb_encrypt(
|
||||
size_t ciphertext_len)
|
||||
{
|
||||
if (!key || !plaintext || !ciphertext)
|
||||
return TINYAES_ERROR_INVALID_INPUT;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
if (ciphertext_len < plaintext_len)
|
||||
return TINYAES_ERROR_BUFFER_TOO_SMALL;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
|
||||
std::vector<uint8_t> k(key, key + key_len);
|
||||
std::vector<uint8_t> pt(plaintext, plaintext + plaintext_len);
|
||||
@@ -107,12 +107,13 @@ extern "C" int tinyaes_ecb_encrypt(
|
||||
|
||||
auto result = tinyaes::ecb_encrypt(k, pt, ct);
|
||||
tinyaes::secure_zero(k.data(), k.size());
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
|
||||
if (result != tinyaes::Result::Success)
|
||||
if (result != tinyaes::Result::Ok)
|
||||
return static_cast<int>(result);
|
||||
|
||||
std::memcpy(ciphertext, ct.data(), ct.size());
|
||||
return TINYAES_SUCCESS;
|
||||
return TINYAES_OK;
|
||||
}
|
||||
|
||||
extern "C" int tinyaes_ecb_decrypt(
|
||||
@@ -124,9 +125,9 @@ extern "C" int tinyaes_ecb_decrypt(
|
||||
size_t plaintext_len)
|
||||
{
|
||||
if (!key || !ciphertext || !plaintext)
|
||||
return TINYAES_ERROR_INVALID_INPUT;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
if (plaintext_len < ciphertext_len)
|
||||
return TINYAES_ERROR_BUFFER_TOO_SMALL;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
|
||||
std::vector<uint8_t> k(key, key + key_len);
|
||||
std::vector<uint8_t> ct(ciphertext, ciphertext + ciphertext_len);
|
||||
@@ -135,9 +136,13 @@ extern "C" int tinyaes_ecb_decrypt(
|
||||
auto result = tinyaes::ecb_decrypt(k, ct, pt);
|
||||
tinyaes::secure_zero(k.data(), k.size());
|
||||
|
||||
if (result != tinyaes::Result::Success)
|
||||
if (result != tinyaes::Result::Ok)
|
||||
{
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
return static_cast<int>(result);
|
||||
}
|
||||
|
||||
std::memcpy(plaintext, pt.data(), pt.size());
|
||||
return TINYAES_SUCCESS;
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
return TINYAES_OK;
|
||||
}
|
||||
|
||||
131
src/gcm.cpp
131
src/gcm.cpp
@@ -123,7 +123,7 @@ namespace tinyaes
|
||||
if (rounds == 0)
|
||||
return Result::InvalidKeySize;
|
||||
if (iv.empty())
|
||||
return Result::InvalidInput;
|
||||
return Result::InvalidIVSize;
|
||||
|
||||
uint32_t rk[internal::AES_MAX_RK_WORDS];
|
||||
auto key_expand = internal::get_key_expand();
|
||||
@@ -180,7 +180,7 @@ namespace tinyaes
|
||||
secure_zero(rk, sizeof(rk));
|
||||
secure_zero(H, sizeof(H));
|
||||
secure_zero(J0, sizeof(J0));
|
||||
return Result::Success;
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
Result gcm_decrypt(
|
||||
@@ -195,9 +195,9 @@ namespace tinyaes
|
||||
if (rounds == 0)
|
||||
return Result::InvalidKeySize;
|
||||
if (iv.empty())
|
||||
return Result::InvalidInput;
|
||||
return Result::InvalidIVSize;
|
||||
if (tag.size() != 16)
|
||||
return Result::InvalidInput;
|
||||
return Result::InvalidInputSize;
|
||||
|
||||
uint32_t rk[internal::AES_MAX_RK_WORDS];
|
||||
auto key_expand = internal::get_key_expand();
|
||||
@@ -226,7 +226,7 @@ namespace tinyaes
|
||||
secure_zero(H, sizeof(H));
|
||||
secure_zero(J0, sizeof(J0));
|
||||
secure_zero(computed_tag, sizeof(computed_tag));
|
||||
return Result::AuthFailed;
|
||||
return Result::AuthenticationFailed;
|
||||
}
|
||||
|
||||
// Tag verified — decrypt ciphertext using CTR mode
|
||||
@@ -264,7 +264,77 @@ namespace tinyaes
|
||||
secure_zero(H, sizeof(H));
|
||||
secure_zero(J0, sizeof(J0));
|
||||
secure_zero(computed_tag, sizeof(computed_tag));
|
||||
return Result::Success;
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
std::vector<uint8_t> ct, tag;
|
||||
auto result = gcm_encrypt(key, nonce, aad, plaintext, ct, tag);
|
||||
if (result != Result::Ok)
|
||||
return result;
|
||||
|
||||
ciphertext_and_tag.resize(ct.size() + 16);
|
||||
if (!ct.empty())
|
||||
std::memcpy(ciphertext_and_tag.data(), ct.data(), ct.size());
|
||||
std::memcpy(ciphertext_and_tag.data() + ct.size(), tag.data(), 16);
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
auto nonce = generate_nonce();
|
||||
if (nonce.empty())
|
||||
return Result::InternalError;
|
||||
|
||||
std::vector<uint8_t> ct_tag;
|
||||
auto result = gcm_encrypt(key, nonce, plaintext, aad, ct_tag);
|
||||
if (result != Result::Ok)
|
||||
return result;
|
||||
|
||||
nonce_ciphertext_tag.resize(12 + ct_tag.size());
|
||||
std::memcpy(nonce_ciphertext_tag.data(), nonce.data(), 12);
|
||||
std::memcpy(nonce_ciphertext_tag.data() + 12, ct_tag.data(), ct_tag.size());
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (ciphertext_and_tag.size() < 16)
|
||||
return Result::InvalidInputSize;
|
||||
|
||||
size_t ct_len = ciphertext_and_tag.size() - 16;
|
||||
std::vector<uint8_t> ct(ciphertext_and_tag.begin(), ciphertext_and_tag.begin() + static_cast<ptrdiff_t>(ct_len));
|
||||
std::vector<uint8_t> tag(ciphertext_and_tag.end() - 16, ciphertext_and_tag.end());
|
||||
return gcm_decrypt(key, nonce, aad, ct, tag, plaintext);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (nonce_ciphertext_tag.size() < 28) // 12 nonce + 16 tag minimum
|
||||
return Result::InvalidInputSize;
|
||||
|
||||
std::vector<uint8_t> nonce(nonce_ciphertext_tag.begin(), nonce_ciphertext_tag.begin() + 12);
|
||||
std::vector<uint8_t> ct_tag(nonce_ciphertext_tag.begin() + 12, nonce_ciphertext_tag.end());
|
||||
return gcm_decrypt(key, nonce, ct_tag, aad, plaintext);
|
||||
}
|
||||
|
||||
} // namespace tinyaes
|
||||
@@ -283,32 +353,33 @@ extern "C" int tinyaes_gcm_encrypt(
|
||||
uint8_t tag[16])
|
||||
{
|
||||
if (!key || !iv || !tag)
|
||||
return TINYAES_ERROR_INVALID_INPUT;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
if (plaintext_len > 0 && (!plaintext || !ciphertext))
|
||||
return TINYAES_ERROR_INVALID_INPUT;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
if (ciphertext_len < plaintext_len)
|
||||
return TINYAES_ERROR_BUFFER_TOO_SMALL;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
|
||||
std::vector<uint8_t> k(key, key + key_len);
|
||||
std::vector<uint8_t> v(iv, iv + iv_len);
|
||||
std::vector<uint8_t> a(aad ? aad : key, aad ? aad + aad_len : key);
|
||||
if (!aad)
|
||||
a.clear();
|
||||
std::vector<uint8_t> pt(plaintext ? plaintext : key, plaintext ? plaintext + plaintext_len : key);
|
||||
if (!plaintext)
|
||||
pt.clear();
|
||||
std::vector<uint8_t> a;
|
||||
if (aad && aad_len > 0)
|
||||
a.assign(aad, aad + aad_len);
|
||||
std::vector<uint8_t> pt;
|
||||
if (plaintext && plaintext_len > 0)
|
||||
pt.assign(plaintext, plaintext + plaintext_len);
|
||||
std::vector<uint8_t> ct, t;
|
||||
|
||||
auto result = tinyaes::gcm_encrypt(k, v, a, pt, ct, t);
|
||||
tinyaes::secure_zero(k.data(), k.size());
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
|
||||
if (result != tinyaes::Result::Success)
|
||||
if (result != tinyaes::Result::Ok)
|
||||
return static_cast<int>(result);
|
||||
|
||||
if (!ct.empty())
|
||||
std::memcpy(ciphertext, ct.data(), ct.size());
|
||||
std::memcpy(tag, t.data(), 16);
|
||||
return TINYAES_SUCCESS;
|
||||
return TINYAES_OK;
|
||||
}
|
||||
|
||||
extern "C" int tinyaes_gcm_decrypt(
|
||||
@@ -325,30 +396,34 @@ extern "C" int tinyaes_gcm_decrypt(
|
||||
const uint8_t tag[16])
|
||||
{
|
||||
if (!key || !iv || !tag)
|
||||
return TINYAES_ERROR_INVALID_INPUT;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
if (ciphertext_len > 0 && (!ciphertext || !plaintext))
|
||||
return TINYAES_ERROR_INVALID_INPUT;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
if (plaintext_len < ciphertext_len)
|
||||
return TINYAES_ERROR_BUFFER_TOO_SMALL;
|
||||
return TINYAES_INVALID_INPUT_SIZE;
|
||||
|
||||
std::vector<uint8_t> k(key, key + key_len);
|
||||
std::vector<uint8_t> v(iv, iv + iv_len);
|
||||
std::vector<uint8_t> a(aad ? aad : key, aad ? aad + aad_len : key);
|
||||
if (!aad)
|
||||
a.clear();
|
||||
std::vector<uint8_t> ct(ciphertext ? ciphertext : key, ciphertext ? ciphertext + ciphertext_len : key);
|
||||
if (!ciphertext)
|
||||
ct.clear();
|
||||
std::vector<uint8_t> a;
|
||||
if (aad && aad_len > 0)
|
||||
a.assign(aad, aad + aad_len);
|
||||
std::vector<uint8_t> ct;
|
||||
if (ciphertext && ciphertext_len > 0)
|
||||
ct.assign(ciphertext, ciphertext + ciphertext_len);
|
||||
std::vector<uint8_t> t(tag, tag + 16);
|
||||
std::vector<uint8_t> pt;
|
||||
|
||||
auto result = tinyaes::gcm_decrypt(k, v, a, ct, t, pt);
|
||||
tinyaes::secure_zero(k.data(), k.size());
|
||||
|
||||
if (result != tinyaes::Result::Success)
|
||||
if (result != tinyaes::Result::Ok)
|
||||
{
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
return static_cast<int>(result);
|
||||
}
|
||||
|
||||
if (!pt.empty())
|
||||
std::memcpy(plaintext, pt.data(), pt.size());
|
||||
return TINYAES_SUCCESS;
|
||||
tinyaes::secure_zero(pt.data(), pt.size());
|
||||
return TINYAES_OK;
|
||||
}
|
||||
|
||||
@@ -63,4 +63,30 @@ namespace tinyaes
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<uint8_t> generate_iv()
|
||||
{
|
||||
std::vector<uint8_t> iv(16);
|
||||
if (generate_iv(iv.data(), 16) != 0)
|
||||
iv.clear();
|
||||
return iv;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> generate_nonce()
|
||||
{
|
||||
std::vector<uint8_t> nonce(12);
|
||||
if (generate_iv(nonce.data(), 12) != 0)
|
||||
nonce.clear();
|
||||
return nonce;
|
||||
}
|
||||
|
||||
} // namespace tinyaes
|
||||
|
||||
extern "C" int tinyaes_generate_iv(uint8_t out[16])
|
||||
{
|
||||
return tinyaes::generate_iv(out, 16);
|
||||
}
|
||||
|
||||
extern "C" int tinyaes_generate_nonce(uint8_t out[12])
|
||||
{
|
||||
return tinyaes::generate_iv(out, 12);
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@ namespace tinyaes
|
||||
{
|
||||
diff |= static_cast<uint8_t>(a[i] ^ b[i]);
|
||||
}
|
||||
volatile uint8_t result = static_cast<uint8_t>(diff == 0);
|
||||
return result != 0;
|
||||
uint8_t d = diff; // volatile read is the barrier
|
||||
return d == 0;
|
||||
}
|
||||
|
||||
} // namespace tinyaes
|
||||
|
||||
Reference in New Issue
Block a user