【发布时间】:2020-09-04 09:35:48
【问题描述】:
我需要用 crypto++ 加密大文件(多 GB)。我设法在帮助我创建以下 2 个功能的文档中找到了一个示例:
bool AESEncryptFile(const std::string& clearfile, const std::string& encfile, const std::string& key) {
try {
byte iv[CryptoPP::AES::BLOCKSIZE] = {};
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encryptor;
encryptor.SetKeyWithIV((unsigned char*)key.c_str(), CryptoPP::AES::DEFAULT_KEYLENGTH, iv);
CryptoPP::StreamTransformationFilter filter(encryptor);
CryptoPP::FileSource source(clearfile.c_str(), false);
CryptoPP::FileSink sink(encfile.c_str());
source.Attach(new CryptoPP::Redirector(filter));
filter.Attach(new CryptoPP::Redirector(sink));
const CryptoPP::word64 BLOCK_SIZE = 4096;
CryptoPP::word64 processed = 0;
while (!EndOfFile(source) && !source.SourceExhausted()) {
source.Pump(BLOCK_SIZE);
filter.Flush(false);
processed += BLOCK_SIZE;
}
filter.MessageEnd();
return true;
} catch (const CryptoPP::Exception& ex) {
return false;
}
}
bool AESDecryptFile(const std::string& encfile, const std::string& clearfile, const std::string& key) {
try {
byte iv[CryptoPP::AES::BLOCKSIZE] = {};
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decryptor;
decryptor.SetKeyWithIV((unsigned char*)key.c_str(), CryptoPP::AES::DEFAULT_KEYLENGTH, iv);
CryptoPP::StreamTransformationFilter filter(decryptor);
CryptoPP::FileSource source(encfile.c_str(), false);
CryptoPP::FileSink sink(clearfile.c_str());
source.Attach(new CryptoPP::Redirector(filter));
filter.Attach(new CryptoPP::Redirector(sink));
const CryptoPP::word64 BLOCK_SIZE = 4096;
CryptoPP::word64 processed = 0;
while (!EndOfFile(source) && !source.SourceExhausted()) {
source.Pump(BLOCK_SIZE);
filter.Flush(false);
processed += BLOCK_SIZE;
}
.
filter.MessageEnd();
return true;
} catch (const CryptoPP::Exception& ex) {
return false;
}
}
这很好用。在 8 GB 文件上,我使用的内存非常少。 但正如您所看到的,IV 是(现在为空)硬编码的,我想:
- 加密时,放在文件末尾。
- 解密时:从文件中获取 IV 以初始化解密器。
有没有办法用 crypto++ 做到这一点,或者我应该在编码/解密过程之后/之前手动处理它?
【问题讨论】:
-
次要问题,但是为什么要将IV放在“文件末尾”而不是开头?您必须在开始加密之前知道它,并且在解密之前需要它。因此,把它放在最后意味着你需要在文件上至少再做一个
seek(可能是两个)才能在解密之前提取它。 -
我并没有真正考虑过。在文件末尾而不是在开头添加数据似乎更容易。但不管对我来说什么都行 :)
-
把这些细节放在文件的开头是很常见的。例如github.com/fernet/spec/blob/master/Spec.md#token-format 描述了一种简单/简短/可读的格式,显示了事物的结构。我不知道
CryptoPP,所以无法直接提供帮助,但这种灵活性可能对其他人有所帮助。我还考虑使用一些身份验证(如 fernet)来确保数据没有被破坏/篡改。 -
我认为你可以写
filter.MessageEnd(0);,意思是消息结尾不会被传播。然后你可以将IV写入sink,当然之后再关闭它。
标签: c++ cryptography aes crypto++