我正在尝试在 CBC 模式和 Crypto++ 库中使用 AES 加密(并在之后解密)
这是我已经做过的:
using namespace CryptoPP;
AutoSeededRandomPool rnd;
//generating the key and iv
SecByteBlock key(AES::MAX_KEYLENGTH);
rnd.GenerateBlock(key, key.size());
byte iv[AES::BLOCKSIZE];
rnd.GenerateBlock(iv, AES::BLOCKSIZE);
为了加密文件,我以二进制模式打开它,并将内容转储为字符串:
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();
然后,我使用之前生成的 key 和 iv 加密此字符串:
std::string ciphertext;
AES::Encryption aesEncryption(key, CryptoPP::AES::MAX_KEYLENGTH);
CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv);
StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(ciphertext));
stfEncryptor.Put(reinterpret_cast<const unsigned char*>(plaintext.c_str()), plaintext.length() + 1);
stfEncryptor.MessageEnd();
现在,我想将加密后的字符串写入一个文件,并用它存储 IV,因为 iv 不需要保密,最好在密文的开头或结尾
问题来了:IV是一个字节数组,密文是一个字符串,我需要将两者之一转换为另一种类型,还是我可以这样做:
std::ofstream fdout(file_path2, std::ios::binary);
if (!fdout)
{
std::cout << "error";
}
fdout << iv;
fdout << ciphertext;
fdout.close();
当我尝试解密这个文件时,如何分别提取 iv 和密文? IV 有 16 个字节长,但在这里我完全迷路了,我不知道该怎么做。
最佳答案
Storing the IV with the ciphertext Crypto++ CBC AES encryption
您使用的某些代码对我来说有点不寻常。我将挑出一些内容并向您展示一些 Crypto++ 方法。
开始之前,请先查看 Pipelines和 Pumping Data在 Crypto++ 维基上。请记住,数据从源流向接收器。在数据之间遇到转换数据的过滤器。
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操作模式。它提供 secret 性和真实性。
Crypto++ 提供 CCM、EAX 和 GCM 认证加密操作模式。 OCB和EAX都是非常好的选择。 EAX 模式记录在 EAX Mode在 Crypto++ 维基上。 OCB 目前不可用。我们正在准备入住 OCB 模式。
Now,i want to write the encrypted string to a file,and store the IV with it,since the iv doesn't need to be kept secret,ideally at the beginning or the end of the ciphertext
使用类似下面的内容。我没有编译它,所以你需要修正拼写错误。
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)));
When i will try to decrypt this file,how can i extract the iv and ciphertext separately ?
使用如下内容。
// 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;
关于c++ - 使用密文 Crypto++ CBC AES 加密存储 IV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45461770/