With symmetric key, Bob and Alice have the same key. NaCl uses the XChaCha20 method, and which supports stream encryption (and which does not require padding as a block cipher does, and is also faster than block cipher modes). ChaCha20 was created by Daniel J. Bernstein, and has an eight byte or 16 byte nonce. XChaCha20 (eXtended-nonce ChaCha) is an update to ChaCha20, and uses a 24 byte nonce. It has a lower propability of nonce misuse than ChaCha20. The cipher text is made up of the cipher message (and which is the same length of the plaintext message) is the same number of bytes as the message (five bytes), and that the cipher text has an extra 16 bytes (used for AEAD - Authenticated Encryption with Associated Data). The MAC bytes used Poly1305 and provide an integrity check for the cipher. An example of a tag is "e956cf49a523b46f7e9fbfe3fee398bd". We generate this when encrypting, and then use it with the authenication data to prove the decryption process.
ChaCha20/Poly1305 in Rust |
An outline of the Rust code is:
extern crate base64; extern crate hex; extern crate crypto; use crypto::{aead::AeadEncryptor, symmetriccipher::{ SynchronousStreamCipher}}; use rustc_serialize::hex::FromHex; use std::env; use core::str; use std::iter::repeat; fn hex_to_bytes(s: &str) -> Vec{ s.from_hex().unwrap() } fn main() { let mut mykey="0000000000000000000000000000000000000000000000000000000000000000"; let mut msg="Hello123456789"; let mut myiv="0000000000000000"; let mut myadd="Additional data"; let args: Vec<String> = env::args().collect(); if args.len() >1 { msg = args[1].as_str();} if args.len() >2 { mykey = args[2].as_str();} if args.len() >3 { myiv = args[3].as_str();} println!("== ChaCha20/Poly1305 =="); println!("Message: {:?}",msg); println!("Key: {:?}",mykey); println!("IV: {:?}",myiv); println!("Additional data: {:?}",myadd); let key=&hex_to_bytes( mykey)[..]; let iv=&hex_to_bytes( myiv)[..]; let plain=msg.as_bytes(); let aad=myadd.as_bytes(); // Encrypting let mut c = crypto::chacha20poly1305::ChaCha20Poly1305::new(&key, iv, aad); let mut output: Vec = repeat(0).take(plain.len()).collect(); let mut outtag: Vec = repeat(0).take(16).collect(); c.encrypt(&plain[..], &mut output[..],&mut outtag[..]); println!("\nEncrypted: {}",hex::encode(output.clone())); println!("\nTag: {}",hex::encode(outtag.clone())); // Decrypting let mut c = crypto::chacha20poly1305::ChaCha20Poly1305::new(&key, iv,aad); let mut newoutput: Vec = repeat(0).take(output.len()).collect(); c.encrypt(&mut output.clone()[..], &mut newoutput[..],&mut outtag[..]); println!("\nDecrypted: {}",str::from_utf8(&newoutput[..]).unwrap()); }
Finally we simply build with:
cargo build
A sample run is:
== ChaCha20/Poly1305 == Message: "Hello123456789" Key: "0000000000000000000000000000000000000000000000000000000000000000" IV: "0000000000000000" Additional data: "Additional data" Encrypted: d7628bd23a600a49ac8fa14b4b14 Tag: e956cf49a523b46f7e9fbfe3fee398bd Decrypted: Hello123456789