gpt4 book ai didi

c++ - 谁能解释为什么我的 crypto++ 解密文件短 16 个字节?

转载 作者:太空宇宙 更新时间:2023-11-03 10:36:12 25 4
gpt4 key购买 nike

为了我可以将 AES 加密文本作为 std::istream 提供给解析器组件,我正在尝试创建一个包装 Vanilla 的 std::streambuf 实现crypto++ 加密/解密。

main() 函数调用以下函数来比较我的包装器与普通实现:

  • EncryptFile() - 使用我的 streambuf 实现加密文件
  • DecryptFile() - 使用我的 streambuf 实现解密文件
  • EncryptFileVanilla() - 使用 vanilla crypto++ 加密文件
  • DecryptFileVanilla() - 使用 vanilla crypto++ 解密文件

问题是虽然 EncryptFile()EncryptFileVanilla() 创建的加密文件是相同的。 DecryptFile() 创建的解密文件不正确,比 DecryptFileVanilla() 创建的文件少 16 个字节。可能并非巧合, block 大小也是 16。

我认为问题一定出在 CryptStreamBuffer::GetNextChar() 中,但我已经盯着它和 crypto++ 文档看了好几个小时。

谁能帮忙/解释一下?

也欢迎任何其他关于我的 std::streambuf 实现多么糟糕或幼稚的评论;-)

谢谢,

汤姆

// Runtime Includes
#include <iostream>

// Crypto++ Includes
#include "aes.h"
#include "modes.h" // xxx_Mode< >
#include "filters.h" // StringSource and
// StreamTransformation
#include "files.h"

using namespace std;

class CryptStreamBuffer: public std::streambuf {

public:

CryptStreamBuffer(istream& encryptedInput, CryptoPP::StreamTransformation& c);

CryptStreamBuffer(ostream& encryptedOutput, CryptoPP::StreamTransformation& c);

~CryptStreamBuffer();

protected:
virtual int_type overflow(int_type ch = traits_type::eof());

virtual int_type uflow();

virtual int_type underflow();

virtual int_type pbackfail(int_type ch);

virtual int sync();

private:
int GetNextChar();

int m_NextChar; // Buffered character

CryptoPP::StreamTransformationFilter* m_StreamTransformationFilter;

CryptoPP::FileSource* m_Source;

CryptoPP::FileSink* m_Sink;

}; // class CryptStreamBuffer

CryptStreamBuffer::CryptStreamBuffer(istream& encryptedInput, CryptoPP::StreamTransformation& c) :
m_NextChar(traits_type::eof()),
m_StreamTransformationFilter(0),
m_Source(0),
m_Sink(0) {

m_StreamTransformationFilter = new CryptoPP::StreamTransformationFilter(c, 0, CryptoPP::BlockPaddingSchemeDef::PKCS_PADDING);
m_Source = new CryptoPP::FileSource(encryptedInput, false, m_StreamTransformationFilter);
}

CryptStreamBuffer::CryptStreamBuffer(ostream& encryptedOutput, CryptoPP::StreamTransformation& c) :
m_NextChar(traits_type::eof()),
m_StreamTransformationFilter(0),
m_Source(0),
m_Sink(0) {

m_Sink = new CryptoPP::FileSink(encryptedOutput);
m_StreamTransformationFilter = new CryptoPP::StreamTransformationFilter(c, m_Sink, CryptoPP::BlockPaddingSchemeDef::PKCS_PADDING);
}

CryptStreamBuffer::~CryptStreamBuffer() {

if (m_Sink) {
delete m_StreamTransformationFilter;
// m_StreamTransformationFilter owns and deletes m_Sink.
}
if (m_Source) {
delete m_Source;
// m_Source owns and deletes m_StreamTransformationFilter.
}
}

CryptStreamBuffer::int_type CryptStreamBuffer::overflow(int_type ch) {

return m_StreamTransformationFilter->Put((byte)ch);
}

CryptStreamBuffer::int_type CryptStreamBuffer::uflow() {

int_type result = GetNextChar();

// Reset the buffered character
m_NextChar = traits_type::eof();

return result;
}

CryptStreamBuffer::int_type CryptStreamBuffer::underflow() {

return GetNextChar();
}

CryptStreamBuffer::int_type CryptStreamBuffer::pbackfail(int_type ch) {

return traits_type::eof();
}

int CryptStreamBuffer::sync() {

// TODO: Not sure sync is the correct place to be doing this.
// Should it be in the destructor?
if (m_Sink) {
m_StreamTransformationFilter->MessageEnd();
// m_StreamTransformationFilter->Flush(true);
}

return 0;
}

int CryptStreamBuffer::GetNextChar() {

// If we have a buffered character do nothing
if (m_NextChar != traits_type::eof()) {
return m_NextChar;
}

// If there are no more bytes currently available then pump the source
if (m_StreamTransformationFilter->MaxRetrievable() == 0) {
m_Source->Pump(1024);
}

// Retrieve the next byte
byte nextByte;
size_t noBytes = m_StreamTransformationFilter->Get(nextByte);
if (0 == noBytes) {
return traits_type::eof();
}

// Buffer up the next character
m_NextChar = nextByte;

return m_NextChar;
}

