编辑我再次改写了这个问题,并提供了一个可以重现错误的最小工作示例。
我正在尝试使用 GCM 进行文件加密。我的下划线框架是 Qt。想法是这样的:
- 加载源文件 egajpg
- 将 GCM 模式下的文件加密为 PDATA
- 放入 ADATA 存储单字节(目前,在实际应用中,这将更多地包含 IV、原始文件名等信息)
将 ADATA 附加到加密文件
加载加密文件并提取 ADATA/PDATA/MAC
- 以正确的顺序将此数据提供给 AuthenticatedDecryptionFilter 并期望将解密的文件存储到 FileSink
我需要一个循环来遍历未加密的文件并将文件泵入 AuthenticatedEncryptionFilter,因为我需要检查 isAlive 以在实际应用程序中进行线程处理。因此,我不能使用简单的流水线,必须在循环中手动处理数据。
现在解决问题
哈希验证在下面的代码上失败(在 derypt 上抛出异常)
#include <qdebug.h>
#include <CryptoPP/cryptlib.h>
#include <CryptoPP/gcm.h>
#include <CryptoPP/aes.h>
#include <CryptoPP/filters.h>
#include <CryptoPP/files.h>
#include <CryptoPP/gzip.h>
#include <qfile.h>
#include <qfileinfo.h>
using namespace CryptoPP;
using namespace std;
int main(int argc, char *argv[])
{
byte * key = new byte[16];
byte * iv = new byte[16];
memset(key, 0, 16);
memset(iv, 0, 16);
const int TAG_SIZE = 16;
const int BUFFER_SIZE = 4096;
byte keyLength = 16;
byte blockSize = 16;
const char * sourceFileName = "C:\\Users\\Tomas\\Documents\\Visual Studio 2013\\Projects\\testgcm\\Win32\\Debug\\source.jpg";
const char * sourceFileName2 = "C:\\Users\\Tomas\\Documents\\Visual Studio 2013\\Projects\\testgcm\\Win32\\Debug\\source2.jpg";
const char * destFileName = "C:\\Users\\Tomas\\Documents\\Visual Studio 2013\\Projects\\testgcm\\Win32\\Debug\\source.jpg.enc";
try
{
GCM< AES >::Encryption e;
e.SetKeyWithIV(key, keyLength, iv, blockSize);
AuthenticatedEncryptionFilter ef(e,
new FileSink(destFileName), false, TAG_SIZE
);
// AuthenticatedEncryptionFilter::ChannelPut
// defines two channels: "" (empty) and "AAD"
// channel "" is encrypted and authenticated
// channel "AAD" is authenticated
// this is the block for ADATA
QByteArray adata;
adata.append((char)1);
ef.ChannelPut("AAD", (const byte *)adata.data(), adata.size());
ef.ChannelMessageEnd("AAD");
FileStore fs(sourceFileName);
int mr = 0;
while (mr = fs.MaxRetrievable()){
fs.TransferTo(ef, BUFFER_SIZE,"");
}
ef.ChannelMessageEnd("");
// append ADATA to encrypted file
QFile file(QString::fromStdString(destFileName));
file.open(QIODevice::Append);
file.write(adata);
file.close();
// HELP: is the encrypted file in this format now? ENC_TEXT||MAC(TAG_SIZE)||HEADER(1)
}
catch (CryptoPP::BufferedTransformation::NoChannelSupport& e)
{
// The tag must go in to the default channel:
// "unknown: this object doesn't support multiple channels"
cerr << "Caught NoChannelSupport..." << endl;
cerr << e.what() << endl;
cerr << endl;
}
catch (CryptoPP::AuthenticatedSymmetricCipher::BadState& e)
{
// Pushing PDATA before ADATA results in:
// "GMC/AES: Update was called before State_IVSet"
cerr << "Caught BadState..." << endl;
cerr << e.what() << endl;
cerr << endl;
}
catch (CryptoPP::InvalidArgument& e)
{
cerr << "Caught InvalidArgument..." << endl;
cerr << e.what() << endl;
cerr << endl;
}
// DECRYPTION
try
{
// now extract ADATA and MAC from enc file
QFile file(QString::fromStdString(destFileName));
file.open(QIODevice::ReadOnly);
file.seek(file.size() - 1);
// ADATA
QByteArray adata = file.read(1);
// exract MAC
file.seek(file.size() - 1 - TAG_SIZE);
QByteArray mac = file.read(TAG_SIZE);
GCM< AES >::Decryption d;
d.SetKeyWithIV(key, keyLength, iv);
// Object will not throw an exception
// during decryption\verification _if_
// verification fails.
AuthenticatedDecryptionFilter df(d, new FileSink(sourceFileName2),
AuthenticatedDecryptionFilter::MAC_AT_BEGIN |
AuthenticatedDecryptionFilter::THROW_EXCEPTION, TAG_SIZE);
df.ChannelPut("", (const byte*)mac.data(), mac.size());
// The order of the following calls are important
df.ChannelPut("AAD", (const byte*)adata.data(), adata.size());
// open enc file
FileStore fs(destFileName);
// when we read the file, we dont care for the ADATA and TAG, so we omit it
int omitSize = (adata.size() + mac.size());
// max retrievable (for FileStore this is how many bytes are not read yet)
int mr = 0;
// get part without tag and footer
while (((mr = fs.MaxRetrievable()) > omitSize)){
mr = ((mr - omitSize) < BUFFER_SIZE) ? (mr - omitSize) : BUFFER_SIZE;
fs.TransferTo(df, mr, "");
}
// we pumped teh whole filestore into df. it was supposed to be pumping it to GUnzip and then to FileSink
// and signal this is all
df.ChannelMessageEnd("AAD");
df.ChannelMessageEnd("");
}
catch (CryptoPP::InvalidArgument& e)
{
cerr << "Caught InvalidArgument..." << endl;
cerr << e.what() << endl;
cerr << endl;
}
catch (CryptoPP::AuthenticatedSymmetricCipher::BadState& e)
{
// Pushing PDATA before ADATA results in:
// "GMC/AES: Update was called before State_IVSet"
cerr << "Caught BadState..." << endl;
cerr << e.what() << endl;
cerr << endl;
}
catch (CryptoPP::HashVerificationFilter::HashVerificationFailed& e)
{
cerr << "Caught HashVerificationFailed..." << endl;
cerr << e.what() << endl;
cerr << endl;
}
}
我怀疑我以错误的方式将信息输入解密器,但我正在关注官方 CryptoPP 示例。
请帮忙,谢谢