C++加密解密问题解惑答疑
🏆本文收录于《全栈Bug调优(实战版)》专栏,主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
问题描述
给了一个加密文件 自行去构建加密解密
然后就是 写的解密函数是正确的 可以解出来,但是 加密回去,再次解密的时候就是乱码了
解密函数应该是没错的,不需要修改 那么加密函数错在哪了呢?
并且 加密回去再次解密的时候,前8个字节是正确的
就是从这以后是乱码
输出信息如下:
/*
解密过程 header_offset:7
--快捷纀?韐f?S?G?C揋播彚筈M6蜧T[??P:}?V?杙l粕|b~孂py阨?}耴?乫?餵∽A疤?墍.衒?敯犕棱呀杬@[橢?觼c??ue収嵮)d?xD?S[oC琱?`dURA????{{35t緥?I?砫k*/
原加密的txt 是:
–快捷方式: 复制 粘贴 增添 删除
可以私下解决酬谢,只要我能承担
std::vector<uint8_t> decryptBlock(const std::vector<uint8_t>& buffer, const std::vector<uint8_t>& key)
{if (buffer.size() != 8 || key.size() < 16){return {};}uint32_t value1 = _byteswap_ulong(*reinterpret_cast<const uint32_t*>(buffer.data()));uint32_t value2 = _byteswap_ulong(*reinterpret_cast<const uint32_t*>(buffer.data() + 4));uint32_t matrix[4];for (int i = 0; i < 4; ++i){matrix[i] = _byteswap_ulong(*reinterpret_cast<const uint32_t*>(key.data() + i * 4));}uint32_t rnd = 0xE3779B90;for (int i = 16; i > 0; --i){value2 -= (rnd + value1) ^ (matrix[2] + 16 * value1) ^ (matrix[3] + (value1 >> 5));uint32_t tmp = (rnd + value2) ^ (matrix[0] + 16 * value2) ^ (matrix[1] + (value2 >> 5));rnd += 1640531527;value1 -= tmp;}std::vector<uint8_t> result(8);*reinterpret_cast<uint32_t*>(result.data()) = _byteswap_ulong(value1);*reinterpret_cast<uint32_t*>(result.data() + 4) = _byteswap_ulong(value2);return result;
}
std::vector<uint8_t> decrypt(const std::vector<uint8_t>& body, const std::vector<uint8_t>& key)
{if (/*body.size() % 8 != 0 ||*/ key.size() != 16){return{};}std::vector<uint8_t> prev_block(8, 0);std::vector<uint8_t> prev_original_block(8, 0);std::vector<uint8_t> result(body.size());int resultIndex = 0;int remain_j = 0;for (size_t i = 0; i < body.size(); i += 8){std::vector<uint8_t> decrypt_block(8);for (int k = 0; k < 8; k++){decrypt_block[k] = prev_block[k] ^ body[i + k];}std::vector<uint8_t> block = decryptBlock(decrypt_block, key);int j = remain_j;if (i == 0){int header_offset = block[0] & 0x07;j = header_offset + 3;std::cout << "解密过程 header_offset:" << header_offset << std::endl;}for (; j < 8; j++){result[resultIndex++] = block[j] ^ prev_original_block[j];}if (j > 8){remain_j = j % 8;}else{remain_j = 0;}prev_block = block;prev_original_block = std::vector<uint8_t>(body.begin() + i, body.begin() + i + 8);}int byteword = 0;while (resultIndex > 0 && result[resultIndex - 1] == 0x0){byteword++;/* --resultIndex;result.resize(resultIndex);*/}/*if (byteword != 7){AfxMessageBox(_T("删除字节数不为7!"));}*/return result;
}
std::vector<uint8_t> encryptBlock(const std::vector<uint8_t>& buffer, const std::vector<uint8_t>& key)
{if (buffer.size() != 8 || key.size() < 16){return {};}uint32_t value1 = _byteswap_ulong(*reinterpret_cast<const uint32_t*>(buffer.data()));uint32_t value2 = _byteswap_ulong(*reinterpret_cast<const uint32_t*>(buffer.data() + 4));uint32_t matrix[4];for (int i = 0; i < 4; ++i){matrix[i] = _byteswap_ulong(*reinterpret_cast<const uint32_t*>(key.data() + i * 4));}uint32_t rnd = 0xE3779B90 + (16 * 1640531527);for (int i = 0; i < 16; ++i){rnd -= 1640531527;uint32_t tmp = (rnd + value2) ^ (matrix[0] + 16 * value2) ^ (matrix[1] + (value2 >> 5));value1 += tmp;value2 += (rnd + value1) ^ (matrix[2] + 16 * value1) ^ (matrix[3] + (value1 >> 5));}std::vector<uint8_t> result(8);*reinterpret_cast<uint32_t*>(result.data()) = _byteswap_ulong(value1);*reinterpret_cast<uint32_t*>(result.data() + 4) = _byteswap_ulong(value2);return result;
}
std::vector<uint8_t> encrypt(const std::vector<uint8_t>& body, const std::vector<uint8_t>& key)
{int m = 7; // 你可以根据需要动态生成if (key.size() != 16){return {};}// 计算 jint j = m + 3;std::vector<uint8_t> padded_plaintext(body.size() + j);for (int k = 0; k < j; k++){padded_plaintext[k] = 0xFF; // 填充 0x00 或其他任意值(填充的值不能小于7,不然后续有影响)}for (size_t k = 0; k < body.size(); k++){padded_plaintext[k + j] = body[k];}padded_plaintext[0] = (padded_plaintext[0] & 0xF8) | (m & 0x07);std::vector<uint8_t> prev_block(8, 0);std::vector<uint8_t> encrypted(padded_plaintext.size());std::vector<uint8_t> prev_original_block(8, 0);for (size_t i = 0; i < padded_plaintext.size(); i += 8){std::vector<uint8_t> block(8);for (int k = 0; k < 8; k++){block[k] = padded_plaintext[i + k] ^ prev_block[k];}std::vector<uint8_t> encrypted_block = encryptBlock(block, key);for (int k = 0; k < 8; k++){encrypted[i + k] = encrypted_block[k] ^ prev_original_block[k];}prev_block = encrypted_block;prev_original_block = std::vector<uint8_t>(padded_plaintext.begin() + i, padded_plaintext.begin() + i + 8);}return encrypted;}
void OnBnClickedEncript() {std::string privateKey = "woshizhongguoren";std::vector<uint8_t> key(privateKey.begin(), privateKey.end());std::string XXX;std::ifstream file(m_outputPath, std::ios::binary);if (file.is_open()){std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());file.close();XXX = content;}std::vector<uint8_t> 文档测试(XXX.begin(), XXX.end());std::vector<uint8_t> 文档加密;std::vector<uint8_t> 文档解密;文档加密 = encrypt(文档测试, key);文档解密 = decrypt(文档加密, key);std::cout << 文档解密.data() << std::endl;}
解决方案
如下是上述问题的解决方案,仅供参考:
从你提供的信息来看,加密后的数据在解密时出现乱码,特别是前8个字节正确,后面出现问题。这种情况很可能是由于加密和解密过程中某些部分的逻辑不一致。常见的问题可能出现在以下几个方面:
问题排查方向:
-
填充处理问题:
你的encrypt
函数中有一个填充操作(填充了0xFF
)。而在解密过程中,可能没有正确处理这些填充值。具体体现在:padded_plaintext[k] = 0xFF;
填充时,确保填充规则的一致性,比如在解密时是否正确处理了填充位。如果填充不正确,解密后得到的内容可能会有额外的无意义字符或者乱码。
建议:查看加密和解密两边对填充字节的处理逻辑是否一致,并确保解密时能够正确去掉填充位。
-
前向反馈链 (CBC) 模式的逻辑问题:
加密和解密的算法是基于一种类似于 CBC(Cipher Block Chaining)的模式,每一个加密块与前一个块相关。你在加密和解密过程中分别维护了两个前一个块的变量prev_block
和prev_original_block
。在加密时,你使用了prev_original_block
来异或,但在解密时,可能并没有正确处理这个前向反馈链。例如,在加密函数中:
encrypted[i + k] = encrypted_block[k] ^ prev_original_block[k];
而解密时的相同部分是否对应上是需要检查的重点。如果反馈链的逻辑不对,后面的块解密会出现错误。
建议:仔细对比加密和解密过程中对
prev_block
和prev_original_block
的处理,确保它们在两边的使用是对称的。错误的块反馈会导致后续的块解密出错。 -
块加密和解密逻辑一致性:
你的encryptBlock
和decryptBlock
函数实现了基于简单算法的加密解密。这部分代码中使用了常量0xE3779B90
和1640531527
来计算加密轮次。需要确认
encryptBlock
和decryptBlock
中的轮次和加密算法的一致性。解密时使用的算法和加密时需要严格对称,如果有任何小的差异,解密的结果就会不正确。 -
块大小和数据对齐问题:
加密时,你的文本数据可能没有刚好是8字节的倍数,因此需要进行填充(如你使用的0xFF
填充)。解密时确保正确去除这些填充字节,否则会导致解密后包含了多余的字节。在
decrypt
函数中,你的代码尝试去除结尾的 0 字节:while (resultIndex > 0 && result[resultIndex - 1] == 0x0) {byteword++; }
建议:确认填充的字节值与解密时去除的字节匹配。如果加密时填充了
0xFF
,但解密时去掉的是0x00
,这将导致解密失败。
针对性调整建议:
-
调整填充策略:确保加密和解密过程中使用的填充值一致,特别是你在
encrypt
中使用0xFF
填充的部分。在解密时,你应该去掉这些特定的填充位。 -
检查 CBC 链接:确保
prev_block
和prev_original_block
在加密和解密中对应正确,特别是在解密时如何使用和更新这些变量。也可以尝试在加密和解密每个块时打印prev_block
和prev_original_block
来确保它们在两边是对称的。 -
对比加密解密块逻辑:仔细检查
encryptBlock
和decryptBlock
中的逻辑,特别是加密轮次是否一致,以及使用的常量是否完全相同。
调整示例:
std::vector<uint8_t> encrypt(const std::vector<uint8_t>& body, const std::vector<uint8_t>& key)
{int m = 7;if (key.size() != 16){return {};}int j = m + 3;std::vector<uint8_t> padded_plaintext(body.size() + j);// 填充 0xFFfor (int k = 0; k < j; k++){padded_plaintext[k] = 0xFF; }for (size_t k = 0; k < body.size(); k++){padded_plaintext[k + j] = body[k];}// 确保填充正确设置padded_plaintext[0] = (padded_plaintext[0] & 0xF8) | (m & 0x07);std::vector<uint8_t> prev_block(8, 0);std::vector<uint8_t> encrypted(padded_plaintext.size());std::vector<uint8_t> prev_original_block(8, 0);for (size_t i = 0; i < padded_plaintext.size(); i += 8){std::vector<uint8_t> block(8);for (int k = 0; k < 8; k++){block[k] = padded_plaintext[i + k] ^ prev_block[k];}std::vector<uint8_t> encrypted_block = encryptBlock(block, key);for (int k = 0; k < 8; k++){encrypted[i + k] = encrypted_block[k] ^ prev_original_block[k];}prev_block = encrypted_block;prev_original_block = std::vector<uint8_t>(padded_plaintext.begin() + i, padded_plaintext.begin() + i + 8);}return encrypted;
}
总结:
通过这些步骤,确保加密和解密中的逻辑和流程一致性,并特别留意填充、块反馈链以及加密解密算法中的轮次和常量的使用。
希望如上措施及解决方案能够帮到有需要的你。
PS:如若遇到采纳如下方案还是未解决的同学,希望不要抱怨&&急躁,毕竟影响因素众多,我写出来也是希望能够尽最大努力帮助到同类似问题的小伙伴,即把你未解决或者产生新Bug黏贴在评论区,我们大家一起来努力,一起帮你看看,可以不咯。
若有对当前Bug有与如下提供的方法不一致,有个不情之请,希望你能把你的新思路或新方法分享到评论区,一起学习,目的就是帮助更多所需要的同学,正所谓「赠人玫瑰,手留余香」。
☀️写在最后
如上问题有的来自我自身项目开发,有的收集网站,有的来自读者…如有侵权,立马删除。再者,针对此专栏中部分问题及其问题的解答思路或步骤等,存在少部分搜集于全网社区及人工智能问答等渠道,若最后实在是没能帮助到你,还望见谅!并非所有的解答都能解决每个人的问题,在此希望屏幕前的你能够给予宝贵的理解,而不是立刻指责或者抱怨!如果你有更优解,那建议你出教程写方案,一同学习!共同进步。
ok,以上就是我这期的Bug修复内容啦,如果还想查找更多解决方案,你可以看看我专门收集Bug及提供解决方案的专栏《CSDN问答解惑-专业版》,都是实战中碰到的Bug,希望对你有所帮助。到此,咱们下期拜拜。
码字不易,如果这篇文章对你有所帮助,帮忙给 bug菌 来个一键三连(关注、点赞、收藏) ,您的支持就是我坚持写作分享知识点传播技术的最大动力。
同时也推荐大家关注我的硬核公众号:「猿圈奇妙屋」 ;以第一手学习bug菌的首发干货,不仅能学习更多技术硬货,还可白嫖最新BAT大厂面试真题、4000G Pdf技术书籍、万份简历/PPT模板、技术文章Markdown文档等海量资料,你想要的我都有!
📣关于我
我是bug菌,CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云2023年度十佳博主,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿哇。