I want to en- and decode a single 16 bytes block of data using AES-128-ECB cipher. First I did it via the openssl command line utility using the ASCII 16 characters string "a_key_simple_key" as the key and the ASCII 16 characters string "1234567890uvwxyz" as the message. The command line utility printed the hexadecimal string "142f 7d9e ad8c 0682 30e0 f165 a52f f789" as ciphered message and then successfully decoded it back to original message, see below:
$ 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
Now I've written a short C++ program which should do the same. It doesn't work. There are 2 issues:
error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
I suspect that the both issues are somehow connected to padding, but I don't understand what is wrong exactly and how to fix it. Here is the full output of the program:
$ 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
And here is the C++ program itself (with line numbers):
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 }
Ok, it seems I figured out what's wrong:
EVP_CIPHER_CTX_set_padding()
call must be done AFTER the EVP_DecryptInit_ex()
call
So the solution is to exchange lines 50/51 and 35/36.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With