Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenSSL C example of AES-GCM using EVP interfaces

For AES-GCM encryption/decryption, I tried this, but it has a problem.

ctx     = EVP_CIPHER_CTX_new();

//Get the cipher.
cipher  = EVP_aes_128_gcm ();


#define     GCM_IV      "000000000000"
#define     GCM_ADD     "0000"
#define     TAG_SIZE    16
#define     ENC_SIZE    64


//Encrypt the data first.
//Set the cipher and context only.
retv    = EVP_EncryptInit (ctx, cipher, NULL, NULL);

//Set the nonce and tag sizes.
//Set IV length. [Optional for GCM].

retv    = EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_SET_IVLEN, strlen((const char *)GCM_IV), NULL);

//Now initialize the context with key and IV. 
retv    = EVP_EncryptInit (ctx, NULL, (const unsigned char *)keybuf, (const unsigned char *)GCM_IV);

//Add Additional associated data (AAD). [Optional for GCM]
retv    = EVP_EncryptUpdate (ctx, NULL, (int *)&enclen, (const unsigned char *)GCM_ADD, strlen(GCM_ADD));

//Now encrypt the data.
retv    = EVP_EncryptUpdate (ctx, (unsigned char *)encm, (int *)&enclen, (const unsigned char *)msg, _tcslen (msg) *sizeof(Char));

//Finalize.
retv    = EVP_EncryptFinal (ctx, (unsigned char *)encm + enclen, (int *)&enclen2);
enclen  += enclen2;


//Append authentication tag at the end.
retv    = EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_GET_TAG, TAG_SIZE, (unsigned char *)encm + enclen);

//DECRYPTION PART
//Now Decryption of the data.
//Then decrypt the data.
//Set just cipher.
retv    = EVP_DecryptInit(ctx, cipher, NULL, NULL);

//Set Nonce size.
retv    = EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_SET_IVLEN, strlen((const char *)GCM_IV), NULL);

//Set Tag from the data.
retv    = EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_SET_TAG, TAG_SIZE, (unsigned char *)encm + enclen);

//Set key and IV (nonce).
retv    = EVP_DecryptInit (ctx, NULL, (const unsigned char*)keybuf, (const unsigned char *)GCM_IV);

//Add Additional associated data (AAD).
retv    = EVP_DecryptUpdate (ctx, NULL, (int *)&declen, (const unsigned char *)GCM_ADD,
                             strlen((const char *)GCM_ADD));

//Decrypt the data.
retv    = EVP_DecryptUpdate (ctx, decm, (int *)&declen, (const unsigned char *)encm, enclen);


//Finalize.
retv    = EVP_DecryptFinal (ctx, (unsigned char*)decm + declen, (int *)&declen2);

This code is working fine (with some modifications). It is encrypting and decrypting the message. The problem is that when cipher text is modified before decryption, it still decrypts the text (however, wrong). As per my understanding of authenticated encryption, in such cases, it should not decrypt the modified cipher texts.

Where am I wrong? Can I get any suitable example of AES-GCM using EVP interfaces of OpenSSL?

like image 544
doptimusprime Avatar asked Aug 28 '12 04:08

doptimusprime


People also ask

Does OpenSSL support AES-GCM?

If you don't mind writing your own software, there are plenty of crypto libraries supporting AES-GCM, such as OpenSSL itself (even if not available from the command line tool).

What is EVP OpenSSL?

The EVP functions provide a high level interface to OpenSSL cryptographic functions. They provide the following features: A single consistent interface regardless of the underlying algorithm or mode. Support for an extensive range of algorithms. Encryption/Decryption using both symmetric and asymmetric algorithms.

How does AES-GCM work?

AES-GCM have two main functions are block cipher encryption and multiplication over the field . The authenticated encryption operation takes Initialization Vector (IV), Additional Authenticated Data (AAD),secret key and plaintext as an input in128-bit and gives a 128-bit ciphertext and authentication tag,T.


1 Answers

Here is an example to encrypt and decrypt 128 bytes every call to update for example:

  int howmany, dec_success, len;
  const EVP_CIPHER *cipher;
  switch(key_len)
  {
  case 128: cipher  = EVP_aes_128_gcm ();break;
  case 192: cipher  = EVP_aes_192_gcm ();break;
  case 256: cipher  = EVP_aes_256_gcm ();break;
  default:break;
  }
  // Encrypt
  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
  EVP_EncryptInit (ctx, cipher, KEY, IV);
  EVP_EncryptUpdate (ctx, NULL, &howmany, AAD, aad_len);
  len = 0;
  while(len <= in_len-128)
  {
     EVP_EncryptUpdate (ctx, CIPHERTEXT+len, &howmany, PLAINTEXT+len, 128);
     len+=128;
  }
  EVP_EncryptUpdate (ctx, CIPHERTEXT+len, &howmany, PLAINTEXT+len, in_len - len);
  EVP_EncryptFinal (ctx, TAG, &howmany);
  EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_GET_TAG, 16, TAG);  
  EVP_CIPHER_CTX_free(ctx);
  // Decrypt
  ctx = EVP_CIPHER_CTX_new();      
  EVP_DecryptInit (ctx, cipher, KEY, IV);
  EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_SET_TAG, 16, ref_TAG);
  EVP_DecryptInit (ctx, NULL, KEY, IV);
  EVP_DecryptUpdate (ctx, NULL, &howmany, AAD, aad_len);
  len = 0;
  while(len <= in_len-128)
  {
     EVP_DecryptUpdate (ctx, decrypted_CT+len, &howmany, CIPHERTEXT+len, 128);
     len+=128;
  }
  EVP_DecryptUpdate (ctx, decrypted_CT+len, &howmany, CIPHERTEXT+len, in_len-len);
  dec_success = EVP_DecryptFinal (ctx, dec_TAG, &howmany);
  EVP_CIPHER_CTX_free(ctx);

In the end you should check that the value of dec_success is 1. If you modify the CIPHERTEXT, before you decrypt it, you should get value of 0.

like image 119
Vlad Krasnov Avatar answered Sep 23 '22 15:09

Vlad Krasnov