0

I was using the above code from Linux libcrypto AES-128 CBC Encryption/Decryption works on Ubuntu but not Raspberry Pi

Modified the code slightly here

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/crypto.h>  

unsigned char aes_key[]={0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf};

/* Print Encrypted and Decrypted data packets */
void print_data(const char *tittle, const void* data, int len);

int main( )
{
    /* Input data to encrypt */
    unsigned char aes_input[]={0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf};

    fprintf(stderr,"%s\n",SSLeay_version(SSLEAY_VERSION));

    /* Init vector */
    //unsigned char iv[AES_BLOCK_SIZE];
    unsigned char iv[]={0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf};
    //memset(iv, 0x00, AES_BLOCK_SIZE);

    /* Buffers for Encryption and Decryption */
    unsigned char enc_out[sizeof(aes_input)];
    unsigned char dec_out[sizeof(aes_input)];

    /* 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(aes_input, enc_out, sizeof(aes_input), &enc_key, iv,         AES_ENCRYPT);

    FILE *fp = fopen("id_encrypted","w");
    fwrite(enc_out, sizeof(enc_out), 1, fp); // write all the new buffer
    fclose(fp);

    /* 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
    //unsigned char iv[AES_BLOCK_SIZE];
    unsigned char iv2[]={0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf};
    AES_set_decrypt_key(aes_key, sizeof(aes_key)*8, &dec_key); // Size of key is in bits
    AES_cbc_encrypt(enc_out, dec_out, sizeof(aes_input), &dec_key, iv2, AES_DECRYPT);

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

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

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

    return 0;
}

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");
}

If you run the code, you can see the below output.

OpenSSL 1.1.1 11 Sep 2018

Original : 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

Encrypted : C6 A1 3B 37 87 8F 5B 82 6F 4F 81 62 A1 C8 D8 79

Decrypted : 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

My objective is to decrypt the encrypted output file [named as id_encrypted in the code] using openssl CLI.

The command that I have used is

openssl enc -d -v -aes-128-cbc -in id_encrypted -out id_decrypted -K "0123456789abcdef" -iv "0123456789abcdef"

but getting below error message and the output file is empty.

bufsize=8192
hex string is too short, padding with zero bytes to length
hex string is too short, padding with zero bytes to length
bad decrypt
139861660053952:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:../crypto/evp/evp_enc.c:537:

Can anyone help with why it's not working ? I guess, the issue is with the openssl command that I am using, since we can see that the code works for both encryption and decryption.

EsmaeelE
  • 2,331
  • 6
  • 22
  • 31
AKV
  • 425
  • 7
  • 20
  • 2
    `"0123456789abcdef"` is not the same as `0x00, 0x01, 0x02 ...` – stark Jan 13 '20 at 21:24
  • 1
    Note on some systems (cough Windows cough) you must `fopen` with mode `"wb"` (and `"rb"` to read) to handle encrypted or otherwise binary data correctly. Also your _plaintext_ is not a C string, as well as your ciphertext. – dave_thompson_085 Jan 13 '20 at 23:54

1 Answers1

2

Don't write your encryption code this way. You are using the low level AES API which is intended for power users with a very good knowledge of what they are doing. In particular they do not:

  • Perform padding - which is required in most circumstances (and expected during decryption by the OpenSSL CLI)
  • Use optimised and constant time (i.e. the most secure) implementations by default

They are also very easy to misuse and shoot yourself in the foot. For this and the above reasons the low level AES API has been discouraged for a long time by the OpenSSL project team and will be deprecated in the next version of OpenSSL:

https://github.com/openssl/openssl/blob/9ce921f2dacc9f56b8ae932ae9c299670700a297/CHANGES#L394-L413

Instead you should be using the EVP APIs. See this page for example code:

https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption

Aside from this you have some additional problems in the way that you are specifying the key and iv on the OpenSSL CLI. The "-K" argument expects the key in hex. Each hex digit represents 4 bits (not eight). So the key you have given is equivalent to:

01 23 45 67 89 ab cd ef

But what you wanted was:

00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f

There is a similar problem with the IV. So what you really intended is:

$ openssl enc -d -v -aes-128-cbc -in id_encrypted -out id_decrypted -K "000102030405060708090a0b0c0d0e0f" -iv "000102030405060708090a0b0c0d0e0f"

But this still won't work until you've fixed your encryption code to do proper padding.

Edited to add:

You can also use the -nopad option to do decryption without padding. However, this it is still preferable to rewrite your code to not require this.

Matt Caswell
  • 8,167
  • 25
  • 28
  • 2
    ... or they add `-nopad`. Using a block mode without padding is much less flexible and usually undesirable, but it _is_ supported, even in `EVP_{Cipher/Encrypt/Decrypt}*` – dave_thompson_085 Jan 13 '20 at 23:51
  • Thanks @dave_thompson_085 that is correct. I've added that info to my answer. – Matt Caswell Jan 14 '20 at 10:19
  • Thanks @Matt Caswell @ dave_thompson_085. Using `-nopad` worked. But note that based on this [https://stackoverflow.com/questions/46223376/linux-libcrypto-aes-128-cbc-encryption-decryption-works-on-ubuntu-but-not-raspbe?noredirect=1&lq=1], I had to use input as a multiple of AES_BLOCK_SIZE. using input as `aes_input[]="0123456789abcde";` and `openssl enc -d -aes-128-cbc -in id_encrypted -out id_decrypted -K "000102030405060708090a0b0c0d0e0f" -iv "000102030405060708090a0b0c0d0e0f" -nopad` also working fine. So using EVP* is much better, since don't have to deal with all these issues. – AKV Jan 16 '20 at 16:48