HC-256: A Fast and Secure Software Stream Cipher
HC-256: A Fast and Secure Software Stream Cipher
Why should you just learn about the most common methods? As a researcher, you should never fully dismiss any method, as methods that might not be popular now may come back and be ready to take on new challenges. Also, a method will have been created for a purpose, and reading the paper will show how the authors have addressed the challenge. It’s basically a journey of discovery and will typically add your knowledge.
And, so, I’ve been reading this paper [here]:
The HC-256 method was created in 2004, and uses a 256-bit key (K) and a 256-bit nonce (IV) value. Internally it has two secret tables: P and Q, and where each table has 1,024 32-bit words. Basically, these represent state values, and each change of state will update one of the entries of the table, and which uses a non-linear update function. Thus, after 2,048 state changes, every element of the tables will have been updated. We then derive the final has by taking a SHA-256, but where we use the P and Q tables as S-boxes. Overall, it is a fast-stream cipher with just four CPU cycles per byte.
The basic functions that HC-256 uses are simple and involve either EX-OR, mod, add or bit shift operations:
As we have a stream cipher, we basically take the key and the IV, and expand into a key stream (s). The cipher is then:
c = p ^ s
and where we EX-OR each bit of the plaintext (p) with the bits in the keystream (s), and generate a cipher stream (c ). In order to recover the plaintext, we just EX-OR again with the key stream:
p = c ^ s
Key and IV setup
The initialization phase provides an expansion of the 256-bit key into the P and Q tables. With this, we take the key and the IV, and split them up into eight 32-bit values (K_0 … K_7, and IV_0 … IV_7). Next, we compute W_i and then use these values to fill the P and Q tables:
Keystream expansion
In this stage, we generate the key stream (s). Each step will update one of the entries in either the P table or the Q table:
This will then create the S-box values for the SHA-256 operation. Once generated, the plaintext and cipher stream is just EX-ORed with the expanded key stream.
Coding
The outline code using Rust is [here]:
use hc_256::Hc256;
use rand::thread_rng;
use rand::Rng;
use hc_256::cipher::{KeyIvInit, StreamCipher};
use std::str;
use std::env;
fn get_random_key32() -> [u8; 32]{
let mut arr = [0u8; 32];
thread_rng().try_fill(&mut arr[..]).expect("Ooops!");
return arr;
}
fn main() {
let key = get_random_key32();
let nonce = get_random_key32();
let args: Vec<String> = env::args().collect();
let mut msg="Test";
if args.len() >1 {
msg = args[1].as_str();
}
let message = String::from(msg);
let plaintext=message.as_bytes();
let len = plaintext.len();
let mut buffer = [0u8; 128];
buffer[..len].copy_from_slice(plaintext);
let mut cipher = Hc256::new(&key.into(), &nonce.into());
cipher.apply_keystream(&mut buffer);
println!("== HC256 ==");
println!("Message: {}",message);
println!("Key {}",hex::encode(&key));
println!("Nonce {}",hex::encode(&nonce));
println!("\nEncrypted: {}",hex::encode(&buffer[0..len]));
let mut cipher = Hc256::new(&key.into(), &nonce.into());
cipher.apply_keystream(&mut buffer);
println!("\nCiphertext: {:?}",str::from_utf8(&buffer[0..len]).unwrap());
}
and Cargo.toml [here]:
[package]
name = "hc256"
version = "0.1.0"
edition = "2021"
[dependencies]
hc-256 = "0.5.0"
hex="0.4.3"
hex-literal="0.3.3"
rand="0.8.3"
A test run is [here]:
== HC256 ==
Message: Hello
Key e01c659e77c0ef0b91abb3cd9b1e6172a0854b8417a2c7b36b999ee6d19f76cf
Nonce 0811c359c9498ff389960d0de31d2bf30a504c219862a028167197cdbf347767
Encrypted: cd896cd27a
Ciphertext: "Hello"
Conclusions
HC-256 is a great example of a fast and secure cipher. If you have time, please read more [here] and you can discover the practical implementation here: