AES-256 Encryption (aes256)
AES-256 symmetric encryption/decryption supporting ECB, CBC, and CTR block cipher modes.
- Key size: 32 bytes
- Block size: 16 bytes
- Rounds: 14
Constants
#define AES256_KEY_SIZE (32)
#define AES256_BLOCK_SIZE (16)
Data Structure
struct aes256_ctx_t {
uint8_t xkey[4 * 8 * (14 + 1)];
};
xkey stores the AES-256 expanded key (14 rounds + initial round key, 15 groups of 8 × 32-bit words, totaling 480 bytes).
API
void aes256_set_key(struct aes256_ctx_t * ctx, uint8_t * key);
Set the 32-byte key, initialize the encryption context, and perform key expansion.
void aes256_ecb_encrypt(struct aes256_ctx_t * ctx, uint8_t * in, uint8_t * out, int blks);
void aes256_ecb_decrypt(struct aes256_ctx_t * ctx, uint8_t * in, uint8_t * out, int blks);
ECB mode encrypt/decrypt. in and out must be blks * 16 bytes, i.e., the input must be a multiple of 16 bytes.
void aes256_cbc_encrypt(struct aes256_ctx_t * ctx, uint8_t * iv, uint8_t * in, uint8_t * out, int blks);
void aes256_cbc_decrypt(struct aes256_ctx_t * ctx, uint8_t * iv, uint8_t * in, uint8_t * out, int blks);
CBC mode encrypt/decrypt. iv is the 16-byte initialization vector, in and out must be blks * 16 bytes. Note that iv is modified during encryption; make a copy beforehand if the original iv needs to be preserved.
void aes256_ctr_encrypt(struct aes256_ctx_t * ctx, uint64_t offset, uint8_t * in, uint8_t * out, int bytes);
void aes256_ctr_decrypt(struct aes256_ctx_t * ctx, uint64_t offset, uint8_t * in, uint8_t * out, int bytes);
CTR mode encrypt/decrypt. offset is the counter offset (in blocks), bytes is the number of bytes to process. CTR mode does not require the input to be a multiple of 16 bytes, and encryption and decryption use the same operation.
Examples
ECB Mode (NIST Test Vector)
struct aes256_ctx_t ctx;
uint8_t key[32] = {
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4
};
uint8_t in[16] = {
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a
};
uint8_t out[16];
aes256_set_key(&ctx, key);
aes256_ecb_encrypt(&ctx, in, out, 1);
/* out = 0xf3,0xee,0xd1,0xbd,0xb5,0xd2,0xa0,0x3c,
0x06,0x4b,0x5a,0x7e,0x3d,0xb1,0x81,0xf8 */
CBC Mode (NIST Test Vector)
struct aes256_ctx_t ctx;
uint8_t key[32] = {
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4
};
uint8_t iv[16] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
uint8_t in[16] = {
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a
};
uint8_t out[16];
aes256_set_key(&ctx, key);
aes256_cbc_encrypt(&ctx, iv, in, out, 1);
/* out = 0xf5,0x8c,0x4c,0x04,0xd6,0xe5,0xf1,0xba,
0x77,0x9e,0xab,0xfb,0x5f,0x7b,0xfb,0xd6 */
CTR Mode
struct aes256_ctx_t ctx;
uint8_t key[32] = { ... };
uint8_t in[100] = { ... };
uint8_t enc[100];
uint8_t dec[100];
aes256_set_key(&ctx, key);
aes256_ctr_encrypt(&ctx, 0, in, enc, 100);
aes256_ctr_decrypt(&ctx, 0, enc, dec, 100);
/* dec equals in */
Encrypt→Decrypt Round-Trip Verification
struct aes256_ctx_t ctx;
uint8_t key[AES256_KEY_SIZE] = { ... };
uint8_t iv[AES256_BLOCK_SIZE] = { ... };
uint8_t in[AES256_BLOCK_SIZE * 10];
uint8_t enc[AES256_BLOCK_SIZE * 10];
uint8_t dec[AES256_BLOCK_SIZE * 10];
aes256_set_key(&ctx, key);
/* ECB round-trip */
aes256_ecb_encrypt(&ctx, in, enc, 10);
aes256_ecb_decrypt(&ctx, enc, dec, 10);
/* memcmp(in, dec, sizeof(in)) == 0 */
/* CBC round-trip (note: iv is modified during encryption, reset before decrypt) */
aes256_cbc_encrypt(&ctx, iv, in, enc, 10);
aes256_cbc_decrypt(&ctx, iv, enc, dec, 10);
/* memcmp(in, dec, sizeof(in)) == 0 */