1

Here is a sample code for encryption and decrption using openssl EVP. when i perform both encryption and decryption it seems to work fine. When i write the encryted string in file and decript from file i am getting error

encrypt.c

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <stdint.h>
#include <assert.h>

void handleErrors(void)
{
  ERR_print_errors_fp(stderr);
  abort();
}

int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
  unsigned char *iv, unsigned char *ciphertext)
{
  EVP_CIPHER_CTX *ctx;

  int len;

  int ciphertext_len;

  /* Create and initialise the context */
  if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

  if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, iv))
    handleErrors();

  if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
    handleErrors();
  ciphertext_len = len;

  if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
  ciphertext_len += len;

  /* Clean up */
  EVP_CIPHER_CTX_free(ctx);

  return ciphertext_len;
}

int main (int argc, char *argv[])
{
  if ( argc != 2 )
    {
        printf("Usage: <process> <file>\n");
        exit(0);
    }
  /* A 256 bit key */
  unsigned char *key = (unsigned char *) "key";

  /* A 128 bit IV  Should be hardcoded in both encrypt and decrypt. */
  unsigned char *iv = (unsigned char *)"iv";

  /* Message to be encrypted */
  unsigned char *plaintext =
                (unsigned char *)"Password";

  unsigned char ciphertext[128],base64[128];

  /* Buffer for the decrypted text */
  unsigned char decryptedtext[128];

  int decryptedtext_len, ciphertext_len;

  /* Initialise the library */
  ERR_load_crypto_strings();
  OpenSSL_add_all_algorithms();
  OPENSSL_config(NULL);

  /* Encrypt the plaintext */
  ciphertext_len = encrypt (plaintext, strlen ((char *)plaintext), key, iv,
                            ciphertext);

  /* Do something useful with the ciphertext here */
  printf("Ciphertext is:\n");
  BIO_dump_fp (stdout, (const char *)ciphertext, ciphertext_len);

  printf("%d %s\n", ciphertext_len, ciphertext);
  int encode_str_size = EVP_EncodeBlock(base64, ciphertext, ciphertext_len);
    printf("%d %s\n", encode_str_size, base64);

  std::ofstream outFile (argv[1]);
  outFile << base64;
  outFile.close();

  /* Clean up */
  EVP_cleanup();
  ERR_free_strings();

  return 0;
}

decrypt.c

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
#include <iostream>
#include <fstream>
using namespace std;

void handleErrors(void)
{
  ERR_print_errors_fp(stderr);
  abort();
}

int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
  unsigned char *iv, unsigned char *plaintext)
{
  EVP_CIPHER_CTX *ctx;

  int len;

  int plaintext_len;

  /* Create and initialise the context */
  if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

  if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, iv))
    handleErrors();

  if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
    handleErrors();
  plaintext_len = len;

  if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
  plaintext_len += len;

  /* Clean up */
  EVP_CIPHER_CTX_free(ctx);

  return plaintext_len;
}

int main (int argc, char *argv[])
{
  if ( argc != 2 )
        {
                printf("Usage: <process> <file>\n");
                exit(0);
        }

  /* A 256 bit key */
  unsigned char *key = (unsigned char *)"key";

  /* A 128 bit IV */
  unsigned char *iv = (unsigned char *)"iv";

  unsigned char ciphertext[128] = "", base64_in[128] = "", base64_out[128] = "";

  /* Buffer for the decrypted text */
  unsigned char decryptedtext[128]="";

  int decryptedtext_len, ciphertext_len;

  /* Initialise the library */
  ERR_load_crypto_strings();
  OpenSSL_add_all_algorithms();
  OPENSSL_config(NULL);

  /* Encrypt the plaintext */
  char fileBuffer[128] = "";
  ifstream infile (argv[1], ios::binary);
  infile.getline(fileBuffer, sizeof(fileBuffer));
  infile.close(); 

  strcpy((char *)base64_in, fileBuffer);
  ciphertext_len =  (strlen(reinterpret_cast<const char *>(base64_in)));
  printf("%d %s\n",ciphertext_len, base64_in);

  int length = EVP_DecodeBlock(base64_out, base64_in, ciphertext_len);
  while(base64_in[--ciphertext_len] == '=') length--;
  printf("%d %s\n", length,base64_out);

  BIO_dump_fp (stdout, (const char *)base64_out, length);

  decryptedtext_len = decrypt(base64_out, length, key, iv,
   decryptedtext);

  /* Add a NULL terminator. We are expecting printable text */
  decryptedtext[decryptedtext_len] = '\0';

  /* Show the decrypted text */
  printf("Decrypted text is:\n");
  printf("%d %s\n", decryptedtext_len ,decryptedtext);

  /* Clean up */
  EVP_cleanup();
  ERR_free_strings();

  return 0;
}

output

./encrypt file
Ciphertext is:
0000 - 52 6f a3 c6 6b ea 4a aa-a5 e8 9d 26 47 dc e9 b7   Ro..k.J....&G...
16 Ro��k�J����&G�鷈H�t�
24 Um+jxmvqSqql6J0mR9zptw==

./decrypt file
24 Um+jxmvqSqql6J0mR9zptw==
16 Ro��k�J����&G���
0000 - 52 6f a3 c6 6b ea 4a aa-a5 e8 9d 26 47 dc e9 b7   Ro..k.J....&G...
140405999580856:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:529:
Aborted (core dumped)

core

Core was generated by `./decrypt file'.
Program terminated with signal SIGABRT, Aborted.
#0  0x00007efe46356428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
54  ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007efe46356428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1  0x00007efe4635802a in __GI_abort () at abort.c:89
#2  0x000000000040110e in handleErrors() ()
#3  0x00000000004011eb in decrypt(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*) ()
#4  0x0000000000401485 in main ()

When i write to a file and read the contents from a file i am not able to decrypt.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
Raghu DV
  • 258
  • 5
  • 18

2 Answers2

2

The key and IV passed to EVP_EncryptInit_ex and EVP_DecryptInit_ex are not strings but character arrays of a fixed size depending on the cipher.

In the case of AES 256, the key is 32 bytes (256 bits) and the IV 16 bytes (128 bits) in length. The string constants you pass in are not long enough to satisfy those constraints. As a result, the above functions read past the end of those strings, invoking undefined behavior.

As to what is most likely happening, the reason it works when you do the encryption and decryption from within the same program is because you're probably passing the same buffer containing the key and IV to both functions, so both read the same set of unknown bytes after the end of each string. When you then do the same in two different programs this unknown data is different, so you effectively has two different sets of key and IV.

Declare your key and IV to be a fixed size and initialize both. Any bytes not explicitly initialized will be set to 0, so you'll have known quantities.

unsigned char key[32] = (unsigned char *) "key";
unsigned char iv[16] = (unsigned char *)"iv";
dbush
  • 205,898
  • 23
  • 218
  • 273
2

dbush got it right about the key and IV problem, but then he continued to get it running instead of getting it right.

If you want to use a password then you should use a PBKDF: a password based key derivation function. If you want to use a key then you should use a key of 16, 24 or 32 bytes - depending on the required key size of 128, 192 or 256 bits.

OpenSSL provides both an own algorithm called EVP_BytesToKey and PBKDF2. Here is an example (unvetted by me) how to use the latter, more modern algorithm.


In the end an AES key should consist of 128, 192 or 256 bits that seem random to an attacker. If you do not provide AES with such a key then the library should return an error instead of continuing. Deliberately feeding it too few or too many bytes is a recipe for disaster. Padding zero bytes is not the way to expand the key.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263