繁体   English   中英

如何正确使用crypto ++ Blowfish

[英]How to use crypto++ Blowfish correctly

我今天整天都在努力寻找如何从二进制文件读取并解密的方法。

在我的文件中,前4个字节描述了文件格式,后32个字节是标头,并使用Blowfish对其进行了加密。

所以我写了这段代码就能做到这一点:

string file = "C:\\test.bin";    

byte *header = new byte[32];

FILE *data = fopen(file.c_str(), "r");

if(data == NULL)
{
    return 1; //Error opening file!
}

char type[6];

type[5] = 0;

if(fread(type, sizeof(type) - 1, 1, data) < 1)
{
    return 2;
}

if(strcmp(type, "ABCD") != 0)
{
    return 3;
}

if(fread(header, sizeof(header), 1, data) < 1)
{
    return 2; //Error reading file!
}

vector<byte> key;

key.push_back(0xAA);
key.push_back(0xBB);
key.push_back(0xCC);
key.push_back(0xDD);
key.push_back(0xAA);
key.push_back(0xBB);
key.push_back(0xCC);
key.push_back(0xDD);

ECB_Mode<Blowfish>::Decryption decryption(key.data(), key.size());

byte out[32];

decryption.ProcessData(out, header, 32);

FILE *outer =  fopen("C:\\out.bin", "w");

fwrite (out, sizeof(byte), sizeof(out), outer);

但这不能正确解密数据。

我做错了什么?

这里有很多东西有点臭

  • 对于二进制模式, fopen应该使用"rb""wb"
  • 您应该使用memcmp而不是strcmp
  • 您不验证fread实际读取了4个字节
  • 对于二进制数据,您应该首选unsigned char (较少的陷阱与符号扩展和溢出时的未定义行为有关)
  • 如果您使用的是C ++,为什么要首先使用cstdlib,cstdio和cstring?
  • 这是一个错误

     if(fread(header, sizeof(header), 1, data) < 1) 

    sizeof (header)在这里是sizeof(byte*) ,而不是您期望的32

这是使用c ++样式的代码的快速回顾: Update为我的真实往返测试添加了一个length字段(请参见下文)。

decryptor.cpp

#include <fstream>
#include <algorithm>
#include <iterator>
#include <crypto++/blowfish.h>
#include <crypto++/modes.h>

static std::vector<byte> const key { 's','e','c','r','e','t' };
static byte const SIGNATURE[] = "ABCD"; //{ 'A','B','C','D' };

int main()
{
    if (std::ifstream data {"test.bin", std::ios::binary})
    {
        char type[] = { 0, 0, 0, 0 };

        if (!data.read(type, 4))
        {
            return 2;
        }

        auto mismatch = std::mismatch(std::begin(SIGNATURE), std::end(SIGNATURE), std::begin(type));

        if (mismatch.first != std::end(SIGNATURE))
        {
            return 3;
        }

        uint32_t length = 0;
        if (!data.read(reinterpret_cast<char*>(&length), sizeof(length))) // TODO use portable byte-order
        {
            return 4;
        }

        std::vector<byte> const ciphertext { std::istreambuf_iterator<char>(data), {} };
        // to read 32 bytes: 
        // std::copy_n(std::istreambuf_iterator<char>(data), 32, std::back_inserter(ciphertext));

        assert(data.good() || data.eof());
        assert(ciphertext.size() >= length);
        assert(ciphertext.size() % CryptoPP::Blowfish::BLOCKSIZE == 0);

        CryptoPP::ECB_Mode<CryptoPP::Blowfish>::Decryption decryption(key.data(), key.size());

        std::vector<char> plaintext(ciphertext.size());

        decryption.ProcessData(reinterpret_cast<byte*>(plaintext.data()), ciphertext.data(), plaintext.size());
        plaintext.resize(length); // trim padding

        std::ofstream out("out.bin", std::ios::binary);
        out.write(plaintext.data(), plaintext.size());
    } else
    {
        return 1; //Error opening file
    }
}

我没有文件可以测试。

更新因此,我现在也制作了一个encryptor.cpp

echo "Hello world" | ./encryptor

在base64中产生一个40字节的文件(sig + length +密文= 4 + 4 + 32 = 40):

base64 test.bin
QUJDRAwAAABCaDMrpG0WEYePd7fI0wsHAQoNkUl1CjIBCg2RSXUKMg==

现在,解密就可以了。 请注意,我发现我需要确保对BLOCKSIZE进行填充,因此,我添加了一个length字段来存储纯文本的实际大小,以避免解密后拖尾垃圾。

您可以通过以下方式查看往返

echo 'Bye world!!' | ./encryptor && ./decryptor && cat out.bin

确实确实在解密后将问候语打印回去。

特别注意TODO 您可能应该使用StreamTransformationFilter ,它会根据需要添加填充。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM