I use openSSL
library functions for encrypting and decrypting purposes based on AES-128/CBC.
The code is shown below (do not be confused by the THROW / EXIT macros, they are just gotos). Regardless of what the function returns, you will see printf
output to track what is being sent back and forth to OpenSSL:
enc_status_t aes_cipher_ext(uint8_t should_encrypt, enc_aes128_key_t *key, uint8_t *iv, void *in, uint32_t inlen, void *out, uint32_t outlen, uint32_t * outlen_act)
{
enc_status_t status;
buffer_t inbuf, outbuf;
int ok;
const uint32_t BUFSIZE = AES_BUFFERSIZE;
uint8_t *read_buf = NULL;
uint8_t *cipher_buf = NULL;
uint32_t blocksize;
int out_len;
uint32_t numRead;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
/* initialize input read buffer */
status = buffer_init(&inbuf, in, inlen);
if (status != ENC_OK) EXIT();
status = buffer_init(&outbuf, out, outlen);
if (status != ENC_OK) EXIT();
/* initialize AES engine */
ok = EVP_CipherInit(ctx, EVP_aes_128_cbc(), key->data, iv, should_encrypt);
if(!ok) THROW(status = ENC_ERR_OPENSSL);
blocksize = EVP_CIPHER_CTX_block_size(ctx);
read_buf = malloc(BUFSIZE);
cipher_buf = malloc(BUFSIZE + blocksize);
out_len = BUFSIZE + blocksize;
while (TRUE) { /*lint !e716 see below */
/* read data and cipher */
status = buffer_read(&inbuf, read_buf, BUFSIZE, &numRead);
if (status != ENC_OK) EXIT();
printf("AES input: num read = %d\n", numRead);
dump_ram(read_buf, numRead);
if (should_encrypt)
{
ok = EVP_EncryptUpdate(ctx, cipher_buf, &out_len, read_buf, numRead);
}
else
{
ok = EVP_DecryptUpdate(ctx, cipher_buf, &out_len, read_buf, numRead);
}
status = buffer_write(&outbuf, cipher_buf, out_len);
printf("AES result bytes: ok=%d\n", ok);
dump_ram(cipher_buf, out_len);
if (status != ENC_OK) EXIT();
if (numRead < BUFSIZE)
{
break; /* this breaks the while */
}
}
/* handle last block */
if (should_encrypt)
{
ok = EVP_EncryptFinal_ex(ctx, cipher_buf, &out_len);
}
else
{
ok = EVP_DecryptFinal_ex(ctx, cipher_buf, &out_len);
}
printf("AES LAST: ok=%d\n", ok);
dump_ram(cipher_buf, out_len);
status = buffer_write(&outbuf, cipher_buf, out_len);
if (status != ENC_OK) EXIT();
*outlen_act = outbuf.act_len;
exit_label:
/* de allocate */
if (cipher_buf) free(cipher_buf);
if (read_buf) free(read_buf);
EVP_CIPHER_CTX_free(ctx);
return status;
}
When I feed the function with
Key = 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36
IV = 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36
Plain = 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36
I get the output:
AES input: num read = 16
31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36
AES result bytes: ok=1
85 7d 51 22 1d 87 4e 53 63 3c da 9f d5 dc 7d 29 <-- first result
AES LAST: ok=1
71 d5 5e 76 23 14 db 09 f6 d8 04 2f d7 5d b6 c9 <-- second result
To be summarized, I get 32 Bytes ciphered text from the 16 bytes plain text:
C = 85 7d 51 22 1d 87 4e 53 63 3c da 9f d5 dc 7d 29 71 d5 5e 76 23 14 db 09 f6 d8 04 2f d7 5d b6 c9
Q: Why does openSSL add additional 16 Bytes? IMO there should be no padding in that case...
When decryption is carried out with this 32 Bytes ciphered text, I get, using the same code
AES input: num read = 32
85 7d 51 22 1d 87 4e 53 63 3c da 9f d5 dc 7d 29
71 d5 5e 76 23 14 db 09 f6 d8 04 2f d7 5d b6 c9
AES result bytes: ok=1
31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36
AES LAST: ok=1
So I get back the original 16 Bytes plain text, with DecryptFinal returning zero bytes (therefore there is no dump).
For comparison, when I decrypt the 32bytes cipered text with this tool the result is
31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36
10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
. . . . . . . . . . . . . . . .
So the result is the original plain text (first line) with an additional line of 0x10.
Trying the same tool to encrypt my plain text will give me only a 16 bytes ciphered string, which is the same as the first 16 bytes I get from openSSL:
85 7d 51 22 1d 87 4e 53 63 3c da 9f d5 dc 7d 29
Why that? Where is the problem??
EVP_CIPHER_CTX_free
by usingunique_ptr
. See EVP Symmetric Encryption and Decryption | C++ Programs on the OpenSSL wiki, unique_ptr and OpenSSL's STACK_OF(X509)*, How to get PKCS7_sign result into a char * or std::string, etc. – jww