Добавляет ли AES_cbc_encrypt заполнение?

Рассмотрим следующий фрагмент кода C++:

#include <iostream>
#include <openssl/aes.h>

#define AES_KEY_LENGTH 32

using namespace std;

int main()
{
    AES_KEY encryption_key;
    AES_KEY decryption_key;

    unsigned char key[AES_KEY_LENGTH] = {'t', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't'};

    unsigned char iv[AES_BLOCK_SIZE] = {'t', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't'};

    unsigned char iv_enc[AES_BLOCK_SIZE];
    unsigned char iv_dec[AES_BLOCK_SIZE];

    memcpy(iv_enc, iv, AES_BLOCK_SIZE);
    memcpy(iv_dec, iv, AES_BLOCK_SIZE);

    AES_set_encrypt_key(key, AES_KEY_LENGTH * 8, &(encryption_key));
    AES_set_decrypt_key(key, AES_KEY_LENGTH * 8, &(decryption_key));

    char message[] = "Attack at dawn! Attack.";

    unsigned char * encryption_output = new unsigned char[32];
    encryption_output[31] = 3;

    AES_cbc_encrypt((unsigned char *) message, encryption_output, sizeof(message), &encryption_key, iv_enc, AES_ENCRYPT);

    unsigned char * decryption_output = new unsigned char[32];

    AES_cbc_encrypt(encryption_output, decryption_output, 32, &decryption_key, iv_dec, AES_DECRYPT);
}

Здесь я шифрую, а затем расшифровываю сообщение с помощью библиотеки openssl aes. Что меня беспокоит, так это длина файла encoding_output. Насколько я понимаю, поскольку AES шифрует блоками размером AES_BLOCK_SIZE (он же 16 байт), количество выходных байтов должно быть равно размеру сообщения, округленному до ближайшего кратного AES_BLOCK_SIZE. Это правильно? В частности, что произойдет, если я удлиню сообщение до длины ровно 32 байта? Будет ли это по-прежнему работать, или будут добавлены 16 пустых байтов заполнения, что вызовет ошибку сегментации при попытке записать байты с 32 по 47 в шифрование_выход?


person Matteo Monti    schedule 05.07.2015    source источник
comment
Заполнение создает оракулов. В новейших безопасных разработках частично используются режимы шифрования с проверкой подлинности для удаления оракулов. Таким образом, вы должны использовать такой режим, как AES/GCM. И вы должны использовать высокий уровень, EVP_* функции. AES_* и друзья иногда сталкиваются с проблемами порядка следования байтов, и они никогда не будут использовать аппаратное обеспечение, такое как AES-NI, потому что это чисто программная реализация.   -  person jww    schedule 06.07.2015
comment
Я действительно не эксперт. Все дело в том, что мне нужно передавать данные фиксированной длины. Обычно эта длина кратна размеру блока. Итак, скажем, мне нужно всегда передавать 16 байт за раз: поскольку я уже знаю, что мне нужно 16 байтов, я действительно хотел бы каждый раз избегать дополнительных 16 байтов бесполезного заполнения: это 100% накладных расходов в моей сети!   -  person Matteo Monti    schedule 07.07.2015
comment
Какова наилучшая стратегия — просто зашифровать данные фиксированной длины безопасным способом? Есть ли существенная разница, если длина кратна размеру блока или нет?   -  person Matteo Monti    schedule 07.07.2015
comment
Вы не должны не использовать AES_encrypt и друзей. Это программная реализация, поэтому вы не получите аппаратной поддержки, такой как AES-NI. Вы должны использовать EVP_* функции. См. симметричное шифрование и дешифрование EVP на вики OpenSSL. На самом деле вам, вероятно, следует использовать шифрование с проверкой подлинности, поскольку оно обеспечивает как конфиденциальность, так и подлинность. См. Шифрование и дешифрование с проверкой подлинности EVP на вики OpenSSL.   -  person jww    schedule 13.08.2016


Ответы (1)


Правильное заполнение PKCS # 7:

  • округляет длину до кратного размера блока, если раньше оно не было кратным
  • и добавляет целый блок в противном случае

В противном случае при расшифровке вы не могли бы знать, является ли последний блок зашифрованного текста «настоящим» или только дополнением. (Фактические значения байтов для заполнения также указаны, но ваш реальный последний блок может содержать их => снова невозможно распознать).

Существуют и другие схемы, кроме PKCS#7, но здесь это не актуально.

Однако с AES_cbc_encrypt вам придется реализовать это самостоятельно, т.е. pad перед шифрованием и удалите заполнение после расшифровки. Само шифрование будет работать с некратной длиной, но используемое «заполнение» имеет проблему, упомянутую выше. Чтобы ответить на ваш первоначальный вопрос, AES_cbc_encrypt не будет добавлять блоки, округление длины - единственное, что он делает.

Для функций с правильным дополнением (и без некоторых других недостатков AES_cbc_encrypt, таких как отсутствие поддержки AESNI и т. д. и т. д.), загляните в часть EVP OpenSSL. AES_cbc_encrypt — более низкоуровневая часть, в зависимости от ситуации, она также используется высокоуровневой функцией.

Кстати, кое-что о C++: если вы не получаете ошибку сегментации,
это не означает, что код правильный.

person deviantfan    schedule 05.07.2015
comment
Не могу попросить более полный ответ, спасибо. Я спрашивал, потому что я обмениваюсь сообщениями фиксированной длины между двумя конечными точками. Я уже знаю, какова длина сообщения, так что все это дополнение совершенно бесполезно. В частности, я отправляю и получаю эти сообщения по сети, и их длина почти всегда кратна размеру блока: я бы всегда тратил эти 16 байт впустую. Спасибо еще раз! - person Matteo Monti; 05.07.2015
comment
Комментарий Segfault: Да! Более того, только потому, что ваша программа делает то, что вы ожидаете (на данный момент), не означает, что она правильная. - person Johannes Overmann; 07.04.2016