首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

AES-CBC 與 AES-CTR 模式加解密原理詳解與 C 實作範例

     編輯:關於C語言

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

一、AES-CBC 原理

CBC 加密流程圖

  • 加密:明文區塊 ⊕ IV → AES 加密 → 密文區塊,密文作為下一區塊 IV。
  • 解密:AES 解密密文區塊 → ⊕ 前一密文區塊(或 IV) → 明文。
  • 特性:需 Padding(PKCS#7 等)、串行不可並行、需 IV(不可預測)。

二、AES-CTR 原理

CTR 加密流程圖

  • 加密/解密:AES 加密計數器 → ⊕ 明文/密文 → 密文/明文。加解密操作對稱。
  • 計數器:Nonce (固定) + Counter (遞增),確保每區塊唯一。
  • 特性:無需 Padding、可並行、隨機存取、Nonce 不可重複使用(同金鑰下)。

三、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;
}

關鍵提醒

  1. CBC 解密需相同 IV,且 aes_cbc_encrypt/decrypt 會修改 IV 緩衝區,每輪必須重置。
  2. CTR 模式下 aes_ctr_encrypt 與 aes_ctr_decrypt 邏輯相同,但計數器狀態必須同步。
  3. 實務建議改用成熟庫(OpenSSL、Crypto++、libsodium),避免手刻模式實作引入漏洞。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved