Difference between revisions of "EVP Authenticated Encryption and Decryption"

From OpenSSLWiki
Jump to navigationJump to search
m (Minor fix)
m (Add additional information.)
 
(21 intermediate revisions by 6 users not shown)
Line 1: Line 1:
The EVP interface supports the ability to perform authenticated encryption and decryption. As for standard symmetric encryption you will need to know the following:
+
{{DocInclude
* Your algorithm (currently only AES is supported)
+
|Name=Authenticated Encryption and Decryption
* Your mode (currently only GCM and CCM are supported)
+
|Url=http://wiki.openssl.org/index.php/Manual:Evp(3)
* Your key
+
|Include=evp.h}}
* Your Initialisation Vector (IV)
 
  
In addition you can (optionally) provide some "Additional Authenticated Data" (AAD). The AAD data is not encrypted, and is typically passed to the recipient in plaintext along with the ciphertext.
+
The EVP interface supports the ability to perform authenticated encryption and decryption, as well as the option to attach unencrypted, associated data to the message. Such Authenticated-Encryption with Associated-Data (AEAD) schemes provide confidentiality by encrypting the data, and also provide authenticity assurances by creating a MAC tag over the encrypted data. The MAC tag will ensure the data is not accidentally altered or maliciously tampered during transmission and storage.
 +
 
 +
There are a number of AEAD modes of operation. The modes include EAX, CCM and GCM mode. Using AEAD modes is nearly identical to using standard symmetric encryption modes like CBC, CFB and OFB modes.
 +
 
 +
As with standard symmetric encryption you will need to know the following:
 +
 
 +
* Algorithm (currently only AES is supported)
 +
* Mode (currently only GCM and CCM are supported)
 +
* Key
 +
* Initialisation Vector (IV)
 +
 
 +
In addition you can (optionally) provide some ''Additional Authenticated Data'' (AAD). The AAD data is not encrypted, and is typically passed to the recipient in plaintext along with the ciphertext. An example of AAD is the IP address and port number in a IP header used with IPsec.
  
 
The output from the encryption operation will be the ciphertext, and a tag. The tag is subsequently used during the decryption operation to ensure that the ciphertext and AAD have not been tampered with.
 
The output from the encryption operation will be the ciphertext, and a tag. The tag is subsequently used during the decryption operation to ensure that the ciphertext and AAD have not been tampered with.
  
The OpenSSL manual describes the usage of the GCM and CCM modes here: http://www.openssl.org/docs/crypto/EVP_EncryptInit.html#GCM_Mode.
+
The OpenSSL manual describes the usage of the GCM and CCM modes here: [[Manual:EVP_EncryptInit(3)#GCM_Mode]].
 +
 
 +
The complete source code of the following examples can be downloaded as [[Media:evp-gcm-encrypt.c|evp-gcm-encrypt.c]] resp.  [[Media:evp-ccm-encrypt.c|evp-ccm-encrypt.c]].
  
 
==Authenticated Encryption using GCM mode==
 
==Authenticated Encryption using GCM mode==
Line 16: Line 28:
 
* You may optionally pass through an IV length using EVP_CIPHER_CTX_ctrl
 
* You may optionally pass through an IV length using EVP_CIPHER_CTX_ctrl
 
* AAD data is passed through in zero or more calls to EVP_EncryptUpdate, with the output buffer set to NULL
 
* AAD data is passed through in zero or more calls to EVP_EncryptUpdate, with the output buffer set to NULL
 +
* Once private data has been added using EVP_EncryptUpdate (non-NULL output buffer), you cannot add AAD data
 
* After the EVP_EncryptFinal_ex call a new call to EVP_CIPHER_CTX_ctrl retrieves the tag
 
* After the EVP_EncryptFinal_ex call a new call to EVP_CIPHER_CTX_ctrl retrieves the tag
  
 
See the code below for an example:
 
See the code below for an example:
 
<pre>
 
<pre>
int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *aad,
+
int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
int aad_len, unsigned char *key, unsigned char *iv,
+
                unsigned char *aad, int aad_len,
unsigned char *ciphertext, unsigned char *tag)
+
                unsigned char *key,
 +
                unsigned char *iv, int iv_len,
 +
                unsigned char *ciphertext,
 +
                unsigned char *tag)
 
{
 
{
EVP_CIPHER_CTX *ctx;
+
    EVP_CIPHER_CTX *ctx;
  
int len;
+
    int len;
  
int ciphertext_len;
+
    int ciphertext_len;
  
  
/* Create and initialise the context */
+
    /* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
+
    if(!(ctx = EVP_CIPHER_CTX_new()))
 +
        handleErrors();
  
/* Initialise the encryption operation. */
+
    /* Initialise the encryption operation. */
if(!EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
+
    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
handleErrors();
+
        handleErrors();
  
/* Set IV length if default 12 bytes (96 bits) is not appropriate */
+
    /*
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
+
    * Set IV length if default 12 bytes (96 bits) is not appropriate
handleErrors();
+
    */
 +
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
 +
        handleErrors();
  
/* Initialise key and IV */
+
    /* Initialise key and IV */
if(!EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
+
    if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
 +
        handleErrors();
  
/* Provide any AAD data. This can be called zero or more times as
+
    /*
* required
+
    * Provide any AAD data. This can be called zero or more times as
*/
+
    * required
if(!EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
+
    */
handleErrors();
+
    if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
 +
        handleErrors();
  
/* Provide the message to be encrypted, and obtain the encrypted output.
+
    /*
* EVP_EncryptUpdate can be called multiple times if necessary
+
    * Provide the message to be encrypted, and obtain the encrypted output.
*/
+
    * EVP_EncryptUpdate can be called multiple times if necessary
if(!EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
+
    */
handleErrors();
+
    if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
ciphertext_len = len;
+
        handleErrors();
 +
    ciphertext_len = len;
  
/* Finalise the encryption. Normally ciphertext bytes may be written at
+
    /*
* this stage, but this does not occur in GCM mode
+
    * Finalise the encryption. Normally ciphertext bytes may be written at
*/
+
    * this stage, but this does not occur in GCM mode
if(!EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
+
    */
ciphertext_len += len;
+
    if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
 +
        handleErrors();
 +
    ciphertext_len += len;
  
/* Get the tag */
+
    /* Get the tag */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
+
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
handleErrors();
+
        handleErrors();
  
/* Clean up */
+
    /* Clean up */
EVP_CIPHER_CTX_free(ctx);
+
    EVP_CIPHER_CTX_free(ctx);
  
return ciphertext_len;
+
    return ciphertext_len;
 
}
 
}
 
</pre>
 
</pre>
Line 86: Line 110:
  
 
<pre>
 
<pre>
int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *aad,
+
int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len,
int aad_len, unsigned char *tag, unsigned char *key, unsigned char *iv,
+
                unsigned char *aad, int aad_len,
unsigned char *plaintext)
+
                unsigned char *tag,
 +
                unsigned char *key,
 +
                unsigned char *iv, int iv_len,
 +
                unsigned char *plaintext)
 +
{
 +
    EVP_CIPHER_CTX *ctx;
 +
    int len;
 +
    int plaintext_len;
 +
    int ret;
 +
 
 +
    /* Create and initialise the context */
 +
    if(!(ctx = EVP_CIPHER_CTX_new()))
 +
        handleErrors();
 +
 
 +
    /* Initialise the decryption operation. */
 +
    if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
 +
        handleErrors();
 +
 
 +
    /* Set IV length. Not necessary if this is 12 bytes (96 bits) */
 +
    if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
 +
        handleErrors();
 +
 
 +
    /* Initialise key and IV */
 +
    if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
 +
        handleErrors();
 +
 
 +
    /*
 +
    * Provide any AAD data. This can be called zero or more times as
 +
    * required
 +
    */
 +
    if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
 +
        handleErrors();
 +
 
 +
    /*
 +
    * Provide the message to be decrypted, and obtain the plaintext output.
 +
    * EVP_DecryptUpdate can be called multiple times if necessary
 +
    */
 +
    if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
 +
        handleErrors();
 +
    plaintext_len = len;
 +
 
 +
    /* Set expected tag value. Works in OpenSSL 1.0.1d and later */
 +
    if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
 +
        handleErrors();
 +
 
 +
    /*
 +
    * Finalise the decryption. A positive return value indicates success,
 +
    * anything else is a failure - the plaintext is not trustworthy.
 +
    */
 +
    ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
 +
 
 +
    /* Clean up */
 +
    EVP_CIPHER_CTX_free(ctx);
 +
 
 +
    if(ret > 0) {
 +
        /* Success */
 +
        plaintext_len += len;
 +
        return plaintext_len;
 +
    } else {
 +
        /* Verify failed */
 +
        return -1;
 +
    }
 +
}
 +
</pre>
 +
 
 +
==Authenticated Encryption using CCM mode==
 +
 
 +
Encryption with CCM mode is much the same as for encryption with GCM but with some additional things to bear in mind.
 +
* you can only call EVP_EncryptUpdate once for AAD and once for the plaintext.
 +
* The total plaintext length must be passed to EVP_EncryptUpdate (only needed if AAD is passed)
 +
* Optionally the tag and IV length can also be passed. If they are not then the defaults are used (12 bytes for AES tags, and 7 bytes for AES IVs)
 +
 
 +
See the code below for an example:
 +
<pre>
 +
int ccm_encrypt(unsigned char *plaintext, int plaintext_len,
 +
                unsigned char *aad, int aad_len,
 +
                unsigned char *key,
 +
                unsigned char *iv,
 +
                unsigned char *ciphertext,
 +
                unsigned char *tag)
 +
{
 +
    EVP_CIPHER_CTX *ctx;
 +
 
 +
    int len;
 +
 
 +
    int ciphertext_len;
 +
 
 +
 
 +
    /* Create and initialise the context */
 +
    if(!(ctx = EVP_CIPHER_CTX_new()))
 +
        handleErrors();
 +
 
 +
    /* Initialise the encryption operation. */
 +
    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL))
 +
        handleErrors();
 +
 
 +
    /*
 +
    * Setting IV len to 7. Not strictly necessary as this is the default
 +
    * but shown here for the purposes of this example.
 +
    */
 +
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, 7, NULL))
 +
        handleErrors();
 +
 
 +
    /* Set tag length */
 +
    EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, 14, NULL);
 +
 
 +
    /* Initialise key and IV */
 +
    if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
 +
        handleErrors();
 +
 
 +
    /* Provide the total plaintext length */
 +
    if(1 != EVP_EncryptUpdate(ctx, NULL, &len, NULL, plaintext_len))
 +
        handleErrors();
 +
 
 +
    /* Provide any AAD data. This can be called zero or one times as required */
 +
    if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
 +
        handleErrors();
 +
 
 +
    /*
 +
    * Provide the message to be encrypted, and obtain the encrypted output.
 +
    * EVP_EncryptUpdate can only be called once for this.
 +
    */
 +
    if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
 +
        handleErrors();
 +
    ciphertext_len = len;
 +
 
 +
    /*
 +
    * Finalise the encryption. Normally ciphertext bytes may be written at
 +
    * this stage, but this does not occur in CCM mode.
 +
    */
 +
    if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
 +
        handleErrors();
 +
    ciphertext_len += len;
 +
 
 +
    /* Get the tag */
 +
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, 14, tag))
 +
        handleErrors();
 +
 
 +
    /* Clean up */
 +
    EVP_CIPHER_CTX_free(ctx);
 +
 
 +
    return ciphertext_len;
 +
}
 +
</pre>
 +
 
 +
==Authenticated Decryption using CCM mode==
 +
 
 +
Decryption with CCM mode is much the same as for decryption with CCM but with some additional things to bear in mind.
 +
* you can only call EVP_DecryptUpdate once for AAD and once for the plaintext.
 +
* The total ciphertext length must be passed to EVP_DecryptUpdate (only needed if AAD is passed)
 +
* Optionally the tag and IV length can also be passed. If they are not then the defaults are used (12 bytes for AES tags, and 7 bytes for AES IVs)
 +
* The tag verify is performed when you call the final EVP_DecryptUpdate and is reflected by the return value: there is no call to EVP_DecryptFinal.
 +
 
 +
See the code below for an example:
 +
<pre>
 +
int ccm_decrypt(unsigned char *ciphertext, int ciphertext_len,
 +
                unsigned char *aad, int aad_len,
 +
                unsigned char *tag,
 +
                unsigned char *key,
 +
                unsigned char *iv,
 +
                unsigned char *plaintext)
 
{
 
{
EVP_CIPHER_CTX *ctx;
+
    EVP_CIPHER_CTX *ctx;
int len;
+
    int len;
int plaintext_len;
+
    int plaintext_len;
int ret;
+
    int ret;
  
/* Create and initialise the context */
+
    /* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
+
    if(!(ctx = EVP_CIPHER_CTX_new()))
 +
        handleErrors();
  
/* Initialise the decryption operation. */
+
    /* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
+
    if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL))
handleErrors();
+
        handleErrors();
  
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
+
    /* Setting IV len to 7. Not strictly necessary as this is the default
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
+
    * but shown here for the purposes of this example */
handleErrors();
+
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, 7, NULL))
 +
        handleErrors();
  
/* Initialise key and IV */
+
    /* Set expected tag value. */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
+
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, 14, tag))
 +
        handleErrors();
  
/* Provide any AAD data. This can be called zero or more times as
+
    /* Initialise key and IV */
* required
+
    if(1 != EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
*/
+
        handleErrors();
if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
 
handleErrors();
 
  
/* Provide the message to be decrypted, and obtain the plaintext output.
 
* EVP_DecryptUpdate can be called multiple times if necessary
 
*/
 
if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
 
handleErrors();
 
plaintext_len = len;
 
  
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
+
    /* Provide the total ciphertext length */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
+
    if(1 != EVP_DecryptUpdate(ctx, NULL, &len, NULL, ciphertext_len))
handleErrors();
+
        handleErrors();
  
/* Finalise the decryption. A positive return value indicates success,
+
    /* Provide any AAD data. This can be called zero or more times as required */
* anything else is a failure - the plaintext is not trustworthy.
+
    if(1 != EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
*/
+
        handleErrors();
ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
 
  
/* Clean up */
+
    /*
EVP_CIPHER_CTX_free(ctx);
+
    * Provide the message to be decrypted, and obtain the plaintext output.
 +
    * EVP_DecryptUpdate can be called multiple times if necessary
 +
    */
 +
    ret = EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len);
  
if(ret > 0)
+
    plaintext_len = len;
{
+
 
/* Success */
+
    /* Clean up */
plaintext_len += len;
+
    EVP_CIPHER_CTX_free(ctx);
return plaintext_len;
+
 
}
+
    if(ret > 0) {
else
+
        /* Success */
{
+
        return plaintext_len;
/* Verify failed */
+
    } else {
return -1;
+
        /* Verify failed */
}
+
        return -1;
 +
    }
 
}
 
}
 
</pre>
 
</pre>
 +
 +
== Potential Issue in AES/GCM ==
 +
 +
