Возникли проблемы с расшифровкой правильно сформированного зашифрованного текста с помощью Crypto++

Фон

Около дня я боролся с расшифровкой, по-видимому, правильно сформированного зашифрованного текста. Предположим, у нас есть следующий шестнадцатеричный зашифрованный текст, который содержит ровно 160 символов, то есть имеет 80 байтов.

QString c = "1BFAC407AF0D440A2D6176C0B5D125AA96088490299AC18C74623C0EF1BB1372E554FC4150A8066220E943697BE2491D8AE13AA036B298425AC510A8A917D59EBB69708B9040AB3A84C63043EAD4AB07";
QString k = CryptoUtils::hexEncode("abc");
QString p = CryptoUtils::decrypt(c, k);

qDebug() << p;

При условии, что мы используем AES 256, AFAIK, ключ должен иметь длину 32 байта, а зашифрованный текст должен иметь длину, кратную 16 байтам, что соответствует всем этим условиям в отношении моего фрагмента кода.

Обратите внимание, что я использую передачу SHA256 с парольной фразой для создания 32-байтового ключа. Таким образом, это гарантирует, что все ключи имеют длину 32 байта.

Полные исходные коды этих функцию можно найти в моем репозитории на GitHub (в ветке Part1).


Мой вопрос

Когда я хочу запустить этот код, мое приложение падает. Вот исключение:

terminate called after throwing an instance of 'CryptoPP::InvalidCiphertext'
  what():  StreamTransformationFilter: invalid PKCS #7 block padding found
The program has unexpectedly finished.

Я искал эту проблему и понял, что это может быть из-за завершающего \0 после того, как вы зашифровали обычный текст. Однако я не мог просто решить проблему. Пожалуйста, помогите мне, это просто сводит меня с ума.


person frogatto    schedule 08.12.2015    source источник
comment
Как вы получили зашифрованный текст? Используя те же методы? Ошибки заполнения PKCS#7 являются единственными ошибками, которые могут быть сгенерированы (помимо ошибок, связанных с размером блока), они показывают неверный код, неверный ключ или неверные данные (а для небольшого зашифрованного текста в режиме CBC даже неверный IV).   -  person Maarten Bodewes    schedule 09.12.2015
comment
StringSource(decodedKey, size, true, new HashFilter(*(new SHA256), new ArraySink(key, AES::MAX_KEYLENGTH)));: это плохой KBKDF, он скрывает проблемы с ключом и, по моему скромному мнению, довольно нечитаем. Если вы используете что-либо, кроме библиотеки, на которую указываете, то расшифровка точно не удастся (если, конечно, такое же нестандартное хеширование не применяется в другой библиотеке).   -  person Maarten Bodewes    schedule 09.12.2015
comment
@MaartenBodewes Я сгенерировал этот зашифрованный текст из функции encrypt (из того файла cpp, на который я ссылался). Кроме того, IV всегда 0. Что касается ключа, я не вижу, в чем проблема с SHA256 (мне просто нужно сгенерировать универсальный ключ из парольной фразы, и для этого просто не имеет значения, какой алгоритм я должен использовать).   -  person frogatto    schedule 09.12.2015


Ответы (2)


Полные исходные коды этих функций можно найти в моем репозитории на GitHub.

Я бы сделал эти изменения как минимум:

QString CryptoUtils::encrypt(QString text, QString keyhex)
{
    ...

    // name the variable, kill the memory leak
    SHA256 sha256;
    StringSource ss1(decodedKey, size, true, new HashFilter(sha256, new ArraySink(key, AES::MAX_KEYLENGTH)));
    ...

    // name the variable
    StringSource ss2(plain, true, new StreamTransformationFilter(Encryptor, new HexEncoder(new StringSink(encrypted))));

    // verify embedded NULLs don't affect results
    QString qs = QString::fromStdString(encrypted);
    assert(qs.length() == encrypted.length());
}

А также:

QString CryptoUtils::decrypt(QString text, QString keyhex)
{
    // bad karma here...
    string encrypted = text.toStdString();
    assert(encrypted.length() == text.length());
    ...

    // name the variable, kill the memory leak
    SHA256 sha256;
    StringSource ss1(decodedKey, size, true, new HashFilter(sha256, new ArraySink(key, AES::MAX_KEYLENGTH)));
    ...

    // name the variable,
    StringSource ss2(encrypted, true, new HexDecoder(new StreamTransformationFilter(Decryptor, new StringSink(plain))));

    // verify embedded NULLs don't affect results
    QString qs = QString::fromStdString(plain);
    assert(qs.length() == plain.length());
}
person jww    schedule 10.12.2015
comment
Спасибо за ваш ответ. Но проблема была из-за моей функции hexEncode. Он генерировал разные шестнадцатеричные коды для одного и того же ввода. - person frogatto; 10.12.2015
comment
@Frogatto - Он генерировал разные шестнадцатеричные коды для одного и того же ввода - это интересно в каком-то болезненном смысле ... Используйте UTF-8; лучше всего подходит для взаимодействия. Или используйте необработанные байты и что-то вроде HKDF для извлечения и расширения энтропия. - person jww; 11.12.2015

Функция hexEncode ведет себя неправильно:

QString CryptoUtils::hexEncode(QString text)
{
    byte *bytearray = (byte *) text.toLatin1().data();
    int length = text.toLatin1().length();

    return hexEncode(bytearray, length);
}

Следует заменить на:

QString CryptoUtils::hexEncode(QString text)
{
    byte *bytearray = (byte *) text.toStdString().data();
    int length = text.length();

    return hexEncode(bytearray, length);
}
person frogatto    schedule 10.12.2015