使用密文 Crypto++ CBC AES 加密存储 IV
您使用的某些代码对我来说有点不寻常。我会挑选一些东西,向你展示一些 Crypto++ 的方法。
在开始之前,请查看Crypto++ wiki 上的Pipelines and Pumping Data 。请记住,数据从源流向接收器。在数据之间遇到转换数据的过滤器。
std::ifstream fin(file_path, std::ios::binary);
if (!fin)
{
std::cout << "error";
}
std::ostringstream ostrm;
ostrm << fin.rdbuf();
std::string plaintext(ostrm.str());
fin.close();
Crypto++FileSource
有一个构造函数,它接受一个std::istream
. 您可以执行以下操作。另请参阅FileSource
Crypto++ wiki。
std::ifstream fin(file_path, std::ios::binary);
FileSource source(fin, true /*pump all*/, NULLPTR);
...
AES::Encryption aesEncryption(key, CryptoPP::AES::MAX_KEYLENGTH);
CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv);
ExternalCipher
用于 FIPS DLL。您可以在没有 DLL 的情况下使用它们,但它们存在于 DLL 中。通常你使用:
CBC_Mode<AES>::Encryption encryptor;
此外,您通常希望避免仅使用机密模式。通常,您希望使用Authenticated Encryption操作模式。它提供机密性和真实性。
Crypto++ 提供 CCM、EAX 和 GCM 认证的加密操作模式。OCB 和 EAX 是非常好的选择。EAX 模式记录在Crypto++ wiki 上的EAX 模式中。OCB 目前不可用。我们正准备签入 OCB 模式。
现在,我想将加密的字符串写入文件,并与它一起存储 IV,因为 iv 不需要保密,最好是在密文的开头或结尾
使用类似下面的东西。我没有编译它,所以你需要修正错别字。
AutoSeededRandomPool prng;
SecByteBlock key(AES::MAXIMUM_KEYLENGTH), iv(AES::BLOCKSIZE);
RandomNumberSource rs1(prng, AES::MAXIMUM_KEYLENGTH, new ArraySink(key, key.size()));
RandomNumberSource rs2(prng, AES::BLOCKSIZE, new ArraySink(iv, iv.size()));
HexEncoder encoder(new FileSink(std::cout));
std::cout << "Key: ";
encoder.Put(key, key.size());
encoder.MessageEnd();
std::cout << std::endl;
std::cout << "IV: ";
encoder.Put(iv, iv.size());
encoder.MessageEnd();
std::cout << std::endl;
EAX<AES>::Encryption encryptor;
encryptor.SetKeyWithIV(key, key.size(), iv, iv.size());
// Plaintext message
std::string message;
// Output file
FileSink file("message.enc");
// Source wrappers
ArraySource as(iv, iv.size(), true,
new Redirector(file));
// Source wrapper
StringSource ss(message, true,
new StreamTransformationFilter(encryptor,
new Redirector(file)));
当我尝试解密此文件时,如何分别提取 iv 和密文?
使用类似下面的东西。
// Key is from previous example. It cannot change
SecByteBlock key(AES::MAXIMUM_KEYLENGTH), iv(AES::BLOCKSIZE);
FileSource fs("message.enc", false /* DO NOT Pump All */);
// Attach new filter
ArraySink as(iv, iv.size());
fs.Attach(new Redirector(as));
fs.Pump(AES::BLOCKSIZE); // Pump first 16 bytes
EAX<AES>::Decryption decryptor;
decryptor.SetKeyWithIV(key, key.size(), iv, iv.size());
// Detach previously attached filter, attach new filter
ByteQueue queue;
fs.Detach(new StreamTransformationFilter(decryptor, new Redirector(queue)));
fs.PumpAll(); // Pump remainder of bytes
加密的数据将在一个ByteQueue
. 它不提供类似 C++ 迭代器的功能,如指针和大小。要从中获取数据,请将其ByteQueue
传输或复制到另一个过滤器或接收器:
SecByteBlock block(queue.MaxRetrievable());
ArraySink sink(block, block.size());
queue.TransferTo(sink);
您可以从中获取数据ByteQueue
并将其放入std::string
:
std::string recovered;
StringSink sink(recovered);
queue.TransferTo(sink);
您可以使用以下命令打印从文件中恢复的 IV:
HexEncoder encoder(new FileSink(std::cout));
std::cout << "IV: ";
encoder.Put(iv, iv.size());
encoder.MessageEnd();
std::cout << std::endl;