我今天一直在努力寻找如何从二进制文件中读取并解密它。
在我的文件中,前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);
但这并没有正确解密数据。
我做错了什么?
答案 0 :(得分:3)
这里有很多东西有点臭
fopen
应使用"rb"
和"wb"
进行二进制模式memcmp
代替strcmp
fread
实际上是否读取了4个字节unsigned char
二进制数据(与符号扩展相关的陷阱更少以及溢出时的未定义行为)这是错误
if(fread(header, sizeof(header), 1, data) < 1)
sizeof (header)
此处为sizeof(byte*)
,而非32
正如您所期待的那样
以下是对c ++风格代码的快速回顾:更新为我的真实往返测试添加了一个长度字段(见下文)。
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
}
}
我还没有要测试的文件。
更新所以,我现在也做了 an encryptor.cpp
。
echo "Hello world" | ./encryptor
在base64中生成一个40字节的文件(sig + length + ciphertext = 4 + 4 + 32 = 40):
base64 test.bin
QUJDRAwAAABCaDMrpG0WEYePd7fI0wsHAQoNkUl1CjIBCg2RSXUKMg==
现在,解密测试就好了。请注意,我发现我需要确保对BLOCKSIZE进行填充,因此我添加了一个length
字段来存储明文的实际大小,以避免在解密后追踪垃圾。
您可以通过
查看往返echo 'Bye world!!' | ./encryptor && ./decryptor && cat out.bin
确实在解密后打印问候语。
注意具体 TODO
。你可能应该use StreamTransformationFilter
which adds padding as required.