In cryptography AES is a titan of an algorithm, standing for Advanced Encryption Standard, it
despite being made over 20 years ago is still the go to algorithm, used as a foundational
piece in modern quantum resistant communications. In fact, it might be fair to say that
AES-256 (A 256 bit key) is inherently quantum resistant, despite not being made for that
purpose. I decided to make my own implementation of the algorithm following the FIPS 197
specification in Rust. Rather than using hardware AES instructions, by targeting compilation
systems, and calling assembly directly I wanted to follow the pseudocode more directly. The
project focused on idiomatic Rust, high performance, and keeping to the algorithm as described
in the document. The program is a CLI tool that uses I/O from the file system (i.e. hard
drive/ssd), processes it, and writes the encrypted or decrypted output. Since file I/O tends
to be the main performance bottleneck, multithreading can only do so much. Despite this, I
implemented a system that allows files to be prefetched and loaded while computation is being
done on other files. This overlap between computation and I/O helps maximize performance
within hardware limits, trying to optimize around the I/O bottleneck. It also involved
structuring the code in a clean, modular way using idiomatic Rust features like iterators and
staying within Rust ownership principles. Overall, this project focused on making a product
simply from a simple document specification, and performance tuning.
Here is a multithreaded file reader that allows prefetching of files, and calls the function
for the computation and reading in files.
for i in 0..2 {
thread::scope(|s| {
s.spawn(|| {
for j in 0..((num_files + (1 - i)) / 2) {
let curr_file = fs::read(&files[i + 2 * j]);
let mut curr_file = curr_file.unwrap();
/* Do decryption/encryption based on user input */
match (args.reverse, use_iv) {
(false, false) => data_encrypt(&mut curr_file, &expanded_key),
(false, true) => data_encrypt_iv(&mut curr_file, &expanded_key, &iv),
(true, false) => data_decrypt(&mut curr_file, &expanded_key),
(true, true) => data_decrypt_iv(&mut curr_file, &expanded_key, &iv),
};
let _ = fs::write(
files[i + 2 * j].to_owned() + enc_or_dec,
&curr_file[0..curr_file.len()],
);
}
});
});