This is Challenge 8 of Cryptopals challenges implemented in Rust language.
Context
We're given a file which lists a bunch of hex-encoded ciphertexts. One of these texts is encrypted with AES-128 in ECB mode. We have to detect which one is it. I recommend to see Challenge 7 if you haven't yet.
Remember that AES-128 divides message into 16 byte blocks before encrypting. In ECB mode each block is encrypted seperately. Therefore - the same 16 byte plaintext block will always produce the same 16 byte ciphertext. We'll exploit this property of ECB mode.
Given the ciphertext, the more number of identical 16-byte blocks, the higher the probability of it having encrypted in ECB mode. Because that means (most probably) the text message contained some identical phrases/blocks that were repeated. And these repeated phrases/blocks encrypted to exactly same ciphertext because of nature of ECB.
...and there was yellow submarine...yellow submarine sank in...
|------ECB-----| |------ECB-----|
...a733hj32hbczxsbv...a733hj32hbczxsbv....
Code
In code we basically loop through each hex string. Convert it to bytes then divide these bytes into 16-byte blocks. Then count number of identical blocks among these. The hex-string that corresponds to max number of identical blocks is encrypted in ECB mode.
use hex;
use std::collections::HashSet;
use std::fs::File;
use std::io::{BufRead, BufReader};
pub fn detect_aes_ecb_encryption(path: &str) -> (usize, usize) {
let file = File::open(path).expect("Error reading file!");
let lines = BufReader::new(file).lines();
let mut i_line: usize = 0;
let mut max_identical_blocks: usize = 0;
let mut n_identical_blocks: usize;
for (i, line) in lines.enumerate() {
let hex = line.unwrap();
// Hex line to bytes vec
let bytes = hex::decode(hex).unwrap();
// Divide bytes into 16 byte blocks (&[u8] blocks)
let blocks: Vec<_> = bytes.chunks_exact(16).collect();
// Get unique blocks
let unique_blocks: HashSet<_> = blocks.iter().cloned().collect();
// No. of identical blocks detected
n_identical_blocks = blocks.len() - unique_blocks.len();
// Cipher containing most identical blocks is more likely to be
// ECB mode encrypted
if n_identical_blocks > max_identical_blocks {
max_identical_blocks = n_identical_blocks;
i_line = i;
}
}
(i_line, max_identical_blocks)
}
And this is it. We've concluded Set 1.
See code on Github
Find me on:
Twitter - @heyNvN
Top comments (0)