A Rusty Key: At The Core of Cybersecurity is Random Numbers

One of the most fundamental aspects of our online security is the generation of random numbers. These typically generate encryption keys…

Photo by Markus Winkler on Unsplash

A Rusty Key: At The Core of Cybersecurity is Random Numbers

One of the most fundamental aspects of our online security is the generation of random numbers. These typically generate encryption keys, which are so fundamental to our security that any flaws in them can compromise our whole environment. So examples are:

  • Generating wallets. When a new Bitcoin wallet is created, for example, the private key is a random 32 byte (256 bit) value. If this value is not random in any way, it can severely affect the strength of the wallet against attack.
  • Generating session keys. Every time, too, we connect to a Web server, it is the magic of random numbers that allows us to create a new encryption key for the session. And, so, if Eve, manages to crack one of these, the next one will be completely different.
  • Generating encryption keys. If we need to encrypt files, we often need to generate an AES key to encrypt its data. This key should be random, as we do not want Eve using brute force to crack the key.

And, so, the safe generation of random numbers is fundamental to the core of cybersecurity. Also, if we want to use encryption, we possibly want to run it in a safe environment, and Rust is one of the best for this. So, let’s develop a random key generator using Rust. First, we will create a function that generates a 128-bit (16 byte) random key. For this, we generate 16-byte values ([u8; 16]), and where u8 is an 8-bit value [here]:

fn get_random_key16() ->  [u8; 16]{
let mut arr = [0u8; 16];
thread_rng().try_fill(&mut arr[..]).expect("Ooops!");
return arr;
}

This uses ThreadRng and which generates a new seed, and then creates 32MB of random data. Once the data is consumed, another 32MB of random data is created. A reseeding happens to protect against Eve using an entropy leak on the generated key. We then generate the keys with [here]:

use rand::thread_rng;
use rand::Rng;
use hex::{self};
fn get_random_key16() ->  [u8; 16]{
let mut arr = [0u8; 16];
thread_rng().try_fill(&mut arr[..]).expect("Ooops!");
return arr;
}
fn get_random_key32() ->  [u8; 32]{
let mut arr = [0u8; 32];
thread_rng().try_fill(&mut arr[..]).expect("Ooops!");
return arr;
}
fn main() {

    let randkey128=get_random_key16();
let randkey256=get_random_key32();
    println!("\nRandom 128 bit (16 byte) key: {}\n",hex::encode(randkey128));
println!("\nRandom 256 bit (32 byte)key: {}\n",hex::encode(randkey256));
}

and Cargo.toml:

[package]
name = "blake3"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
hex="0.4.2"
rand="0.8.3"

and a sample run:

Random 128 bit (16 byte) key: 7de6d175af301867fabb5617161e4c09


Random 256 bit (32 byte)key: ef1dbc08699d83f4d98e914ed57e6e5c397d67b5d2364ca686bc2995f9ec0fe6

Now, we can go ahead and use these keys to do some encryption, such as using AES with CBC mode. For this, we also need to generate an IV (initialisation vector):

use rand::thread_rng;
use rand::Rng;
use hex::{self};
use std::str;
use std::env;
use aes::Aes128;
use block_modes::{BlockMode, Cbc};
use block_modes::block_padding::Pkcs7;
type Aes128Cbc = Cbc;
fn get_random_key16() ->  [u8; 16]{
let mut arr = [0u8; 16];
thread_rng().try_fill(&mut arr[..]).expect("Ooops!");
return arr;
}
fn get_random_key32() ->  [u8; 32]{
let mut arr = [0u8; 32];
thread_rng().try_fill(&mut arr[..]).expect("Ooops!");
return arr;
}

fn main() {

    let randkey128=get_random_key16();
let randkey256=get_random_key32();
let iv=get_random_key16();
    let mut msg = String::from("Hello world!");
let args: Vec = env::args().collect();
	if args.len() >1 {
		msg = args[1].clone();
}
    println!("\nRandom 128 bit (16 byte) key: {}\n",hex::encode(randkey128));
println!("\nRandom 256 bit (32 byte)key: {}\n",hex::encode(randkey256));
    let plaintext=msg.as_bytes();

    let cipher = Aes128Cbc::new_from_slices(&randkey128, &iv).unwrap();
    let pos = plaintext.len();
let mut buffer = [0u8; 128];

buffer[..pos].copy_from_slice(plaintext);

let ciphertext = cipher.encrypt(&mut buffer, pos).unwrap();
    println!("\nMessage: {}",String::from(msg));
println!("\nCiphertext: {}",hex::encode(ciphertext));


let cipher = Aes128Cbc::new_from_slices(&randkey128, &iv).unwrap();
let mut buf = ciphertext.to_vec();
let decrypted_ciphertext = cipher.decrypt(&mut buf).unwrap();

println!("\nPlaintext: {}",str::from_utf8(decrypted_ciphertext).unwrap());
}

And a sample run:

Random 128 bit (16 byte) key: f7271be9d20ba9b367b542e54d0a05b8


Random 256 bit (32 byte)key: b6e1659040e6f9217bcebe365b9c35d4895d67b0ca989ce84bb64e96253181b3


Message: Hello You

Ciphertext: 08ab5e37560abb148152d55418be7957

Plaintext: Hello You

And, that’s it … how to create random keys. But, remember to test them, to make sure they are random!

Well here is the finished program:

https://asecuritysite.com/rust/rust_key

and some more Rust:

https://asecuritysite.com/rust/