Early versions of the authenticated encryption interface required using a 0-sized array (not a NULL array) to arrive at the proper authentication tag '''''when''''' the authentication tag size was ''not'' a multiple of the block size (for example, an authentication tag size of 20 bytes). For more information on the issue and the work-arounds, see [http://rt.openssl.org/Ticket/Display.html?id=2859 Issue #2859: Possible bug in AES GCM mode] and [http://groups.google.com/d/msg/mailing.openssl.users/idg9Z22MYZs/Jqlo8dA-2tMJ Possible bug in GCM/GMAC with (just) AAD of size unequal to block size].
 +
 +
==See also==
 +
* [[EVP]]
 +
* [[Libcrypto API]]
 +
* [[EVP Symmetric Encryption and Decryption]]
 +
* [[EVP Asymmetric Encryption and Decryption of an Envelope]]
 +
* [[EVP Signing and Verifying]]
 +
* [[EVP Message Digests]]
 +
* [[EVP Key Agreement]]
 +
* [[EVP Key and Parameter Generation]]
 +
 +
[[Category:Crypto API]]
 +
[[Category:C level]]
 +
[[Category:Examples]]

Latest revision as of 04:48, 5 June 2019

Authenticated Encryption and Decryption
Documentation
#include <openssl/evp.h>

The EVP interface supports the ability to perform authenticated encryption and decryption, as well as the option to attach unencrypted, associated data to the message. Such Authenticated-Encryption with Associated-Data (AEAD) schemes provide confidentiality by encrypting the data, and also provide authenticity assurances by creating a MAC tag over the encrypted data. The MAC tag will ensure the data is not accidentally altered or maliciously tampered during transmission and storage.

There are a number of AEAD modes of operation. The modes include EAX, CCM and GCM mode. Using AEAD modes is nearly identical to using standard symmetric encryption modes like CBC, CFB and OFB modes.

As with standard symmetric encryption you will need to know the following:

  • Algorithm (currently only AES is supported)
  • Mode (currently only GCM and CCM are supported)
  • Key
  • Initialisation Vector (IV)

In addition you can (optionally) provide some Additional Authenticated Data (AAD). The AAD data is not encrypted, and is typically passed to the recipient in plaintext along with the ciphertext. An example of AAD is the IP address and port number in a IP header used with IPsec.

The output from the encryption operation will be the ciphertext, and a tag. The tag is subsequently used during the decryption operation to ensure that the ciphertext and AAD have not been tampered with.

The OpenSSL manual describes the usage of the GCM and CCM modes here: Manual:EVP_EncryptInit(3)#GCM_Mode.

The complete source code of the following examples can be downloaded as evp-gcm-encrypt.c resp. evp-ccm-encrypt.c.

Authenticated Encryption using GCM mode[edit]

Encryption is performed in much the same way as for symmetric encryption as described here. The main differences are:

  • You may optionally pass through an IV length using EVP_CIPHER_CTX_ctrl
  • AAD data is passed through in zero or more calls to EVP_EncryptUpdate, with the output buffer set to NULL
  • Once private data has been added using EVP_EncryptUpdate (non-NULL output buffer), you cannot add AAD data
  • After the EVP_EncryptFinal_ex call a new call to EVP_CIPHER_CTX_ctrl retrieves the tag

See the code below for an example:

int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
                unsigned char *aad, int aad_len,
                unsigned char *key,
                unsigned char *iv, int iv_len,
                unsigned char *ciphertext,
                unsigned char *tag)
{
    EVP_CIPHER_CTX *ctx;

    int len;

    int ciphertext_len;


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

    /* Initialise the encryption operation. */
    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
        handleErrors();

    /*
     * Set IV length if default 12 bytes (96 bits) is not appropriate
     */
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
        handleErrors();

    /* Initialise key and IV */
    if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
        handleErrors();

    /*
     * Provide any AAD data. This can be called zero or more times as
     * required
     */
    if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
        handleErrors();

    /*
     * Provide the message to be encrypted, and obtain the encrypted output.
     * EVP_EncryptUpdate can be called multiple times if necessary
     */
    if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
        handleErrors();
    ciphertext_len = len;

    /*
     * Finalise the encryption. Normally ciphertext bytes may be written at
     * this stage, but this does not occur in GCM mode
     */
    if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
        handleErrors();
    ciphertext_len += len;

    /* Get the tag */
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
        handleErrors();

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    return ciphertext_len;
}

Authenticated Decryption using GCM mode[edit]

Again, the decryption operation is much the same as for normal symmetric decryption as described here. The main differences are:

  • You may optionally pass through an IV length using EVP_CIPHER_CTX_ctrl
  • AAD data is passed through in zero or more calls to EVP_DecryptUpdate, with the output buffer set to NULL
  • Prior to the EVP_DecryptFinal_ex call a new call to EVP_CIPHER_CTX_ctrl provides the tag
  • A non positive return value from EVP_DecryptFinal_ex should be considered as a failure to authenticate ciphertext and/or AAD. It does not necessarily indicate a more serious error.

See the code example below:

int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len,
                unsigned char *aad, int aad_len,
                unsigned char *tag,
                unsigned char *key,
                unsigned char *iv, int iv_len,
                unsigned char *plaintext)
{
    EVP_CIPHER_CTX *ctx;
    int len;
    int plaintext_len;
    int ret;

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

    /* Initialise the decryption operation. */
    if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
        handleErrors();

    /* Set IV length. Not necessary if this is 12 bytes (96 bits) */
    if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
        handleErrors();

    /* Initialise key and IV */
    if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
        handleErrors();

    /*
     * Provide any AAD data. This can be called zero or more times as
     * required
     */
    if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
        handleErrors();

    /*
     * Provide the message to be decrypted, and obtain the plaintext output.
     * EVP_DecryptUpdate can be called multiple times if necessary
     */
    if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
        handleErrors();
    plaintext_len = len;

    /* Set expected tag value. Works in OpenSSL 1.0.1d and later */
    if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
        handleErrors();

    /*
     * Finalise the decryption. A positive return value indicates success,
     * anything else is a failure - the plaintext is not trustworthy.
     */
    ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    if(ret > 0) {
        /* Success */
        plaintext_len += len;
        return plaintext_len;
    } else {
        /* Verify failed */
        return -1;
    }
}

