void c_crypto::encrypt_buffer(std::string &input, unsigned char key[AES_KEY_SIZE], unsigned char iv[AES_KEY_SIZE]) {
CryptoPP::AES::Encryption aesEncryption(key, AES_KEY_SIZE);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv);
CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(input));
stfEncryptor.Put(reinterpret_cast<const unsigned char*>(input.c_str()), input.length());
stfEncryptor.MessageEnd();
input = base64_encode(input);
}
Не используйте ту же строку в качестве источника и приемника, как вы. Вместо этого используйте отдельный временный.
Большинство (всех?) Блочных шифров могут взять 16-байтовый блок и зашифровать или расшифровать на месте. Однако, в случае строки, строка as изменяет базовые изменения размещения. Когда изменяется распределение, изменяется базовый указатель.
Может быть, использовать что-то вроде следующего. Временные потоки обходят проблемы использования строки как источника и приемника. Это также обеспечивает лучшую безопасность исключений. Если что-то идет в сторону, ваш input
остается без изменений.
void c_crypto::encrypt_buffer(std::string &input, unsigned char key[AES_KEY_SIZE], unsigned char iv[AES_KEY_SIZE]) {
AES::Encryption aesEncryption(key, AES_KEY_SIZE);
CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv);
std::string encrypted; encrypted.reserve(input.size()+16);
StreamTransformationFilter stfEncryptor(cbcEncryption, new StringSink(encrypted));
stfEncryptor.Put(reinterpret_cast<const unsigned char*>(input.c_str()), input.length());
stfEncryptor.MessageEnd();
std::string encoded = base64_encode(encrypted);
std::swap(encoded, input);
}
void c_crypto::decrypt_buffer(std::string &input, unsigned char key[AES_KEY_SIZE], unsigned char iv[AES_KEY_SIZE]) {
std::string decoded = base64_decode(input);
std::string decrypted; decrypted.reserve(decoded.size());
AES::Decryption aesDecryption(key, AES_KEY_SIZE);
CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv);
StreamTransformationFilter stfDecryptor(cbcDecryption, new StringSink(decrypted));
stfDecryptor.Put(reinterpret_cast<const unsigned char*>(decoded.c_str()), decoded.size());
stfDecryptor.MessageEnd();
std::swap(decrypted, input);
}
Использование буфера в качестве входного / выходного параметра работает нормально. В этом примере указатель не будет частично меняться в процессе:
byte buff[16] = {0};
CBC_Mode<AES>::Encryption enc(key, 16, iv);
enc.ProcessBlock(buff);
Однако ваш вариант использования немного сложнее, потому что зашифрованный текст добавляется к строке input
посредством StringSink(input)
, что неизбежно приводит к росту input
и делает недействительными используемые итераторы для передать данные в шифратор с помощью StringSource(input, ...)
.
Если интересно, ProcessBlock
и ProcessString
- это низкоуровневые функции-члены, используемые для преобразования данных. Фильтры типа StreamTransformationFilter
просто звонят вам за это. Там нет магии или вреда. Это просто высокоуровневый способ обработки данных. Также см. BlockTransformation
в руководстве по Doxygen.
Что касается заполнения, вы использовали:
StreamTransformationFilter stfEncryptor(cbcEncryption, new StringSink(input));
Что на самом деле это StreamTransformationFilter
конструктор:
StreamTransformationFilter (StreamTransformation &c, BufferedTransformation *attachment=NULL, BlockPaddingScheme padding=DEFAULT_PADDING)
DEFAULT_PADDING
- это одна из двух вещей. Для режимов, которым требуется заполнение, таких как ECB и CBC, это заполнение PKCS # 7 (PKCS_PADDING
). Для режимов, которым не требуется заполнение, например, CTR, это не заполнение (NO_PADDING
).
Обычно вы должны использовать значение по умолчанию, когда речь идет о схемах заполнения.