Вычислить CBC-MAC с AES-256 и openssl в C

Я хочу вычислить CBC-MAC данного открытого текста с помощью openssl. У меня есть следующий текст (hexdump):

hexdump -C example.txt
00000000  4d 41 43 73 20 61 72 65  20 76 65 72 79 20 75 73  |MACs are very us|
00000010  65 66 75 6c 20 69 6e 20  63 72 79 70 74 6f 67 72  |eful in cryptogr|
00000020  61 70 68 79 21 20 20 20  20 20 20 20 20 20 20 20  |aphy!           |

Если я использую функцию командной строки openssl, я получаю следующее решение:

openssl aes-256-cbc -in example.txt -K 8000000000000000000000000000000000000000000000000000000000000001 -e -iv 00 | hexdump -C
00000000  e8 e9 a4 ce 5d 20 c4 ad  f5 52 b2 c6 38 2e 12 4e  |....] ...R..8..N|
00000010  20 f5 63 65 b4 b3 96 9f  ad 8d ca e4 e8 34 2a e5  | .ce.........4*.|
00000020  0d 82 0e 3a 1e 10 5d 30  72 16 fc 00 c7 a5 b4 49  |...:..]0r......I|
00000030  f5 63 9f 85 ff e3 a4 a4  23 6e 6f 09 20 ed b1 ae  |.c......#no. ...|

Все идет нормально. У меня есть один дополнительный блок, потому что первый блок должен быть зашифрованным IV. Теперь последней строкой должен быть мой CBC-MAC, если я правильно понял. Затем я попытался сделать то же самое в C, вот пример кода:

#include <stdio.h>
#include <string.h>
#include <openssl/sha.h>
#include <openssl/aes.h>

int main(int argc, char *argv[])
{
    unsigned char obuf[64] = {0};
    unsigned char decbuf[48] = {0};
    unsigned char msg1[] = {0x4d, 0x41, 0x43, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x75, 0x73,
                            0x65, 0x66, 0x75, 0x6c, 0x20, 0x69, 0x6e, 0x20, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x67, 0x72, 
                            0x61, 0x70, 0x68, 0x79, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
    unsigned char key[] =  {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
    unsigned char ivenc[] ={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    unsigned char ivdec[] ={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    int i=0;

    AES_KEY enc_key, dec_key;
    AES_set_encrypt_key(key, 256, &enc_key);
    AES_cbc_encrypt(msg1, obuf, 48, &enc_key, ivenc, AES_ENCRYPT);

    for (i = 0; i < 64; i++) {
        if (!(i%16))
            printf("\n");
        printf("%02x ", obuf[i]);
    }
    printf("\n");

    AES_set_decrypt_key(key, 256, &dec_key);
    AES_cbc_encrypt(obuf, decbuf, 64, &dec_key, ivdec, AES_DECRYPT);

    for (i = 0; i < 48; i++) {
        if (!(i%16))
            printf("\n");
        printf("%02x ", decbuf[i]);
    }
    printf("\n");

    return 0;
}

Затем я расшифровываю зашифрованное сообщение, чтобы проверить мой код. Вывод моего кода довольно удивителен:

e8 e9 a4 ce 5d 20 c4 ad f5 52 b2 c6 38 2e 12 4e 
20 f5 63 65 b4 b3 96 9f ad 8d ca e4 e8 34 2a e5 
0d 82 0e 3a 1e 10 5d 30 72 16 fc 00 c7 a5 b4 49 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

4d 41 43 73 20 61 72 65 20 76 65 72 79 20 75 73 
65 66 75 6c 20 69 6e 20 63 72 79 70 74 6f 67 72 
61 70 68 79 21 20 20 20 20 20 20 20 20 20 20 20 

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

Вопросы:

  • Как это возможно, что я могу расшифровать вывод моего шифрования, даже если у меня нет последней строки?
  • Какой у меня CBC-MAC? это последняя строка из моего вывода командной строки или последняя строка моего вывода C-кода?
  • Я делаю что-то не так в моем коде C? Я использовал этот вопрос как помощь.

1 ответ

Решение

Ваша ошибка здесь:

У меня есть один дополнительный блок, потому что первый блок должен быть зашифрованным IV.

Дополнительный блок связан с тем, что OpenSSL добавляет заполнение к простому тексту, так что оно кратно размеру блока (16 байт для AES). В этом случае обычный текст уже кратен 16 байтам, но используемая схема заполнения ( PKCS7) всегда добавляет заполнение, поэтому здесь перед шифрованием добавляется целый блок.

Обычно добавляют IV в начало зашифрованного текста, но это не то, что здесь происходит.

Чтобы получить тот же результат из вашего кода, вам нужно добавить этот отступ самостоятельно. В этом случае это довольно просто, просто добавьте шестнадцать 0x10 байтов до конца msg1 (так что его длина составляет 64), и измените 48 в призыве к AES_cbc_encrypt в 64, Нули, которые вы видите, это просто значение, которое вы инициализируете obuf к, так как вы записываете только 48 байтов в этот буфер.

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