title: Process a single AES-128-ECB block using C/C++ and openssl
body: <p>I want to en- and decode a single 16 bytes block of data using <strong>AES-128-ECB</strong> cipher.
  First I did it via the <strong>openssl</strong> 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: </p>
  
  <pre><code>$ 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
  </code></pre>
  
  <p>Now I've written a short C++ program which should do the same. It doesn't work. There are 2 issues:</p>
  
  <ol>
  <li>The output of encoding part is 32 bytes long instead of 16 bytes (the first half of these 32 bytes is exactly the ciphered text I expected to see)</li>
  <li>The decoding part is failing in the finalization step with the following openssl message: </li>
  </ol>
  
  <p><strong>error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt</strong></p>
  
  <p>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:</p>
  
  <pre><code>$ g++ -Wall -g ssl-aes-128-ecb.c++ -lcrypto -lssl &amp;&amp; ./a.out 2&gt;&amp;1 | less
  ENCODING: FAIL
  ENCODING: 1234567890uvwxyz --&gt; ^T/}&lt;9E&gt;&lt;AD&gt;&lt;8C&gt;^F&lt;82&gt;0&lt;E0&gt;&lt;F1&gt;e&lt;A5&gt;/&lt;F7&gt;&lt;89&gt;^X&lt;A0&gt;P&lt;U+DACE&gt;R&lt;F8&gt;a^R^A&lt;8A&gt;&lt;97&gt;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
  </code></pre>
  
  <p>And here is the C++ program itself (with line numbers):</p>
  
  <pre><code>01 #include &lt;string&gt;
  02 #include &lt;iostream&gt;
  03 #include &lt;openssl/evp.h&gt;
  04 #include &lt;openssl/err.h&gt;
  05 #include &lt;openssl/ssl.h&gt;
  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&lt;unsigned char&gt; 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 &lt;&lt; "ENCODING: " &lt;&lt; (encode(key, clear_text)==secret_txt ? "ok" : "FAIL") &lt;&lt; std::endl;
  24   std::cerr &lt;&lt; "ENCODING: " &lt;&lt; (char*)clear_text.c_str() &lt;&lt; " --&gt; " &lt;&lt; (char*)encode(key, clear_text).c_str() &lt;&lt; std::endl;
  25   std::cerr &lt;&lt; "DECODING: " &lt;&lt; (decode(key, secret_txt)==clear_text ? "ok" : "FAIL") &lt;&lt; std::endl;
  26   std::cerr &lt;&lt; "DECODING: " &lt;&lt; (char*)secret_txt.c_str() &lt;&lt; " --&gt; " &lt;&lt; (char*)decode(key, secret_txt).c_str() &lt;&lt; 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(&amp;ctx);
  35   EVP_CIPHER_CTX_set_padding(&amp;ctx, false);
  36   EVP_EncryptInit_ex (&amp;ctx, EVP_aes_128_ecb(), NULL, key.c_str(), NULL);
  37   unsigned char buffer[1024], *pointer = buffer;
  38   int outlen;
  39   EVP_EncryptUpdate (&amp;ctx, pointer, &amp;outlen, data.c_str(), data.length()) or ABORT();
  40   pointer += outlen;
  41   EVP_EncryptFinal_ex(&amp;ctx, pointer, &amp;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(&amp;ctx);
  50   EVP_CIPHER_CTX_set_padding(&amp;ctx, false);
  51   EVP_DecryptInit_ex (&amp;ctx, EVP_aes_128_ecb(), NULL, key.c_str(), NULL);
  52   unsigned char buffer[1024], *pointer = buffer;
  53   int outlen;
  54   EVP_DecryptUpdate (&amp;ctx, pointer, &amp;outlen, data.c_str(), data.length()) or ABORT();
  55   pointer += outlen;
  56   EVP_DecryptFinal_ex(&amp;ctx, pointer, &amp;outlen) or ABORT();
  57   pointer += outlen;
  58   return u_string(buffer, pointer-buffer);
  59 }
  </code></pre>