Обработка одного блока AES-128-ECB с использованием C/C++ и openssl

Я хочу закодировать и декодировать один 16-байтовый блок данных, используя шифр AES-128-ECB. Сначала я сделал это с помощью утилиты командной строки openssl, используя 16-символьную строку ASCII "a_key_simple_key" в качестве ключа и 16-символьную строку ASCII "1234567890uvwxyz" в качестве сообщения. Утилита командной строки напечатала шестнадцатеричную строку «142f 7d9e ad8c 0682 30e0 f165 a52f f789» в виде зашифрованного сообщения, а затем успешно декодировала ее обратно в исходное сообщение, см. ниже:

$ echo -n "1234567890uvwxyz" | openssl aes-128-ecb -K $(echo -n "a_key_simple_key" | xxd -ps) -nopad | xxd
0000000: 142f 7d9e ad8c 0682 30e0 f165 a52f f789  ./}.....0..e./..
$ echo "142f 7d9e ad8c 0682 30e0 f165 a52f f789" | xxd -r -ps | openssl aes-128-ecb -d -K $(echo -n "a_key_simple_key" | xxd -ps) -nopad 
1234567890uvwxyz

Теперь я написал короткую программу на C++, которая должна делать то же самое. Это не работает. Есть 2 проблемы:

  1. Вывод части кодирования имеет длину 32 байта вместо 16 байтов (первая половина этих 32 байтов - это именно тот зашифрованный текст, который я ожидал увидеть)
  2. Часть декодирования не работает на этапе завершения со следующим сообщением openssl:

ошибка:06065064:подпрограммы цифрового конверта:EVP_DecryptFinal_ex:плохая расшифровка

Я подозреваю, что обе проблемы как-то связаны с заполнением, но я не понимаю, что именно не так и как это исправить. Вот полный вывод программы:

$ g++ -Wall -g ssl-aes-128-ecb.c++ -lcrypto -lssl && ./a.out 2>&1 | less
ENCODING: FAIL
ENCODING: 1234567890uvwxyz --> ^T/}<9E><AD><8C>^F<82>0<E0><F1>e<A5>/<F7><89>^X<A0>P<U+DACE>R<F8>a^R^A<8A><97>GF*
error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
Aborting in u_string decode(u_string, u_string) at ssl-aes-128-ecb.c++:56

А вот и сама программа на C++ (с номерами строк):

01 #include <string>
02 #include <iostream>
03 #include <openssl/evp.h>
04 #include <openssl/err.h>
05 #include <openssl/ssl.h>
06 #define ABORT() (fprintf(stderr, "%s\nAborting in %s at %s:%d\n", ERR_error_string(ERR_get_error(), NULL), __PRETTY_FUNCTION__, __FILE__, __LINE__), abort(), 0)
07
08 typedef std::basic_string<unsigned char> u_string;
09 static u_string encode(u_string key, u_string data);
10 static u_string decode(u_string key, u_string data);
11
12 // echo -n "1234567890uvwxyz" | openssl aes-128-ecb -K $(echo -n "a_key_simple_key" | xxd -ps) -nopad | xxd
13 // echo "142f 7d9e ad8c 0682 30e0 f165 a52f f789" | xxd -r -ps | openssl aes-128-ecb -d -K $(echo -n "a_key_simple_key" | xxd -ps) -nopad
14
15 int main()
16 {
17   SSL_load_error_strings();
18
19   u_string key = (unsigned char *) "a_key_simple_key";
20   u_string clear_text = (unsigned char *) "1234567890uvwxyz";
21   u_string secret_txt = (unsigned char *) "\x14\x2f" "\x7d\x9e" "\xad\x8c" "\x06\x82" "\x30\xe0" "\xf1\x65" "\xa5\x2f" "\xf7\x89";
22
23   std::cerr << "ENCODING: " << (encode(key, clear_text)==secret_txt ? "ok" : "FAIL") << std::endl;
24   std::cerr << "ENCODING: " << (char*)clear_text.c_str() << " --> " << (char*)encode(key, clear_text).c_str() << std::endl;
25   std::cerr << "DECODING: " << (decode(key, secret_txt)==clear_text ? "ok" : "FAIL") << std::endl;
26   std::cerr << "DECODING: " << (char*)secret_txt.c_str() << " --> " << (char*)decode(key, secret_txt).c_str() << std::endl;
27
28   return 0;
29 }
30
31 static u_string encode(u_string key, u_string data)
32 {
33   EVP_CIPHER_CTX ctx;
34   EVP_CIPHER_CTX_init(&ctx);
35   EVP_CIPHER_CTX_set_padding(&ctx, false);
36   EVP_EncryptInit_ex (&ctx, EVP_aes_128_ecb(), NULL, key.c_str(), NULL);
37   unsigned char buffer[1024], *pointer = buffer;
38   int outlen;
39   EVP_EncryptUpdate (&ctx, pointer, &outlen, data.c_str(), data.length()) or ABORT();
40   pointer += outlen;
41   EVP_EncryptFinal_ex(&ctx, pointer, &outlen) or ABORT();
42   pointer += outlen;
43   return u_string(buffer, pointer-buffer);
44 }
45
46 static u_string decode(u_string key, u_string data)
47 {
48   EVP_CIPHER_CTX ctx;
49   EVP_CIPHER_CTX_init(&ctx);
50   EVP_CIPHER_CTX_set_padding(&ctx, false);
51   EVP_DecryptInit_ex (&ctx, EVP_aes_128_ecb(), NULL, key.c_str(), NULL);
52   unsigned char buffer[1024], *pointer = buffer;
53   int outlen;
54   EVP_DecryptUpdate (&ctx, pointer, &outlen, data.c_str(), data.length()) or ABORT();
55   pointer += outlen;
56   EVP_DecryptFinal_ex(&ctx, pointer, &outlen) or ABORT();
57   pointer += outlen;
58   return u_string(buffer, pointer-buffer);
59 }

person ilya    schedule 15.05.2013    source источник
comment
Можно было бы оставить вопрос и код немного маленьким.   -  person Rohit Vipin Mathews    schedule 15.05.2013
comment
Теперь я уверен, что это происходит из-за заполнения, потому что ( echo -n 1234567890uvwxyz ; (echo 10101010 10101010 10101010 10101010 | xxd -ps -r )) | openssl aes-128-ecb -K $(echo -n a_key_simple_key | xxd -ps) -nopad | xxd выводит точно такой же зашифрованный текст, как и моя часть кодирования программы   -  person ilya    schedule 15.05.2013
comment
Пожалуйста, никогда не используйте режим ECB. Всегда. (За исключением того, что вы узнаете, почему вам никогда не следует использовать режим ECB.)   -  person gha.st    schedule 15.05.2013


Ответы (1)


Хорошо, кажется, я понял, что не так:

EVP_CIPHER_CTX_set_padding() звонок должен быть сделан ПОСЛЕ EVP_DecryptInit_ex() звонка

Таким образом, решение состоит в том, чтобы поменять местами строки 50/51 и 35/36.

person ilya    schedule 15.05.2013