Ошибка шифрования строки с AES128 с использованием OpenSSL в C ++ - PullRequest
3 голосов
/ 07 мая 2019

У меня проблемы с последними символами зашифрованного сообщения, которое я генерирую с помощью библиотеки OpenSSL и алгоритма AES 128 в режиме CBC, вот данные, которые я использую:

Message in Hex = "7b22494443223a2232363930393439376434222c22444553223a2256656e74616d656e7564656f222c22414d4f223a3530302c22444154223a313530383233303035383730362c22524546223a302c22434f4d223a312c22545950223a31392c2276223a7b224e414d223a2252616661656c56616c656e7a75656c614172656e6173222c22414343223a2235383732313233343536373836303132222c2242414e223a34303132372c22545943223a332c22444556223a22353532373139323132382f30227d7da"
Key128 in Hex = "dadf11e74d014a62d73ccadd9591442a"
Initialization Vector in Hex = "cab9da8940cd7dc9510c7249fe47c6e6"

Этокод, который я использую:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <math.h>
#include <assert.h>
#include <stdint.h>
#include <stdbool.h>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <locale>

#include <openssl/aes.h>
#include <openssl/des.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>

using namespace std;

/* AES key for Encryption and Decryption */
const static unsigned char aes_key[16]={0xda, 0xdf, 0x11, 0xe7, 0x4d, 0x01, 0x4a, 0x62, 0xd7, 0x3c, 0xca, 0xdd, 0x95, 0x91, 0x44, 0x2a};

/* Print Encrypted and Decrypted data packets */
void print_data(const char *tittle, const void* data, int len)
{
    printf("%s : ",tittle);
    const unsigned char * p = (const unsigned char*)data;
    int i = 0;

    for (; i<len; ++i)
    {
        printf("%02X ", *p++);
    }

    printf("\n");
}

int main( )
{
    /* Input data to encrypt */
    unsigned char enc_out[235]={0x7b, 0x22, 0x49, 0x44, 0x43, 0x22, 0x3a, 0x22, 0x32, 0x36, 0x39, 0x30, 0x39, 0x34, 0x39, 0x37, 0x64, 0x34, 0x22, 0x2c, 0x22, 0x44, 0x45, 0x53, 0x22, 0x3a, 0x22, 0x56, 0x65, 0x6e, 0x74, 0x61, 0x6d, 0x65, 0x6e, 0x75, 0x64, 0x65, 0x6f, 0x22, 0x2c, 0x22, 0x41, 0x4d, 0x4f, 0x22, 0x3a, 0x35, 0x30, 0x30, 0x2c, 0x22, 0x44, 0x41, 0x54, 0x22, 0x3a, 0x31, 0x35, 0x30, 0x38, 0x32, 0x33, 0x30, 0x30, 0x35, 0x38, 0x37, 0x30, 0x36, 0x2c, 0x22, 0x52, 0x45, 0x46, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x43, 0x4f, 0x4d, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x54, 0x59, 0x50, 0x22, 0x3a, 0x31, 0x39, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x7b, 0x22, 0x4e, 0x41, 0x4d, 0x22, 0x3a, 0x22, 0x52, 0x61, 0x66, 0x61, 0x65, 0x6c, 0x56, 0x61, 0x6c, 0x65, 0x6e, 0x7a, 0x75, 0x65, 0x6c, 0x61, 0x41, 0x72, 0x65, 0x6e, 0x61, 0x73, 0x22, 0x2c, 0x22, 0x41, 0x43, 0x43, 0x22, 0x3a, 0x22, 0x35, 0x38, 0x37, 0x32, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x36, 0x30, 0x31, 0x32, 0x22, 0x2c, 0x22, 0x42, 0x41, 0x4e, 0x22, 0x3a, 0x34, 0x30, 0x31, 0x32, 0x37, 0x2c, 0x22, 0x54, 0x59, 0x43, 0x22, 0x3a, 0x33, 0x2c, 0x22, 0x44, 0x45, 0x56, 0x22, 0x3a, 0x22, 0x35, 0x35, 0x32, 0x37, 0x31, 0x39, 0x32, 0x31, 0x32, 0x38, 0x2f, 0x30, 0x22, 0x7d, 0x7d, 0xa};

    /* Init vector */
    unsigned char iv[16]={0xca, 0xb9, 0xda, 0x89, 0x40, 0xcd, 0x7d, 0xc9, 0x51, 0x0c, 0x72, 0x49, 0xfe, 0x47, 0xc6, 0xe6};
    //memset(iv, 0x00, AES_BLOCK_SIZE);

    /* Buffers for Encryption and Decryption */
    unsigned char dec_out[400];
    unsigned char aux_out[400];

    memset(dec_out, 0, sizeof(dec_out));
    memset(aux_out, 0, sizeof(aux_out));

    /* AES-128 bit CBC Encryption */
    AES_KEY enc_key, dec_key;
    AES_set_encrypt_key(aes_key, sizeof(aes_key)*8, &enc_key);
    AES_cbc_encrypt(enc_out, dec_out, sizeof(enc_out), &enc_key, iv, AES_ENCRYPT);
    /* AES-128 bit CBC Decryption */
    memset(iv, 0x00, AES_BLOCK_SIZE); // don't forget to set iv vector again, else you can't decrypt data properly
    AES_set_decrypt_key(aes_key, sizeof(aes_key)*8, &dec_key); // Size of key is in bits
    AES_cbc_encrypt(dec_out, aux_out, sizeof(enc_out), &dec_key, iv, AES_DECRYPT);

    /* Printing and Verifying */
    print_data("\n Original ",enc_out, sizeof(enc_out)); // you can not print data as a string, because after Encryption its not ASCII

    print_data("\n Encrypted",dec_out, sizeof(enc_out));

    print_data("\n Decrypted",aux_out, sizeof(dec_out));

    return 0;
}

Видимо, только конец цепочки является неправильным (последние 32 символа), остальное в порядке, я немного исследовал, и все указывает накакой тип заполнения текста, но в соответствии с тем, что я прочитал, он уже дополнен PKCS5 (который мне нужен на самом деле), поэтому я не вижу, в чем ошибка.

The Correct Encryption = EFC063DD33406D424D359809695D0B1E2D65027E803962C6A115DF7CCABEEB0C8C358830E556ED23943FA4F02E6461D235EF913CFCE5519F7CE2279DD07D3C4054D045827D5D7D9FE94DA3C5B718A24E79539B3FFC1E68E4C3FF441EEA176F61EE3D7B33B622E3069D95815F6407FBC79342BB972A2DDE4E50FDE9302BDE4409B7D2BD388AB6A043B9EF236D982937D8537F954564FF4134BD8A6EAB994FE4C29E9DC4E54D53A561A4688C45C90961EDB1763B6EF6C86B593C7E16FDF35C49CE16B1E6948BB1EAE6A8692326A019960B

The Output of the Program = EFC063DD33406D424D359809695D0B1E2D65027E803962C6A115DF7CCABEEB0C8C358830E556ED23943FA4F02E6461D235EF913CFCE5519F7CE2279DD07D3C4054D045827D5D7D9FE94DA3C5B718A24E79539B3FFC1E68E4C3FF441EEA176F61EE3D7B33B622E3069D95815F6407FBC79342BB972A2DDE4E50FDE9302BDE4409B7D2BD388AB6A043B9EF236D982937D8537F954564FF4134BD8A6EAB994FE4C29E9DC4E54D53A561A4688C45C90961EDB1763B6EF6C86B593C7E16FDF35C49CE608E3F73FC8E3DDF1D3BCF40B3DFACD00B732A9FCC10F6E0FB18E126A1C21A082D7A4F053F131A9329474D

Я понимаю, что в коде есть много улучшений, и я не рассматриваю дескрипцию, но в данный момент она мне не нужна.

Ответы [ 2 ]

2 голосов
/ 08 мая 2019

AES_cbc_encrypt - шифрование с использованием низкоуровневых примитивов.Он не выполняет никаких дополнений.Вот ссылка на исходный код CBC, который непосредственно вызывается кодом AES CBC: https://github.com/openssl/openssl/blob/master/crypto/modes/cbc128.c - заполнение вообще не указывается.

Реальный вопрос - почему вы быиспользуйте плохо описанные функции реализации низкого уровня вместо EVP API , который поддерживает сам OpenSSL.Вы можете подумать, что примитивы более низкого уровня более производительны, но это может быть не так, если, например, развернут AES-NI;издержки на вызов в любом случае будут минимальными по сравнению с самим шифром.

1 голос
/ 09 мая 2019

Массив enc_out рассчитан на 235 байтов, но инициализируется только явно для 200 байтов, то есть остальные байты неявно инициализируются с 0x00 -значениями.Это соответствует зашифрованному тексту длиной 240 байт (= 15 х 16 байт).Следовательно, текущий код возвращает зашифрованный текст длиной 240 байт, последние три блока которого:

608E3F73FC8E3DDF1D3BCF40B3DFACD0 0B732A9FCC10F6E0FB18E126A1C21A08 2D7A4F053F131A9329474DE44DA772BC

Это соответствует неявному заполнению со значениями 0x00.Последние 5 байтов отсутствуют в зашифрованном зашифрованном тексте, потому что для вывода используется длина открытого текста (вместо зашифрованного текста).

Скорее всего, должны быть зашифрованы только первые 200 байтов.Это будет соответствовать зашифрованному тексту длиной 208 байтов (= 13 x 16 байтов), который является просто длиной ожидаемого зашифрованного текста.Для этого размер массива enc_out должен быть уменьшен с 235 до 200, или даже лучше, размер не должен быть явно указан вообще.

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

...