aes.c
June 7, 2026 ยท View on GitHub
Purpose
AES helper layer with four modes:
- CBC with PKCS#7 padding
- XBC, a custom CBC-based framing mode with random prefix
- SIV, deterministic authenticated encryption using CMAC/S2V + CTR
- SIVN, nonce-based (non-deterministic) AES-SIV: same as SIV but folds a
caller-supplied nonce into S2V as the single associated-data string, so
identical plaintexts produce distinct ciphertext. Set the nonce with
XAES_SetSIVNonce()afterXAES_Init().
Types
xaes_key_t: raw key/IV container.nKeySizeis stored in bits.xaes_ctx_t: expanded round-key context.xaes_t: full runtime object containing mode, key and expanded context.
API Reference
void XAES_InitSIVKey(xaes_key_t *pKey, const uint8_t *pMacKey, const uint8_t *pCtrKey, size_t nKeySize)
- Arguments:
pKey: destination key struct.pMacKey: CMAC/S2V key bytes.pCtrKey: CTR encryption key bytes.nKeySize: key size in bits, expected128,192or256.
- Does:
- stores separate SIV MAC and CTR keys into
pKey. - zeroes IV state.
- stores separate SIV MAC and CTR keys into
- Returns:
- no return value.
void XAES_InitKey(xaes_key_t *pKey, const uint8_t *pAESKey, size_t nKeySize, const uint8_t *pIV, uint8_t bContainIV)
- Arguments:
pKey: destination key struct.pAESKey: AES key bytes.nKeySize: key size in bits.pIV: optional IV pointer.bContainIV: whether ciphertext should embed IV.
- Does:
- copies key bytes and records key size.
- copies
pIVonly ifpIVexists and its first byte is non-zero. - otherwise generates a random IV when
bContainIVis true, or uses all-zero IV when false.
- Returns:
- no return value.
int XAES_Init(xaes_t *pAES, const xaes_key_t *pKey, xaes_mode_t eMode)
- Arguments:
pAES: destination AES runtime object.pKey: previously prepared key struct.eMode:XAES_MODE_CBC,XAES_MODE_XBC,XAES_MODE_SIVorXAES_MODE_SIV_NONCE.
- Does:
- validates key size.
- expands encryption round keys.
- for SIV/SIVN, expands both CMAC and CTR contexts.
- Returns:
XSTDOKon success.XSTDINV/XSTDERRstyle negative status on invalid key size or init failure.
void XAES_SetSIVNonce(xaes_t *pAES, const uint8_t *pNonce, size_t nNonceLen)
- Arguments:
pAES: initialized runtime object (must beXAES_MODE_SIV_NONCE).pNonce: nonce bytes.nNonceLen: must equalXAES_BLOCK_SIZE(16).
- Does:
- records the nonce (in the per-context IV slot) for the next
XAES_Encrypt/XAES_Decrypt; S2V consumes it as the associated-data string. - the caller owns nonce uniqueness/randomness; a repeated nonce only degrades to deterministic output (nonce-misuse resistant), never keystream reuse.
- records the nonce (in the per-context IV slot) for the next
- Returns:
- no return value.
void XAES_ECB_Crypt(const xaes_t *pAES, uint8_t *pBuffer)
void XAES_ECB_Decrypt(const xaes_t *pAES, uint8_t *pBuffer)
- Arguments:
pAES: initialized AES context.pBuffer: one 16-byte block to encrypt/decrypt in place.
- Does:
- transforms exactly one AES block in ECB style.
- Returns:
- no return value.
uint8_t *XAES_CBC_Crypt(xaes_t *pAES, const uint8_t *pInput, size_t *pLength)
- Arguments:
pAES: initialized CBC/XBC runtime object.pInput: plaintext bytes.pLength: in/out length pointer; input plaintext size, output ciphertext size.
- Does:
- applies PKCS#7 padding.
- encrypts in CBC mode.
- prepends IV when
nContainIVis set. - mutates stored IV to last ciphertext block when IV is not embedded.
- Returns:
- newly allocated ciphertext buffer on success.
NULLon invalid args or allocation failure.
uint8_t *XAES_CBC_Decrypt(xaes_t *pAES, const uint8_t *pInput, size_t *pLength)
- Arguments:
- same shape as
XAES_CBC_Crypt.
- same shape as
- Does:
- extracts embedded IV when present.
- validates block size and PKCS#7 padding.
- mutates stored IV to last ciphertext block when IV is external.
- Returns:
- newly allocated plaintext buffer on success.
NULLon invalid input length, invalid padding or allocation failure.
uint8_t *XAES_SIV_Crypt(xaes_t *pAES, const uint8_t *pInput, size_t *pLength)
- Arguments:
pAES: initialized SIV runtime object.pInput: plaintext bytes.pLength: input plaintext size, then output size.
- Does:
- computes S2V/CMAC synthetic IV over plaintext.
- prepends the 16-byte SIV.
- encrypts plaintext with CTR using the synthetic IV.
- Returns:
- allocated
SIV || ciphertextbuffer on success. NULLon failure.
- allocated
uint8_t *XAES_SIV_Decrypt(xaes_t *pAES, const uint8_t *pInput, size_t *pLength)
- Arguments:
- same shape as
XAES_SIV_Crypt.
- same shape as
- Does:
- splits SIV from ciphertext.
- decrypts with CTR.
- recomputes SIV and verifies it in constant time.
- Returns:
- allocated plaintext buffer on success.
NULLwhen input is too short, authentication fails or allocation fails.
uint8_t *XAES_XBC_Crypt(xaes_t *pAES, const uint8_t *pInput, size_t *pLength)
- Arguments:
- same shape as CBC helpers.
- Does:
- creates a custom framed plaintext:
- 4-byte big-endian random-prefix length
- random prefix bytes
- user plaintext
- CBC-encrypts that framed buffer.
- optionally embeds IV.
- creates a custom framed plaintext:
- Returns:
- allocated ciphertext buffer or
NULL.
- allocated ciphertext buffer or
uint8_t *XAES_XBC_Decrypt(xaes_t *pAES, const uint8_t *pInput, size_t *pLength)
- Arguments:
- same shape as
XAES_XBC_Crypt.
- same shape as
- Does:
- CBC-decrypts.
- validates the 4-byte random-prefix header.
- strips the random prefix and returns only original plaintext.
- Returns:
- allocated plaintext buffer or
NULLwhen framing is invalid.
- allocated plaintext buffer or
uint8_t *XAES_Encrypt(xaes_t *pAES, const uint8_t *pInput, size_t *pLength)
uint8_t *XAES_Decrypt(xaes_t *pAES, const uint8_t *pInput, size_t *pLength)
- Arguments:
- generic AES runtime object plus input bytes and in/out length.
- Does:
- dispatches by
pAES->modeto CBC, XBC or SIV implementation.
- dispatches by
- Returns:
- allocated output buffer on success.
NULLon invalid mode or lower-level failure.
Output Ownership
- Every encrypt/decrypt function returning
uint8_t *allocates a new buffer. - The caller owns that buffer and must free it.
- Binary outputs usually include a trailing
NUL, but callers must trust*pLength, notstrlen().