【C语言】使用 OpenSSL 进行 AES CBC 加密与解密

发布于:2024-10-12 ⋅ 阅读:(6) ⋅ 点赞:(0)

使用 OpenSSL 进行 AES CBC 加密与解密

在这篇文章中,我们将使用 OpenSSL 库实现 AES CBC 模式的加密和解密功能。AES(高级加密标准)是一种对称加密算法,广泛应用于数据保护。本示例展示了如何使用 PKCS#7 填充标准来处理明文的长度,以及如何确保在加密和解密过程中正确管理密钥和初始化向量(IV)。

代码实现

下面是实现 AES CBC 加密与解密的完整代码:

#include <stdio.h>  
#include <string.h>  
#include <openssl/aes.h>  
#include <openssl/rand.h>  

// PKCS#7 去除填充的函数
int pkcs7_unpad(unsigned char *data, int len) {  
    int padding = data[len - 1];  
    if (padding < 1 || padding > AES_BLOCK_SIZE) {
        return -2;  // 错误的填充
    }
    for (int i = len - padding; i < len; i++) {
        if (data[i] != padding) return -1;  // 填充不正确
    }
    return len - padding; 
}

// PKCS#7 填充函数
void pkcs7_pad(unsigned char *plaintext, int plaintext_len, int block_size) {  
    int padding = block_size - (plaintext_len % block_size);  
    memset(plaintext + plaintext_len, padding, padding);
}

// AES CBC 解密函数
int aes_cbc_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext) {
    AES_KEY dec_key;  
    if (AES_set_decrypt_key(key, 256, &dec_key) < 0) {
        return -2;  // 设置解密密钥失败
    }

    int block_size = AES_BLOCK_SIZE;  
    if (ciphertext_len % block_size != 0) {
        return -3;  // 密文长度不是块大小的倍数
    }

    // 进行解密
    AES_cbc_encrypt(ciphertext, plaintext, ciphertext_len, &dec_key, iv, AES_DECRYPT);  
    int plaintext_len = pkcs7_unpad(plaintext, ciphertext_len);  
    if (plaintext_len < 0) {
        return plaintext_len;  // 填充去除失败
    }

    return plaintext_len;  
} 

// AES CBC 加密函数  
int aes_cbc_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext) {  
    AES_KEY enc_key;  
    AES_set_encrypt_key(key, 256, &enc_key);  

    int block_size = AES_BLOCK_SIZE;  
    int padding = block_size - (plaintext_len % block_size);  
    int ciphertext_len = plaintext_len + padding;  

    unsigned char plaintext2[ciphertext_len];
    memcpy(plaintext2, plaintext, plaintext_len);
    pkcs7_pad(plaintext2, plaintext_len, block_size);  

    AES_cbc_encrypt(plaintext2, ciphertext, ciphertext_len, &enc_key, iv, AES_ENCRYPT);  

    return ciphertext_len;  
}

int main() {
    // 假设的密钥和IV  
    unsigned char key[AES_BLOCK_SIZE * 2] = "your-256-bit-key-here-xxxxxxxxxx";  
    unsigned char iv[AES_BLOCK_SIZE] = "your-iv-here-xxx";  
    
    // 明文  
    unsigned char plaintext[] = "Hello,World";  
    int plaintext_len = strlen((char *)plaintext);  

    unsigned char *ciphertext_buffer = malloc(plaintext_len + AES_BLOCK_SIZE);  
    if (ciphertext_buffer == NULL) {  
        return 1;  
    }  
    
    int ret_len = aes_cbc_encrypt(plaintext, plaintext_len, key, iv, ciphertext_buffer);
    
    unsigned char iv2[AES_BLOCK_SIZE] = "your-iv-here-xxx";  
    unsigned char *plaintext_buffer2 = malloc(plaintext_len + AES_BLOCK_SIZE);  
    int code = aes_cbc_decrypt(ciphertext_buffer, ret_len, key, iv2, plaintext_buffer2);
    
    printf("Decrypted: %.*s\n", code, plaintext_buffer2);

    free(ciphertext_buffer);
    free(plaintext_buffer2);
    return 0;
}

代码分析

1. 填充与去填充

我们使用 PKCS#7 填充标准来处理明文长度。这种填充方式确保了明文的长度是块大小的倍数,便于后续的加密操作。

2. AES 加密与解密

aes_cbc_encrypt 函数负责加密明文,而 aes_cbc_decrypt 函数则负责解密密文。在这两个函数中,我们都使用了相同的密钥和初始化向量。

3. 主函数

main 函数中,我们定义了明文、密钥和 IV。我们调用加密和解密函数,并打印出解密后的结果。

总结

本文展示了如何使用 OpenSSL 实现 AES CBC 模式的加密与解密。通过合理的填充和去填充机制,我们确保了数据的完整性与安全性。在实际应用中,请确保密钥和 IV 的安全性,以防止潜在的安全风险。

补充

环境:安装OpenSSL

1. Ubuntu/Debian

打开终端,运行以下命令:

sudo apt update
sudo apt install openssl libssl-dev
2. CentOS

对于 CentOS ,可以使用以下命令:

sudo yum install openssl openssl-devel

编译

gcc -o main main.c -lcrypto