Skip to content

XChaChaAeadCipher

Tom Auger edited this page Jun 25, 2018 · 2 revisions

Technical Details

Parameter Value
Encryption Algorithm XChaCha20
Authentication Algorithm Poly1305-MAC
Key Size 32 bytes
Nonce Size 24 bytes
Max Message Size 2^64-1 bytes

Description

The XChaChaAeadCipher class wraps the crypto_aead_xchacha20poly1305_ietf_* functions provided in libsodium. The following description of the algorithm is taken from the libsodium documentation [2018-05-30]:

The XChaCha20-Poly1305 construction can safely encrypt a practically unlimited number of messages with the same key, without any practical limit to the size of a message (up to ~ 2^64 bytes).

As an alternative to counters, its large nonce size (192-bit) allows random nonces to be safely used.

Example

The following example demonstrates how to encrypt/decrypt a single message:

Encryption

using (var key = XChaChaKey.Generate())
{
    var aeadCipher = new XChaChaAeadCipher();
    var nonce = XChaChaNonce.Generate();
    var message = Encoding.UTF8.GetBytes("Test Message");
    var ciphertext = aeadCipher.Encrypt(message, key, nonce);
}

Decryption

var keyBytes = Convert.FromBase64String("XPRT6QuYZDdytKM55WW+gnZklhaJBcDnOWi1kEI2we4=");
var nonceBytes = Convert.FromBase64String("2eQuiE8Fy70rwlCAi5T2oVEj5MrwxJaT");
var ciphertext = Convert.FromBase64String("w2jUPkWL0PfvnNFM7xq4o9gcVKrMTkd6SsYhLQ==");
using (var key = new XChaChaKey(keyBytes))
{
    var aeadCipher = new XChaChaAeadCipher();
    var nonce = new XChaChaNonce(nonceBytes);
    var message = aeadCipher.Decrypt(ciphertext, key, nonce);
}

Additional APIs

TryDecrypt

Decrypt will throw a CryptographicException if the decryption fails. Instead, TryDecrypt will return true or false depending on whether the decryption succeeded:

    ...
    bool success = aeadCipher.TryDecrypt(ciphertext, message, key, nonce);

Using a buffer

Overloads of Encrypt/Decrypt/TryDecrypt allow passing in a buffer for the ciphertext/plaintext as demonstrated in the following examples:

Encryption

using (var key = XChaChaKey.Generate())
{
    var aeadCipher = new XChaChaAeadCipher();
    var nonce = XChaChaNonce.Generate();
    var message = Encoding.UTF8.GetBytes("Test Message");
    var ciphertext = new byte[aeadCipher.GetCipherTextLength(message.Length)];
    aeadCipher.Encrypt(message, ciphertext, key, nonce);
}

Decryption

var keyBytes = Convert.FromBase64String("XPRT6QuYZDdytKM55WW+gnZklhaJBcDnOWi1kEI2we4=");
var nonceBytes = Convert.FromBase64String("2eQuiE8Fy70rwlCAi5T2oVEj5MrwxJaT");
var ciphertext = Convert.FromBase64String("w2jUPkWL0PfvnNFM7xq4o9gcVKrMTkd6SsYhLQ==");
using (var key = new XChaChaKey(keyBytes))
{
    var aeadCipher = new XChaChaAeadCipher();
    var nonce = new XChaChaNonce(nonceBytes);
    var message = new byte[aeadCipher.GetPlaintextLength(ciphertext.Length)];
    aeadCipher.Decrypt(ciphertext, message, key, nonce);
}

Additional Authenticated Data

Overloads of Encrypt/Decrypt/TryDecrypt allow passing Additional Authenticated Data to be used when computing the authentication tag:

Encryption

...
var aad = Encoding.UTF8.GetBytes(DateTime.Now.ToString());
var ciphertext = aeadCipher.Encrypt(message, key, nonce, aad);

Decryption

...
var aad = Encoding.UTF8.GetBytes(DateTime.Now.ToString());
var message = aeadCipher.Decrypt(ciphertext, key, nonce, aad);