Authenticated Encryption with Additional Data using AES-GCM

Example with Additional Data

var key = new byte[]
{
    0x42, 0x90, 0xbc, 0xb1, 0x54, 0x17, 0x35, 0x31, 0xf3, 0x14, 0xaf,
    0x57, 0xf3, 0xbe, 0x3b, 0x50, 0x06, 0xda, 0x37, 0x1e, 0xce, 0x27,
    0x2a, 0xfa, 0x1b, 0x5d, 0xbd, 0xd1, 0x10, 0x0a, 0x10, 0x07
};

var nonce = new byte[]
{
    0xcd, 0x7c, 0xf6, 0x7b, 0xe3, 0x9c, 0x79, 0x4a, 0x79, 0xc0, 0xd1, 0x10
};

var ad = new byte[]
{
    0x87, 0xe2, 0x29, 0xd4, 0x50, 0x08, 0x45, 0xa0, 0x79, 0xc0
};

var m = new byte[]
{
    0x86, 0xd0, 0x99, 0x74, 0x84, 0x0b, 0xde, 0xd2, 0xa5, 0xca
};

// check CPU support
if (SecretAeadAes.IsAvailable())
{
    //encrypt with Additional Data
    var encrypted = SecretAeadAes.Encrypt(m, nonce, key, ad);
    //decrypt with Additional Data
    var decrypted = SecretAeadAes.Decrypt(encrypted, nonce, key, ad);
}
else
{
    Console.WriteLine("Missing AES support");
}

Example without Additional Data

var key = new byte[]
{
    0x42, 0x90, 0xbc, 0xb1, 0x54, 0x17, 0x35, 0x31, 0xf3, 0x14, 0xaf,
    0x57, 0xf3, 0xbe, 0x3b, 0x50, 0x06, 0xda, 0x37, 0x1e, 0xce, 0x27,
    0x2a, 0xfa, 0x1b, 0x5d, 0xbd, 0xd1, 0x10, 0x0a, 0x10, 0x07
};

var nonce = new byte[]
{
    0xcd, 0x7c, 0xf6, 0x7b, 0xe3, 0x9c, 0x79, 0x4a, 0x79, 0xc0, 0xd1, 0x10
};

var m = new byte[]
{
    0x86, 0xd0, 0x99, 0x74, 0x84, 0x0b, 0xde, 0xd2, 0xa5, 0xca
};

// check CPU support
if (SecretAeadAes.IsAvailable())
{
    //encrypt with Additional Data
    var encrypted = SecretAeadAes.Encrypt(m, nonce, key);
    //decrypt with Additional Data
    var decrypted = SecretAeadAes.Decrypt(encrypted, nonce, key);
}
else
{
    Console.WriteLine("Missing AES support");
}

Purpose

This operation:

  • Encrypts a message with a key and a nonce to keep it confidential
  • Computes an authentication tag. This tag is used to make sure that the message, as well as optional, non-confidential (non-encrypted) data, haven't been tampered with.

A typical use case for additional data is to store protocol-specific metadata about the message, such as its length and encoding.

It can also be used as a MAC, with an empty message.

Decryption will never be performed, even partially, before verification.

When supported by the CPU, AES-GCM is the fastest AEAD cipher available in this library.

Limitations

The current implementation of this construction is hardware-accelerated and requires the Intel SSSE3 extensions, as well as the aesni and pclmul instructions.

Intel Westmere processors (introduced in 2010) and newer meet the requirements.

There are no plans to support non hardware-accelerated implementations of AES-GCM. If portability is a concern, use ChaCha20-Poly1305 instead.

Random Helpers

public static byte[] GenerateNonce()

Namespace: Sodium.SecretAeadAes

Uses Sodium.SodiumCore.GetRandomBytes() to generate a 12 byte nonce.

Usage

Check CPU support

public static bool IsAvailable()

This is the .NET equivalent of crypto_aead_aes256gcm_is_available.

Namespace: Sodium.SecretAeadAes

Returns true if the current CPU supports the AES256-GCM implementation, and false if it doesn't.

Encrypt

public static byte[] Encrypt(byte[] message, byte[] nonce, byte[] key, byte[] additionalData = null)

This is the .NET equivalent of crypto_aead_aes256gcm_encrypt.

Namespace: Sodium.SecretAeadAes

The Encrypt() function encrypts a message using a secret key and a public nonce.

The key must be 32 bytes, otherwise the function throws a KeyOutOfRangeException.

The nonce must be 12 bytes, otherwise the function throws a NonceOutOfRangeException.

The public nonce should never ever be reused with the same key. The recommended way to generate it is to use SecretAead.GenerateNonce() for the first message, and increment it for each subsequent message using the same key.

The additionalData may be null (if no additional data is required), or between 0 and 16 bytes, otherwise the function throws a AdditionalDataOutOfRangeException.

The function returns a byte array on success, or throws an CryptographicException() on failure.

Decrypt

public static byte[] Decrypt(byte[] cipher, byte[] nonce, byte[] key, byte[] additionalData = null)

This is the .NET equivalent of crypto_aead_aes256gcm_decrypt.

Namespace: Sodium.SecretAeadAes

The Decrypt() function decrypts a message cipher using a secret key and a public nonce.

The key must be 32 bytes, otherwise the function throws a KeyOutOfRangeException.

The nonce must be 12 bytes, otherwise the function throws a NonceOutOfRangeException.

The additionalData may be null (if no additional data is required), or between 0 and 16 bytes, otherwise the function throws a AdditionalDataOutOfRangeException.

The function returns a byte array on success, or throws an CryptographicException() on failure.

Notes

The nonce is 96 bits long. In order to prevent nonce reuse, if a key is being reused, it is recommended to increment the previous nonce instead of generating a random nonce for each message. To prevent nonce reuse in a client-server protocol, either use different keys for each direction, or make sure that a bit is masked in one direction, and set in the other.