文件的2倍XORcypher加密不会产生相同的文件

问题描述

我试图用XORencryption用c ++加密图像文件。 它运作良好,但是当我用相同的代码解密时,我无法打开图像,我认为它们不相同,但是在XORencryption中,它们必须相同

这是代码

void xor_encrypt(std::string const& path) {
    char key[65] = "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08";
    std::ifstream input{ path,std::ios::binary };
    std::ofstream output;
    output = std::ofstream{ path + ".hafnium",/*added*/ std::ios::binary };

    char buffer[64];

    while (input.read(buffer,64)) {
        for (size_t i = 0; i < 64; i++) {
            buffer[i] ^= key[i];
        }
        output.write(buffer,/*added*/  input.gcount());
    }

    input.close();
    std::remove(path.c_str());
}

这里是3个文件:原始图像,加密图像和2倍加密图像

[1]原始图片https://i.stack.imgur.com/VKHKU.jpg [2]已将图像加密1次:https://mega.nz/file/BUMG2I7K#G3PsUeYCwtTCOj2cYSH47t67_WafRZQsRHyIims-EW0 [3]使用xor加密图像2次:https://mega.nz/file/FUMywI5I#mvI6Ge2nEw19fDfTEVso7hKMFSggRJcGJ7_g9178LMQ

我看到的文件之间唯一的区别是它们的大小不一样

为什么用xor加密2次的图像不能产生相同的文件? 谢谢答案

编辑:感谢您的回答,它对于图像文件效果很好,但是当我拍摄其他文件(如视频)时,它就不再起作用了:

原始视频:https://mega.nz/file/BYU3hQJI#JugOnHZ6_ajnRqHqc18j_j54MqFoIXAUHITSMxbAo48 加密的视频:https://mega.nz/file/JAMFXCRK#DxYqKAvCqda18oC47qOH0Wiec1bmJ7hSlmypczS9LXE 加密的2次视频:https://mega.nz/file/VVUT1KiA#f0vf43PkEssAmoHuPIcY722kd1p7nvQheIlIwFkmrzk

解决方法

这实际上是某种buffer underflow

文件结尾是问题。

您使用input.read(buffer,64)进行阅读,并且上次执行此操作时,它的阅读量可能少于64个字符,但更少。

然后,您仍然要写入64个字符(您只需从数组中写入64个字符,其内容就来自之前)。

使用下面的代码编写尽可能多的内容:

while (input.read(buffer,64)) {
        for (size_t i = 0; i < 64; i++) {
            buffer[i] ^= key[i];
        }
        output.write(buffer,input.gcount());
    }

它使用gcount来计数读取的字符数。

如果您也有二进制输入,我也建议您编写二进制。

output = std::ofstream{ path + ".hafnium",std::ios::binary };
,

dan1st已经发现没有考虑实际读取的字节数的问题,并且提到需要以二进制方式处理两个文件。 不建议这样做,如果您希望该程序在Windows上正常运行,则需要这样做(如果仅处理文本,则可能会逃脱,但是一个奇怪的文件会咬住您)。但是,我想注意三件事。

我看到的第一个问题是原始文件不匹配。 imgur链接未提供您使用的文件(imgur可能已对其进行了重新处理)。

第二,加密文件丢失 个字节。不计算读取的字节数的错误会使您的某些文件更大(它们将被填充为64字节,并带有一些纯文本字节)。我怀疑这可能是由于未使用二进制模式引起的。

第三,您正在使用64个字符的十六进制键执行预期的操作。您的密钥是由字符'9','f','8','6'组成的...您只对文件的一部分进行了异化处理。您可能想做的是使用{0x9f,0x86、0xd0、0x81、0x88 ...}进行异或运算,即,您应该将十六进制字符串转换为字节并对其进行异或运算。仍然可以很容易地将其破坏,但这将是使用此256位密钥的正确方法。