Authenticated Encryption using CCM mode[edit]

Encryption with CCM mode is much the same as for encryption with GCM but with some additional things to bear in mind.

  • you can only call EVP_EncryptUpdate once for AAD and once for the plaintext.
  • The total plaintext length must be passed to EVP_EncryptUpdate (only needed if AAD is passed)
  • Optionally the tag and IV length can also be passed. If they are not then the defaults are used (12 bytes for AES tags, and 7 bytes for AES IVs)

See the code below for an example:

int ccm_encrypt(unsigned char *plaintext, int plaintext_len,
                unsigned char *aad, int aad_len,
                unsigned char *key,
                unsigned char *iv,
                unsigned char *ciphertext,
                unsigned char *tag)
{
    EVP_CIPHER_CTX *ctx;

    int len;

    int ciphertext_len;


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

    /* Initialise the encryption operation. */
    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL))
        handleErrors();

    /*
     * Setting IV len to 7. Not strictly necessary as this is the default
     * but shown here for the purposes of this example.
     */
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, 7, NULL))
        handleErrors();

    /* Set tag length */
    EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, 14, NULL);

    /* Initialise key and IV */
    if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
        handleErrors();

    /* Provide the total plaintext length */
    if(1 != EVP_EncryptUpdate(ctx, NULL, &len, NULL, plaintext_len))
        handleErrors();

    /* Provide any AAD data. This can be called zero or one times as required */
    if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
        handleErrors();

    /*
     * Provide the message to be encrypted, and obtain the encrypted output.
     * EVP_EncryptUpdate can only be called once for this.
     */
    if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
        handleErrors();
    ciphertext_len = len;

    /*
     * Finalise the encryption. Normally ciphertext bytes may be written at
     * this stage, but this does not occur in CCM mode.
     */
    if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
        handleErrors();
    ciphertext_len += len;

    /* Get the tag */
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, 14, tag))
        handleErrors();

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    return ciphertext_len;
}

Authenticated Decryption using CCM mode[edit]

Decryption with CCM mode is much the same as for decryption with CCM but with some additional things to bear in mind.

  • you can only call EVP_DecryptUpdate once for AAD and once for the plaintext.
  • The total ciphertext length must be passed to EVP_DecryptUpdate (only needed if AAD is passed)
  • Optionally the tag and IV length can also be passed. If they are not then the defaults are used (12 bytes for AES tags, and 7 bytes for AES IVs)
  • The tag verify is performed when you call the final EVP_DecryptUpdate and is reflected by the return value: there is no call to EVP_DecryptFinal.

See the code below for an example:

int ccm_decrypt(unsigned char *ciphertext, int ciphertext_len,
                unsigned char *aad, int aad_len,
                unsigned char *tag,
                unsigned char *key,
                unsigned char *iv,
                unsigned char *plaintext)
{
    EVP_CIPHER_CTX *ctx;
    int len;
    int plaintext_len;
    int ret;

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

    /* Initialise the decryption operation. */
    if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL))
        handleErrors();

    /* Setting IV len to 7. Not strictly necessary as this is the default
     * but shown here for the purposes of this example */
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, 7, NULL))
        handleErrors();

    /* Set expected tag value. */
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, 14, tag))
        handleErrors();

    /* Initialise key and IV */
    if(1 != EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
        handleErrors();


    /* Provide the total ciphertext length */
    if(1 != EVP_DecryptUpdate(ctx, NULL, &len, NULL, ciphertext_len))
        handleErrors();

    /* Provide any AAD data. This can be called zero or more times as required */
    if(1 != EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
        handleErrors();

    /*
     * Provide the message to be decrypted, and obtain the plaintext output.
     * EVP_DecryptUpdate can be called multiple times if necessary
     */
    ret = EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len);

    plaintext_len = len;

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    if(ret > 0) {
        /* Success */
        return plaintext_len;
    } else {
        /* Verify failed */
        return -1;
    }
}

Potential Issue in AES/GCM[edit]

Early versions of the authenticated encryption interface required using a 0-sized array (not a NULL array) to arrive at the proper authentication tag when the authentication tag size was not a multiple of the block size (for example, an authentication tag size of 20 bytes). For more information on the issue and the work-arounds, see Issue #2859: Possible bug in AES GCM mode and Possible bug in GCM/GMAC with (just) AAD of size unequal to block size.

See also[edit]