ChaCha20 and a Bouncy Castle

Which encryption method just needs an EX-OR function to encrypt and to decrypt? Well, that will be a stream encryption method, and where to…

ChaCha20 and a Bouncy Castle

Which encryption method just needs an EX-OR function to encrypt and to decrypt? Well, that will be a stream encryption method, and where to EX-OR each bit of our plain text stream with our cipher key stream.

AES has become the gold standard for encryption and will hopefully remain robust in a world of quantum computers. But what if someone finds a vulnerability in it? And surely it is rather complex for simple IoT devices to implement?

Well, for TLS 1.3, Google has been searching for a replacement for RC4 — and which has been shown to have flaws — and have settled on ChaCha20 for symmetric key encryption and Poly1305 for a message authentication code (MAC). Both were originally created by Daniel J. Bernstein, and focus on not relying on AES as a core method:

Google has been pushing for improved cryptography methods, and can move the market because of its predominance with Chrome.

ChaCha20 takes a 256-bit key and a 96-bit nonce and then creates a key stream, which is then XORed with the plaintext stream. In software, it is three times faster than AES, and is well suited to lower-powered devices and in real time communications. It is integrated into TLS with:

and where the define the following cipher suites:

TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256   = {0xCC, 0xA8}
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xA9}
TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAA}TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAB}
TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAC}
TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAD}
TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAE}

With this, for TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, we can used ECDHE for the key exchange, RSA for the authentcation, SHA-256 for the hash, and ChaCha20/Poly1305 for the symmetric key method.

Implementation

The Chacha20 Cipher is a stream cipher which uses a 256-bit key and a 64-bit nonce [paper]. Currently AES has a virtual monopoly on secret key encryption. There would be major problems, though, if this was cracked. Along with this AES has been shown to be weak around cache-collision attacks. Google thus propose ChaCha20 as an alternative, and actively use it within TLS connections. Currently it is three times faster than software-enabled AES, and is not sensitive to timing attacks. It operates by creating a key stream which is then X-ORed with the plaintext. It has been standardised with RFC 7539.

First we can create code with integrates with ChaCha20 in the Bouncy Castle library. This uses a 92 bit (12 byte) nonce value (typically known as an IV — Initialization Vector), and additional data. This additional data is used to create AEAD (Authenticated Encryption with Additional Data) [here]:


namespace ChaCha20
{
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;

class Program
{

static void Main(string[] args)
{



var msg="Hello";
var add="";
var iv="000102030405060708090A0B";
var size=256;

if (args.Length >0) msg=args[0];
if (args.Length >1) add=args[1];
if (args.Length >2) iv=args[2];
if (args.Length >3) size=Convert.ToInt32(args[3]);



try {

var plainTextData=System.Text.Encoding.UTF8.GetBytes(msg);

ChaCha20Poly1305 cipher = new ChaCha20Poly1305();

int macSize = 128;
byte[] nonce = new byte[12];
Array.Copy(Convert.FromHexString(iv), nonce, 12);

byte[] associatedText =System.Text.Encoding.UTF8.GetBytes(add);


CipherKeyGenerator keyGen = new CipherKeyGenerator();
keyGen.Init(new KeyGenerationParameters(new SecureRandom(), size));
KeyParameter keyParam = keyGen.GenerateKeyParameter();

AeadParameters keyParamAead = new AeadParameters(keyParam, macSize, nonce, associatedText);


cipher.Init(true,keyParamAead);

int outputSize = cipher.GetOutputSize(plainTextData.Length);

byte[] cipherTextData = new byte[outputSize];
int result = cipher.ProcessBytes(plainTextData, 0, plainTextData.Length, cipherTextData, 0);
cipher.DoFinal(cipherTextData, result);
var rtn = cipherTextData;


// Decrypt
cipher.Init(false,keyParamAead);
outputSize = cipher.GetOutputSize(cipherTextData.Length);
plainTextData = new byte[outputSize];
result = cipher.ProcessBytes(cipherTextData, 0, cipherTextData.Length,plainTextData, 0);
cipher.DoFinal(plainTextData, result);
var pln=plainTextData;

Console.WriteLine("=== ChaCha20 Cipher ==");
Console.WriteLine("Message:\t\t{0}",msg);
Console.WriteLine("IV:\t\t\t{0}",iv);
Console.WriteLine("Key:\t\t\t{0} [{1}]",Convert.ToHexString(keyParam.GetKey()),Convert.ToBase64String(keyParam.GetKey()));

Console.WriteLine("Additional data:\t{0}",add);
Console.WriteLine("\nCipher (hex):\t\t{0}",Convert.ToHexString(rtn));
Console.WriteLine("Cipher (Base64):\t{0}",Convert.ToBase64String(rtn));
Console.WriteLine("\nPlain:\t\t\t{0}",System.Text.Encoding.UTF8.GetString(pln));



} catch (Exception e) {
Console.WriteLine("Error: {0}",e.Message);
}
}
}

}

A sample run gives [here]:

=== ChaCha20 Cipher ==
Message: Hello 123
IV: 000102030405060708090A0B
Key: F3E54C5FC8A237FF1673B78FC2203D0B1A456A928F21E40A57422E2D56BF13F6 [8+VMX8iiN/8Wc7ePwiA9CxpFapKPIeQKV0IuLVa/E/Y=]
Additional data: test

Cipher (hex): 3FAA94DAAD2F63728EC87B17537544D4B279F2564FF52FF4A0
Cipher (Base64): P6qU2q0vY3KOyHsXU3VE1LJ58lZP9S/0oA==

Plain: Hello 123

We could notice that the cipher is longer than the plaintext, as we have added in the Poly1305 MAC code. This is used to verify that the cipher has not been changed.

Conclusions

Some people just don’t trust NIST and their standards. Others just want to see an alterative to AES GCM encryption. One thing that is for certain, ChaCha20 is one of the best symmetric key methods around.