c语言 aes加密解密

99ANYc3cd6
预计阅读时长 24 分钟
位置: 首页 C语言 正文

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

c语言 aes加密解密
(图片来源网络,侵删)

第一步:准备工作(安装 OpenSSL)

在使用 OpenSSL 之前,你需要确保你的开发环境中已经安装了它。

在 Linux (如 Ubuntu/Debian) 上

sudo apt-get update
sudo apt-get install libssl-dev

在 macOS 上 (使用 Homebrew)

brew install openssl

在 Windows 上

  1. 访问 OpenSSL 官方下载页面:https://slproweb.com/products/Win32OpenSSL.html
  2. 下载 "Win64 OpenSSL v3.x.x" 安装包(推荐较新版本)。
  3. 运行安装程序,安装时,务必勾选 "Add OpenSSL to the system PATH" 选项,这样命令行和编译器才能找到它。
  4. 你还需要一个 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 选项。

c语言 aes加密解密
(图片来源网络,侵删)
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:

c语言 aes加密解密
(图片来源网络,侵删)
./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.

重要概念和最佳实践

  1. 不要自己实现 AES:AES 算法非常复杂,细节繁多,使用像 OpenSSL 这样经过严格审查和广泛使用的库是唯一安全可靠的选择。
  2. 密钥管理:代码中硬编码密钥是极其危险的,在实际应用中,密钥必须安全地生成、存储和传输,可以考虑使用密钥派生函数(如 PBKDF2, scrypt, Argon2)从用户密码中生成密钥。
  3. IV 的使用:IV 必须是唯一的,但对于给定的密钥,它不需要保密,每次加密操作都应使用一个全新的、随机的 IV,IV 会被直接附加在密文的前面或后面一起传输。
  4. 填充:AES 是一个块加密算法,它处理固定长度的数据块(128位,即16字节),如果明文长度不是16字节的整数倍,就需要进行填充,OpenSSL 的 EVP 接口会自动处理填充(PKCS#7 是最常见的填充方式)。
  5. 认证加密:仅仅加密数据是不够的,攻击者可能会篡改密文,为了确保数据的完整性和真实性,应该使用认证加密模式,如 AES-GCMAES-CCM,这些模式在加密的同时会生成一个认证标签,解密时会验证这个标签,以判断密文是否被篡改,OpenSSL 也支持这些高级模式。
-- 展开阅读全文 --
头像
织梦缩略图为何不变型?
« 上一篇 今天
dede如何调用文章属性?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]