c++ - 使用密文 Crypto++ CBC AES 加密存储 IV

标签 c++ encryption aes crypto++ initialization-vector

我正在尝试在 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++ 方法。

开始之前,请先查看 PipelinesPumping 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/

相关文章:

c++ - 左右移动负整数是否定义了行为?

Spring Config Server "="符号加密问题

c++ - 'function1' 和 'function2' 之间的歧义 (C++)

c++ - 使用点和单元手动将网格插入 CGAL

php - 从 mysql pdo php 解密的值

php - 如何使用aes解密php mysql中的加密数据?

c# - "Padding is invalid and cannot be removed"- 这段代码有什么问题?

encryption - AES(128 或 256)加密是否会扩展数据?如果是这样,幅度是多少?

c++ - 是否可以强制 CMake 在其他项目类型生成时生成 Visual Studio 项目?

php - 如何测试浏览器以查看它是否支持 128 位加密?