CBC模式:Cipher Block Chaining mode(密码分组链接模式)
CBC模式的加解密
CBC模式中,首先将明文分组与前一个密文分组进行XOR运算,然后再进行加密。密文分组像链条一样相互连接在一起。
CBC模式的加密流程图
CBC模式的解密流程图
将一个分组的加密过程分离出来,对ECB模式和CBC模式进行比较,ECB模式只进行了加密,而CBC模式则在加密之前进行了一次XOR。
ECB模式与CBC模式的比较
初始化向量
当加密第一个明文分组时,由于不存在”前一个密文分组“,因此需要事先准备一个长度为一个分组的比特序列来替代”前一个密文分组“,这个比特序列称为初始化向量,通常缩写为IV。通常,每次加密时都会随机产生一个不同的比特序列来作为初始化向量。
注:在UDS 27hex服务中不同的初始化向量可以代表着不同的解锁等级。
应用代码:演示加密和解密过程。
/*** @file mainCBC.c* @author jimu (minijimu@foxmail.com)* @brief * @version 0.1* @date 2024-09-02* * @addtogroup 《图解密技术-第3版》* @copyright Copyright (c) 2024* */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "aes.h"// 假设我们有一个密钥和一个初始化向量(IV)
uint8_t key[AES_KEYLEN] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
uint8_t iv[AES_BLOCKLEN] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};// 加密函数
void encrypt(uint8_t *plaintext, uint8_t *ciphertext, size_t length)
{uint8_t *padded_text = (uint8_t *)malloc(length);memset(padded_text, 0, length);memcpy(padded_text, plaintext, length);AES_ctx ctx;AES_init_ctx_iv(&ctx, key, iv);if (length % AES_BLOCKLEN != 0){printf("Error: Plaintext length must be a multiple of AES block size.\n");exit(1);}AES_CBC_encrypt_buffer(&ctx, padded_text, length);memcpy(ciphertext, padded_text, length);free(padded_text);
}// 解密函数
void decrypt(uint8_t *ciphertext, uint8_t *decryptedtext, size_t length)
{AES_ctx ctx;AES_init_ctx_iv(&ctx, key, iv);if (length % AES_BLOCKLEN != 0){printf("Error: Ciphertext length must be a multiple of AES block size.\n");exit(1);}AES_CBC_decrypt_buffer(&ctx, ciphertext, length);memcpy(decryptedtext, ciphertext, length);
}int main()
{// 假设我们有一个明文消息const uint8_t plaintext[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00};size_t plaintext_len = sizeof(plaintext);// 虽然plaintext_len 是 AES_BLOCKLEN 的倍数,但是在加密和解密之前,我们需要确保 plaintext_len 是 AES_BLOCKLEN 的倍数。// 当前可认为是无填充模式。if (plaintext_len % AES_BLOCKLEN != 0){plaintext_len = (plaintext_len / AES_BLOCKLEN + 1) * AES_BLOCKLEN;}// 为密文和明文缓冲区分配内存uint8_t *ciphertext = (uint8_t *)malloc(plaintext_len);uint8_t *decryptedtext = (uint8_t *)malloc(plaintext_len);printf("IV: ");for (size_t i = 0; i < AES_BLOCKLEN; i++){printf("%02x", iv[i]);}printf("\n");printf("plaintext: ");for (size_t i = 0; i < sizeof(plaintext); i++){printf("%02x", plaintext[i]);}printf("\n");// 加密encrypt((uint8_t *)plaintext, ciphertext, plaintext_len);// 打印密文printf("Ciphertext text:");for (size_t i = 0; i < plaintext_len; i++){printf("%02x", ciphertext[i]);}printf("\n");// 解密decrypt(ciphertext, decryptedtext, plaintext_len);// 打印解密后的明文// printf("Decrypted text: %s\n", decryptedtext);printf("Decrypted text: ");for (size_t i = 0; i < plaintext_len; i++){printf("%02x", decryptedtext[i]);}printf("\n");// 使用 memcmp 比较原始明文和解密后的文本if (memcmp(plaintext, decryptedtext, plaintext_len) == 0){printf("Decryption successful!\n");}else{printf("Decryption failed!\n");}// 释放内存free(ciphertext);free(decryptedtext);getchar();return 0;
}
- 对比代码加密和工具加密的结果
代码简述
- 定义明文
plaintext
和其长度plaintext_len
。 - 确保
plaintext_len
是 AES 块大小的倍数。 - 分配内存用于存储密文和解密后的明文。
- 打印初始化向量(IV)和明文。
- 调用
encrypt
函数加密明文。 - 打印密文。
- 调用
decrypt
函数解密密文。 - 打印解密后的明文。
- 比较原始明文和解密后的明文,确认解密成功。
- 释放内存。
CBC模式应用场景
- 文件加密 :CBC 模式适合于加密静态文件,如备份文件或存储在硬盘上的数据。
- 通信加密 :在网络通信中,CBC 模式可用于加密数据包,尤其是在需要确保数据块间相关性的场景下。
- 数据库加密 :在数据库中存储敏感信息时,可以使用 CBC 模式来加密记录或字段。
实际应用注意事项
- IV 的管理 :IV 应该是随机的,并且对于每个加密操作都是唯一的。IV 需要与密文一起存储或传输,以便解密时使用。
- 填充机制 :选择合适的填充机制,并确保解密时正确去除填充。
- 完整性检查 :单独使用 CBC 模式无法提供数据完整性验证。通常需要结合 MAC(Message Authentication Code)或数字签名来确保数据的完整性和真实性。
并且对于每个加密操作都是唯一的。IV 需要与密文一起存储或传输,以便解密时使用。 - 填充机制 :选择合适的填充机制,并确保解密时正确去除填充。
- 完整性检查 :单独使用 CBC 模式无法提供数据完整性验证。通常需要结合 MAC(Message Authentication Code)或数字签名来确保数据的完整性和真实性。