Хранение IV с шифрованным текстом Crypto ++ CBC AES шифрование

Я пытаюсь зашифровать (и расшифровать после) файл с использованием AES в режиме CBC и библиотеки Crypto ++

Вот что я уже сделал:

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();

Затем я зашифровываю эту строку, используя ключ и ранее сгенерированный 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 байт, но здесь я полностью потерян и не знаю, как это сделать.

1

Решение

Хранение IV с шифрованным текстом Crypto ++ CBC AES шифрование

Часть кода, который вы используете, немного необычна для меня. Я выберу пару вещей и покажу вам некоторые способы Crypto ++.

Прежде чем начать, взгляните на Трубопроводы а также Насосные данные на 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();

Крипто ++ FileSource имеет конструктор, который принимает std::istream, Вы могли бы сделать что-то вроде следующего. Также см FileSource на Crypto ++ вики.

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. Обычно вы используете:

 CBC_Mode<AES>::Encryption encryptor;

Кроме того, вы обычно хотите избежать Конфиденциальность только Режим. Обычно вы хотите использовать Аутентифицированное шифрование режим работы. Это обеспечивает конфиденциальность и подлинность.

Crypto ++ обеспечивает режимы шифрования с аутентификацией CCM, EAX и GCM. OCB и EAX — очень хороший выбор. Режим EAX задокументирован в EAX Mode на Crypto ++ вики. 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;
1

Другие решения

StringSink имеет следующую документацию:

StringSink служит местом назначения для строковых данных в парадигме конвейерной обработки. Данные могут быть двоичными или ASCII.

Так что, хотя это строка, это внутренне октет- или байтовая строка. Так что да, вы можете просто сохранить IV и зашифрованный текст таким образом.

Но чтобы быть уверенным, просто сравните длину результата с размером IV (16 байт) и размером зашифрованного текста вместе. Если он равен, то у вас все будет хорошо.

0

По вопросам рекламы [email protected]