C语言中用OpenSSL库实现3DES CBC解密遇密钥长度异常求助
解决3DES CBC解密16字节密钥失效的问题
你遇到的核心问题是单DES的密钥调度逻辑无法适配16字节的双密钥3DES场景——16字节密钥属于双密钥3DES(2TDEA),需要用OpenSSL专门的3DES EDE(Encrypt-Decrypt-Encrypt)模式接口处理,而非单DES的流程。
问题根源
你当前代码用的是DES_key_schedule(单DES密钥调度),但16字节密钥对应的是双密钥3DES:加密时执行K1加密 → K2解密 → K1加密,解密时则是K1解密 → K2加密 → K1解密。单DES的处理逻辑完全不匹配这个三次操作的流程,自然会导致解密结果错误。
修改后的解密函数示例
下面是适配16字节双密钥3DES CBC解密的代码:
#include <openssl/des.h> #include <string.h> int CBC_3Des_Decrypt(unsigned char *data, int data_len, unsigned char *okey, unsigned char *out_data, int *out_len) { // 双密钥3DES需要两个独立的密钥调度 DES_key_schedule ks1, ks2; DES_cblock ivec = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // 必须与加密时的IV完全一致 DES_cblock key1, key2; int ret = -1; // 1. 拆分16字节密钥为两个8字节DES密钥 if (strlen((char*)okey) != 16) { // 密钥长度不符合双密钥3DES要求,可根据需求扩展兼容8/24字节 return ret; } memcpy(key1, okey, 8); memcpy(key2, okey + 8, 8); // 2. 设置密钥调度(自动调整奇偶校验并检查有效性) if (DES_set_key_checked(&key1, &ks1) != 0 || DES_set_key_checked(&key2, &ks2) != 0) { // 密钥无效(奇偶位错误等),若确认密钥合法可改用DES_set_key_unchecked跳过检查 return ret; } // 3. 执行双密钥3DES CBC解密(EDE2模式) // 注意:输入data_len必须是8字节的倍数,3DES块大小固定为8字节 *out_len = data_len; DES_ede2_cbc_encrypt(data, out_data, data_len, &ks1, &ks2, &ivec, DES_DECRYPT); // 4. 去除PKCS#7填充(如果加密时使用了填充) // 假设最后一个字节为填充长度,比如缺n字节就填充n个0x0n unsigned char pad_len = out_data[*out_len - 1]; if (pad_len > 0 && pad_len <= 8) { *out_len -= pad_len; out_data[*out_len] = '\0'; // 确保字符串正常结束 } ret = 0; return ret; }
关键注意事项
- 多密钥长度兼容:如果需要同时支持8字节(单DES)、16字节(双密钥3DES)、24字节(三密钥3DES),可增加长度判断分支:
- 8字节:使用单DES的
DES_ncbc_encrypt - 16字节:使用
DES_ede2_cbc_encrypt - 24字节:使用
DES_ede3_cbc_encrypt(拆分3个8字节密钥)
- 8字节:使用单DES的
- IV一致性:加密和解密必须使用完全相同的初始化向量(IV),否则解密结果会完全混乱。如果加密时IV不是全0,要同步传入解密函数。
- 填充处理:3DES要求输入数据长度是8字节的倍数,加密时通常用PKCS#7填充补足长度,解密后必须去除填充才能得到原始明文。
- 密钥奇偶校验:DES密钥的第8位是奇偶校验位,
DES_set_key_checked会自动检查并调整;若密钥是外部传入的已处理过奇偶位的合法密钥,可改用DES_set_key_unchecked跳过检查。
内容的提问来源于stack exchange,提问作者Majid Hajibaba
相关产品推荐
相关产品推荐

