Я хочу зашифровать входные данные блоками по 100 байт с помощью шифрования OpenSSL AES-256-cbc. Однако EVP_EncryptUpdate шифрует только 96 байт (параметр tmp = 96). Следующий вызов EVP_EncryptUpdate шифрует остальные данные (кроме 4 отсутствующих).
Расшифровка в порядке, за исключением этих 4 недостающих байтов.
Если я вызову EVP_EncryptUpdate только один раз и передам все данные сразу, все в порядке.
Я не понимаю, почему эти 4 байта отсутствуют, если я передаю только 100 байт в EVP_EncryptUpdate.
std::string data = "A12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123hgfedcba";
unsigned char key[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
unsigned char iv[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
int i = 0, tmp = 0, ol = 0;
int res = EVP_EncryptInit(&ctx, EVP_aes_256_ecb(), key, iv);
std::unique_ptr<unsigned char[]> ret(new unsigned char[dataLen+EVP_CIPHER_CTX_block_size(&ctx)]);
for (i = 0; i < dataLen / 100; i++)
{
EVP_EncryptUpdate(&ctx,
&ret[ol], &tmp, &data[ol], 100);
ol += tmp;
}
if (dataLen % 100)
{
EVP_EncryptUpdate(&ctx, &ret[ol], &tmp, &data[ol], dataLen % 100);
ol += tmp;
}
EVP_EncryptFinal(&ctx, &ret[ol], &tmp);
EVP_EncryptUpdate
ДОЛЖЕН сопровождаться EVP_EncryptFinal
. Режим CBC может шифровать/дешифровать только полные блоки. Библиотека не знает, что за последним вызовом EVP_EncryptUpdate
не следует другой, поэтому EVP_EncryptFinal
должен следует использовать для обозначения конца открытого текстового сообщения для шифрования/дешифрования.
EVP_EncryptUpdate
попытается зашифровать как можно больше блоков, а остальные оставит во внутреннем буфере. Во время EVP_EncryptFinal
к данным, находящимся в буфере, добавляется дополнение, совместимое с PKCS#7, и последний блок (блоки) шифруются, и возвращается последняя часть зашифрованного текста. Обратите внимание, что применяется заполнение всегда, даже если внутренний буфер пуст.
В общем, ваши последние четыре байта дополняются и шифруются, когда вы вызываете EVP_EncryptFinal
или добавляете достаточно данных с помощью обновлений, чтобы создать полный блок открытого текста для шифрования. Если вы не вызываете EVP_EncryptFinal
, то зашифрованный текст не дополняется, и ваше расшифрование либо завершается ошибкой или — если последнюю часть зашифрованного текста можно рассматривать как действительное заполнение — оно удалит несколько байтов с конца и вернет то, что осталось . Опять же, при использовании обновлений вы должен финализируете.
Если вам не нравится такое поведение, вы можете взглянуть на режим CTR, который — по крайней мере теоретически — является потоковым режимом и может напрямую возвращать зашифрованные байты, не требуя заполнения. Это называется «онлайн» свойством режима блочного шифрования. Иногда реализации по-прежнему буферизуют открытый текст до тех пор, пока не будет заполнен полный блок, так что будьте осторожны.
Примечания по кодированию:
100 не кратно размеру блока (16 байт), поэтому, очевидно, осталось 4 байта.
CBC требует уникального непредсказуемого ключа / IV для режима CBC, а CTR требует уникального одноразового номера.
Вам лучше изучить эти алгоритмы, иначе у вас не получится создать безопасный код. Для безопасности транспорта вы захотите использовать аутентифицированный шифр.
Удалено замечание о
ol
, потому что текущая обработка в порядке (это для модов, я отмечу удаление комментариев).