Шифрование с помощью AES-256-GCM с использованием (LibreSSL) libcrypto

Учитывая соответствующий key а также ivэта программа на С должна зашифровать stdin, выводя на stdout,

EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit(ctx, EVP_aes_256_gcm(), key, iv);

const size_t block_size = 128;
unsigned char inbuf[block_size];
unsigned char outbuf[block_size + EVP_MAX_BLOCK_LENGTH];
int inlen, outlen;
for (;;)
{
        inlen = fread(inbuf, 1, block_size, stdin);
        if (inlen <= 0)
                break;

        EVP_EncryptUpdate(ctx, outbuf, &outlen, inbuf, inlen)
        fwrite(outbuf, 1, outlen, stdout);
}
EVP_EncryptFinal_ex(ctx, outbuf, &outlen)
fwrite(outbuf, 1, outlen, stdout);

(Ошибка проверки удалена для краткости.)

Я проверяю вывод этого кода, запустив

openssl aes-256-gcm -in ciphertext.txt -K <key> -iv <iv> -d

Это успешно и надежно расшифровывает зашифрованный текст, но записывает, например, плохую расшифровку

$ openssl aes-256-gcm ...
Hello World.
bad decrypt

Что может пойти не так, чтобы заставить это сказать это?

2 ответа

Решение

Мне не удалось получить тег аутентификации GCM после шифрования и затем предоставить его во время расшифровки.

Сообщение о "плохом дешифровании" вводило в заблуждение - расшифровка шла хорошо, но тег, обеспечивающий аутентификацию, не был предоставлен.

Тег можно получить после звонка EVP_EncryptFinal_ex с

unsigned char *tag = malloc(TAGSIZE);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAGSIZE, tag);

TAGSIZE размер в байтах тега, и может быть числом различных значений. Это обсуждается в Википедии среди других мест.

Проблема здесь в том, что вы не реализуете правильное заполнение, как того требует PKCS#7. openssl ожидает правильного заполнения в декодированном сообщении. Правила таковы:

  • Всегда должен быть хотя бы 1 байт заполнения
  • Он должен быть дополнен до размера блока шифра

Теперь с AES-256 у вас есть размер блока 128 бит (16 байт). Это означает, что вы должны добавить 1-16 байтов заполнения. Добавляемые байты заполнения всегда имеют размер заполнения, поэтому, если вам нужно добавить 9 байтов заполнения, вы должны добавить 9 0x09 байт.

Если вы правильно добавите этот отступ к исходному тексту, openssl должен прекратить жаловаться на расшифровку.

Другие вопросы по тегам