ChaCha20 and Rust

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

Photo by Sixteen Miles Out on Unsplash

ChaCha20 and Rust

Which encryption method just needs an EX-OR function to encrypt? 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 32-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. Here is my testing page for ChaCha:

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}

An outline of the Rust code is [here]:

extern crate base64;
extern crate hex;
extern crate crypto;
use crypto::{symmetriccipher::{ SynchronousStreamCipher}};
use rustc_serialize::hex::FromHex;
use std::env;
use core::str;
use std::iter::repeat;
fn hex_to_bytes(s: &str) -> Vec<u8> {
s.from_hex().unwrap()
}
fn main() {
     
let mut mykey="0000000000000000000000000000000000000000000000000000000000000000";
let mut msg="Hello";

    let mut myiv="000000000000000000000000";
    let args: Vec = 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 ==");
println!("Message: {:?}",msg);
println!("Key: {:?}",mykey);
println!("IV: {:?}",myiv);

 
let key=&hex_to_bytes( mykey)[..];
let iv=&hex_to_bytes( myiv)[..];
let plain=msg.as_bytes();

// Encrypting
let mut c = crypto::chacha20::ChaCha20::new(&key, iv);
let mut output: Vec = repeat(0).take(plain.len()).collect();
c.process(&plain[..], &mut output[..]);
println!("\nEncrypted: {}",hex::encode(output.clone()));
// Decrypting
let mut c = crypto::chacha20::ChaCha20::new(&key, iv);
let mut newoutput: Vec = repeat(0).take(output.len()).collect();
c.process(&mut output[..], &mut newoutput[..]);
println!("\nDecrypted: {}",str::from_utf8(&newoutput[..]).unwrap());
}

Finally we simply build with:

cargo build

A sample run is [here]:

== ChaCha20 ==
Message: "Hello"
Key: "0000000000000000000000000000000000000000000000000000000000000000"
IV: "000000000000000000000000"
Encrypted: 3edd8cc1cf
Decrypted: Hello

Conclusions

It took me a couple of hours to get this cipher to work in Rust. I eventually added some test vectors, and managed to find the problem. What I love about crypto, is the reveal of the correct answer, and my “Hello” revealed itself as being decrypted. Here is the code:

https://asecuritysite.com/rust/rust_chacha20