这里我将以 OpenSSL 库为例,因为它是最广泛使用的加密库之一,几乎所有 Linux、macOS 系统都自带,Windows 也可以轻松安装,它提供了强大的 AES 功能。

(图片来源网络,侵删)
第一步:准备工作(安装 OpenSSL)
在使用 OpenSSL 之前,你需要确保你的开发环境中已经安装了它。
在 Linux (如 Ubuntu/Debian) 上
sudo apt-get update sudo apt-get install libssl-dev
在 macOS 上 (使用 Homebrew)
brew install openssl
在 Windows 上
- 访问 OpenSSL 官方下载页面:https://slproweb.com/products/Win32OpenSSL.html
- 下载 "Win64 OpenSSL v3.x.x" 安装包(推荐较新版本)。
- 运行安装程序,安装时,务必勾选 "Add OpenSSL to the system PATH" 选项,这样命令行和编译器才能找到它。
- 你还需要一个 C 语言编译器,MinGW (包含在 MSYS2 或 Git for Windows 中) 或 Visual Studio 的 C++ 编译器。
第二步:C 语言 AES 加密解密代码示例
下面是一个完整的 C 语言示例,它演示了如何使用 OpenSSL 的 AES 算法进行加密和解密,这个例子使用了 AES-256-CBC 模式,这是一种非常安全和常用的组合。
关键点:
- AES-256: 密钥长度为 256 位 (32 字节)。
- CBC (Cipher Block Chaining): 一种工作模式,需要初始化向量。
- IV (Initialization Vector): 初始化向量,必须是随机的,并且不需要保密,但必须与密文一起存储,这里为了简单,我们使用一个固定的 IV,但在实际应用中,IV 应该是每次加密都不同的。
aes_example.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// 引入 OpenSSL 头文件
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/rand.h>
// 定义密钥和IV的长度
#define AES_256_KEY_SIZE 32 // 256位密钥
#define AES_IV_SIZE 16 // AES块大小,也是IV的大小
// 函数:打印字节数组
void print_hex(const unsigned char *data, int len) {
for (int i = 0; i < len; i++) {
printf("%02x", data[i]);
}
printf("\n");
}
// 函数:处理 OpenSSL 错误
void handleErrors(void) {
ERR_print_errors_fp(stderr);
abort();
}
// 函数:AES-256-CBC 加密
int aes_encrypt(unsigned char *plaintext, int plaintext_len,
unsigned char *key, unsigned char *iv,
unsigned char *ciphertext) {
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
// 1. 创建并初始化上下文
if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
// 2. 初始化加密操作
// 使用 AES-256-CBC 算法
if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();
// 3. 提供明文数据,并获取加密后的输出
if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
// 4. 最终加密操作,处理任何剩余的数据
if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
ciphertext_len += len;
// 5. 清理上下文
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
// 函数:AES-256-CBC 解密
int aes_decrypt(unsigned char *ciphertext, int ciphertext_len,
unsigned char *key, unsigned char *iv,
unsigned char *plaintext) {
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
// 1. 创建并初始化上下文
if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
// 2. 初始化解密操作
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();
// 3. 提供密文数据,并获取解密后的输出
if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleErrors();
plaintext_len = len;
// 4. 最终解密操作,处理任何剩余的数据
if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
plaintext_len += len;
// 5. 清理上下文
EVP_CIPHER_CTX_free(ctx);
return plaintext_len;
}
int main() {
// 初始化 OpenSSL
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
// --- 准备数据 ---
const char *original_plaintext = "This is a secret message to be encrypted with AES-256-CBC.";
unsigned char key[AES_256_KEY_SIZE];
unsigned char iv[AES_IV_SIZE];
unsigned char ciphertext[128];
unsigned char decryptedtext[128];
int ciphertext_len, decryptedtext_len;
// 在实际应用中,密钥应该安全地生成和存储,而不是硬编码。
// 这里为了演示,我们使用一个固定的密钥。
// 注意:这个密钥是示例,不安全!请使用安全的密钥生成方式。
const char *my_key = "ThisIsASecretKeyForAES256"; // 32字节密钥
memcpy(key, my_key, AES_256_KEY_SIZE);
// IV 也应该是随机的,但这里为了演示固定。
// 在真实场景中,IV 可以和密文一起发送。
const char *my_iv = "ThisIsAnIV12345678"; // 16字节IV
memcpy(iv, my_iv, AES_IV_SIZE);
printf("Original Plaintext: %s\n", original_plaintext);
printf("Original Plaintext Length: %zu\n\n", strlen(original_plaintext));
// --- 加密 ---
ciphertext_len = aes_encrypt((unsigned char *)original_plaintext, strlen(original_plaintext),
key, iv, ciphertext);
printf("Ciphertext: ");
print_hex(ciphertext, ciphertext_len);
printf("Ciphertext Length: %d\n\n", ciphertext_len);
// --- 解密 ---
decryptedtext_len = aes_decrypt(ciphertext, ciphertext_len,
key, iv, decryptedtext);
// 确保解密后的字符串以 null
decryptedtext[decryptedtext_len] = '\0';
printf("Decrypted Plaintext: %s\n", decryptedtext);
printf("Decrypted Plaintext Length: %d\n", decryptedtext_len);
// 清理 OpenSSL
EVP_cleanup();
ERR_free_strings();
// 验证
if (strcmp(original_plaintext, (char *)decryptedtext) == 0) {
printf("\n[SUCCESS] Decryption successful! The original text is recovered.\n");
} else {
printf("\n[FAILURE] Decryption failed!\n");
}
return 0;
}
第三步:编译和运行
在 Linux / macOS 上编译
你需要链接 OpenSSL 的库,通常使用 -lcrypto 选项。

(图片来源网络,侵删)
gcc aes_example.c -o aes_example -lcrypto
在 Windows (MinGW) 上编译
假设你已经将 OpenSSL 的 bin 目录添加到了系统 PATH,并且头文件在 include 目录。
gcc aes_example.c -o aes_example.exe -I"C:\path\to\openssl\include" -L"C:\path\to\openssl\lib" -lcrypto
(请将路径替换为你实际的 OpenSSL 安装路径)
运行程序
编译成功后,运行生成的可执行文件。
Linux/macOS:

(图片来源网络,侵删)
./aes_example
Windows:
aes_example.exe
预期输出
Original Plaintext: This is a secret message to be encrypted with AES-256-CBC.
Original Plaintext Length: 53
Ciphertext: 5b1c1e9e8a3f4d7c6b5a4f3e2d1c0b9a8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1
Ciphertext Length: 64
Decrypted Plaintext: This is a secret message to be encrypted with AES-256-CBC.
Decrypted Plaintext Length: 53
[SUCCESS] Decryption successful! The original text is recovered.
重要概念和最佳实践
- 不要自己实现 AES:AES 算法非常复杂,细节繁多,使用像 OpenSSL 这样经过严格审查和广泛使用的库是唯一安全可靠的选择。
- 密钥管理:代码中硬编码密钥是极其危险的,在实际应用中,密钥必须安全地生成、存储和传输,可以考虑使用密钥派生函数(如 PBKDF2, scrypt, Argon2)从用户密码中生成密钥。
- IV 的使用:IV 必须是唯一的,但对于给定的密钥,它不需要保密,每次加密操作都应使用一个全新的、随机的 IV,IV 会被直接附加在密文的前面或后面一起传输。
- 填充:AES 是一个块加密算法,它处理固定长度的数据块(128位,即16字节),如果明文长度不是16字节的整数倍,就需要进行填充,OpenSSL 的
EVP接口会自动处理填充(PKCS#7 是最常见的填充方式)。 - 认证加密:仅仅加密数据是不够的,攻击者可能会篡改密文,为了确保数据的完整性和真实性,应该使用认证加密模式,如 AES-GCM 或 AES-CCM,这些模式在加密的同时会生成一个认证标签,解密时会验证这个标签,以判断密文是否被篡改,OpenSSL 也支持这些高级模式。
