AES(Rijndael)為區塊加密標準,區塊固定 128 bits(16 bytes),金鑰支援 128/192/256 bits。常見模式 ECB、CBC、CFB、OFB、CTR。ECB 相同明文產生相同密文,易受明文攻擊;CBC 與 CTR 為主流選擇,本文解析原理並提供 Gladman AES 庫實作範例。


官網:Gladman Cryptography
需加入專案:aes_modes.c、aescrypt.c、aeskey.c、aestab.c
#include <iostream>
#include <string.h>
#include "aes/aes.h"
typedef unsigned char uint8;
typedef unsigned long long uint64;
void ctr_inc(uint8 ctr[16]) { // RFC 3686 計數器遞增
if (!++ctr[15]) if (!++ctr[14]) if (!++ctr[13]) ++ctr[12];
}
void ctr_init(uint8 nonce[4], uint8 iv[8], uint8 ctr[16]) {
memcpy(ctr, nonce, 4);
memcpy(ctr+4, iv, 8);
memset(ctr+12, 0, 4);
ctr_inc(ctr);
}
void print_hex(uint8* buf, uint64 len) {
for (uint64 i=0; i<len; i++) {
printf("%02X", buf[i]);
if (i%16==15) printf("\n");
}
printf("\n");
}
int main() {
uint8 key[16] = {0x10,0xa5,0x88,0x69,0xd7,0x4b,0xe5,0xa3,
0x74,0xcf,0x86,0x7c,0xfb,0x47,0x38,0x59};
uint8 msg[] = "HelloWorld!23456";
uint64 fsize = strlen((char*)msg);
uint8* DataBuf = new uint8[1024];
/* ===== CBC ===== */
printf("AES-CBC\n");
memset(DataBuf, 0, 1024);
strcpy((char*)DataBuf, (char*)msg);
uint8 iv1[16] = {0};
uint8 pad = 16 - fsize % 16;
uint64 newlen = fsize + pad;
memset(DataBuf + fsize, pad, pad); // PKCS#7 padding
aes_encrypt_ctx en_ctx[1];
aes_decrypt_ctx de_ctx[1];
uint8 buf[16], *p = DataBuf;
for (uint64 i=0; i<newlen/16; i++) {
aes_encrypt_key128(key, en_ctx);
aes_cbc_encrypt(p, buf, 16, iv1, en_ctx); // iv1 會被更新
memcpy(p, buf, 16);
p += 16;
}
printf("Ciphertext:\n"); print_hex(DataBuf, newlen);
// 解密
uint8 iv2[16] = {0};
uint8 dec[256];
aes_decrypt_key128(key, de_ctx);
aes_cbc_decrypt(DataBuf, dec, newlen, iv2, de_ctx);
printf("Decrypted:\n"); print_hex(dec, newlen); // 含 padding
/* ===== CTR ===== */
printf("AES-CTR\n");
memset(DataBuf, 0, 1024);
strcpy((char*)DataBuf, (char*)msg);
uint8 iv3[16] = {0};
uint8 ctr_buf[16];
p = DataBuf;
for (uint64 i=0; i<fsize/16; i++) {
aes_encrypt_key128(key, en_ctx);
ctr_init(iv3, iv3+4, ctr_buf);
aes_ctr_encrypt(p, buf, 16, ctr_buf, ctr_inc, en_ctx);
memcpy(p, buf, 16);
p += 16;
}
if (fsize % 16) { // 尾部不滿區塊
aes_encrypt_key128(key, en_ctx);
ctr_init(iv3, iv3+4, ctr_buf);
aes_ctr_encrypt(p, buf, fsize%16, ctr_buf, ctr_inc, en_ctx);
memcpy(p, buf, fsize%16);
}
printf("Ciphertext:\n"); print_hex(DataBuf, fsize);
// CTR 解密同加密操作
aes_encrypt_key128(key, en_ctx);
ctr_init(iv3, iv3+4, ctr_buf);
aes_ctr_decrypt(DataBuf, dec, fsize, ctr_buf, ctr_inc, en_ctx);
printf("Decrypted:\n"); print_hex(dec, fsize);
delete[] DataBuf;
return 0;
}
aes_cbc_encrypt/decrypt 會修改 IV 緩衝區,每輪必須重置。aes_ctr_encrypt 與 aes_ctr_decrypt 邏輯相同,但計數器狀態必須同步。