void InitKey(byte key[]) {

key[0] = -62;
key[1] = 102;
key[2] = 78;
key[3] = 75;
key[4] = -96;
key[5] = 125;
key[6] = 66;
key[7] = 125;
key[8] = -95;
key[9] = -66;
key[10] = 114;
key[11] = 22;
key[12] = 48;
key[13] = 111;
key[14] = -51;
key[15] = 112;
}

/** Decrypt using my CryptStreamBuffer */
void DecryptFile(const char* sourceFileName, const char* destFileName) {

ifstream ifs(sourceFileName, ios::in | ios::binary);
ofstream ofs(destFileName, ios::out | ios::binary);

byte key[CryptoPP::AES::DEFAULT_KEYLENGTH];
InitKey(key);

CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption decryptor(key, sizeof(key));

if (ifs) {
if (ofs) {
CryptStreamBuffer cryptBuf(ifs, decryptor);
std::istream decrypt(&cryptBuf);

int c;
while (EOF != (c = decrypt.get())) {
ofs << (char)c;
}
ofs.flush();
}
else {
std::cerr << "Failed to open file '" << destFileName << "'." << endl;
}
}
else {
std::cerr << "Failed to open file '" << sourceFileName << "'." << endl;
}
}

/** Encrypt using my CryptStreamBuffer */
void EncryptFile(const char* sourceFileName, const char* destFileName) {

ifstream ifs(sourceFileName, ios::in | ios::binary);
ofstream ofs(destFileName, ios::out | ios::binary);

byte key[CryptoPP::AES::DEFAULT_KEYLENGTH];
InitKey(key);

CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption encryptor(key, sizeof(key));

if (ifs) {
if (ofs) {
CryptStreamBuffer cryptBuf(ofs, encryptor);
std::ostream encrypt(&cryptBuf);

int c;
while (EOF != (c = ifs.get())) {
encrypt << (char)c;
}
encrypt.flush();
}
else {
std::cerr << "Failed to open file '" << destFileName << "'." << endl;
}
}
else {
std::cerr << "Failed to open file '" << sourceFileName << "'." << endl;
}
}

/** Decrypt using vanilla crypto++ */
void DecryptFileVanilla(const char* sourceFileName, const char* destFileName) {

byte key[CryptoPP::AES::DEFAULT_KEYLENGTH];
InitKey(key);

CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption decryptor(key, sizeof(key));

CryptoPP::FileSource(sourceFileName, true,
new CryptoPP::StreamTransformationFilter(decryptor,
new CryptoPP::FileSink(destFileName), CryptoPP::BlockPaddingSchemeDef::PKCS_PADDING
) // StreamTransformationFilter
); // FileSource
}

/** Encrypt using vanilla crypto++ */
void EncryptFileVanilla(const char* sourceFileName, const char* destFileName) {

byte key[CryptoPP::AES::DEFAULT_KEYLENGTH];
InitKey(key);

CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption encryptor(key, sizeof(key));

CryptoPP::FileSource(sourceFileName, true,
new CryptoPP::StreamTransformationFilter(encryptor,
new CryptoPP::FileSink(destFileName), CryptoPP::BlockPaddingSchemeDef::PKCS_PADDING
) // StreamTransformationFilter
); // FileSource
}

int main(int argc, char* argv[])
{
EncryptFile(argv[1], "encrypted.out");
DecryptFile("encrypted.out", "decrypted.out");
EncryptFileVanilla(argv[1], "encrypted_vanilla.out");
DecryptFileVanilla("encrypted_vanilla.out", "decrypted_vanilla.out");
return 0;
}

最佳答案

在使用 crypto++ 的调试版本后,发现缺少的是对 StreamTransformationFilter 的调用,通知它不会有更多来自源的信息,它应该结束最后几个字节的处理,包括填充。

CryptStreamBuffer::GetNextChar() 中:

替换:

// If there are no more bytes currently available then pump the source
if (m_StreamTransformationFilter->MaxRetrievable() == 0) {
m_Source->Pump(1024);
}

与:

// If there are no more bytes currently available from the filter then
// pump the source.
if (m_StreamTransformationFilter->MaxRetrievable() == 0) {
if (0 == m_Source->Pump(1024)) {
// This seems to be required to ensure the final bytes are readable
// from the filter.
m_StreamTransformationFilter->ChannelMessageEnd(CryptoPP::DEFAULT_CHANNEL);
}
}

我不声称这是最好的解决方案,只是我通过反复试验发现似乎有效的解决方案。

关于c++ - 谁能解释为什么我的 crypto++ 解密文件短 16 个字节?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3024127/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com