-
Notifications
You must be signed in to change notification settings - Fork 0
ChaCha20
It is a refinement of the Salsa20 algorithm, and uses a 256-bit key. I do recommend it as a more secure variant over Salsa20.
- Key - secret key/passphrase using 256-bit
🔑 Secret field. The original algorithm also specified 128-bit keys.
- Nonce - a unique non-repeating number
📢 Public field. Bitness depends on the cipher variant. Does not need to be random, can be sequential.
- Counter - identifies a block to encipher/decipher (random access)
📢 Public field. Bitness depends on the cipher variant.
- Rounds - tradeoff between security and speed
📢 Public field. (recommended tradeoffs: 8 = speed, 12 = balanced, 20 = security). Implementation can handle 2^32.
Currently there are three variants of ChaCha20 (as of 2020)
-
ChaCha20 (256-bit key, 64-bit nonce, 64-bit counter)
🛈 First original version released by D. J. Bernstein (implemented)
-
IETF ChaCha20 (256-bit key, 96-bit nonce, 32-bit counter)
🛈 IETF slightly tweaked version as RFC 7539 for networking (implemented)
-
XChaCha20 (256-bit key, 192-bit nonce, 64-bit counter)
🛈 Another version released after original by D. J. Bernstein
Encryption (ChaCha20 using RFC 7539)
// Multiple ways to initialize ChaCha.Create("ChaCha12") or new ChaCha8
using(var chacha = SymmetricAlgorithm.Create("ChaCha20Rfc7539"))
{
using(var ms = new MemoryStream())
using(var cse = new CryptoStream(ms, chacha.CreateEncryptor(myKey, myNonce), CryptoStreamMode.Write))
{
byte[] data = Encoding.UTF8.GetBytes("SecretMessage");
cse.Write(data, 0, data.Length);
// Make sure to flush any remaining buffer content
// alternatively call Close()
if(!cse.HasFlushedFinalBlock)
cse.FlushFinalBlock();
byte[] encryptedData = ms.ToArray();
}
}Decryption (ChaCha20 original paper)
using(var chacha = new ChaCha20())
{
using(var ms = new MemoryStream())
using(var csd = new CryptoStream(ms, chacha.CreateDecryptor(myKey, myNonce), CryptoStreamMode.Read))
{
byte[] encryptedData = ...;
csd.Read(encryptedData, 0, encryptedData.Length);
// Make sure to flush any remaining buffer content
// alternatively call Close()
if(!csd.HasFlushedFinalBlock)
csd.FlushFinalBlock();
byte[] originalData = ms.ToArray();
}
}Multiple ways to initialize
// Creating object directly
ChaCha8 chacha = new ChaCha8();
// Calling base class Create method (only chacha family)
ChaCha chacha = ChaCha.Create("ChaCha12");
// Using SymmetricAlgorithm.Create (any symmetric alg.)
SymmetricAlgorithm chacha = SymmetricAlgorithm.Create("ChaCha8Rfc7539");- Always try to use non-predictable randomly chosen key to improve security
- Remember that (key, nonce) pair must be unique; same nonce cannot be reused with same key and vice versa
- The nonce is short and thus generating it randomly can create possible collisions. It is recommended to increment the previous nonce instead of generating a random nonce every time a new stream is required. (general rule: 128-bit numbers and higher have very low to non-existent collision chance. Example)
- A single given pair of a (key, nonce) allows to safely de/encrypt only up to 256GB and 1ZiB (2^70 bytes) for IETF ChaCha20 and Original ChaCha20 respectively.
- Salsa20 may be slightly faster on some platforms due to different core function.
- Encrypted ciphertext has same length as plaintext; (use it as advantage to pre-allocate buffers in advance, some other algorithms may require you padding the output)