diff --git a/src/bytes.rs b/src/bytes.rs index 3dd6f22..95bae9f 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -45,19 +45,16 @@ impl Bytes { } pub fn from_hex(s: &str) -> Bytes { - if s.len() % 2 != 0 { - panic!("Input string has uneven number of characters"); - } - + assert!( + s.len() % 2 == 0, + "Input string has uneven number of characters" + ); let bytes_result: Result, std::num::ParseIntError> = (0..s.len()) .step_by(2) .map(|i| u8::from_str_radix(&s[i..i + 2], 16)) .collect(); - match bytes_result { - Ok(b) => Bytes(b), - Err(_) => panic!("Could not convert all digit pairs to hex."), - } + Bytes(bytes_result.expect("Invalid hex string")) } pub fn to_hex(&self) -> String { @@ -84,12 +81,9 @@ impl Bytes { let mut r = 0; for &c in v.iter() { match c { - 32 => r += 2, - 33..=64 => r += 1, - 65..=90 => r += 3, - 91..=96 => r += 1, - 97..=122 => r += 3, - 123..=127 => r += 1, + b'!'..=b'@' | b'['..=b'`' | b'{'..=b'~' => r += 1, + b' ' => r += 2, + b'A'..=b'Z' | b'a'..=b'z' => r += 3, _ => (), } } @@ -108,7 +102,9 @@ impl Bytes { pub fn pad_pkcs7(&mut self, block_size: usize) { let Bytes(v) = self; - let padding_value = (block_size - v.len() % block_size) as u8; + let padding_value = (block_size - v.len() % block_size) + .try_into() + .expect("Padding value has to be an u8"); for _ in 0..padding_value { v.push(padding_value); } @@ -180,7 +176,6 @@ impl Bytes { false } - #[allow(dead_code)] pub fn hemming(Bytes(a): &Bytes, Bytes(b): &Bytes) -> u32 { let v: Vec = Iterator::zip(a.iter(), b.iter()) .map(|z| (*(z.0) ^ *(z.1)).count_ones()) diff --git a/src/bytes_base64.rs b/src/bytes_base64.rs index 6170275..c40693b 100644 --- a/src/bytes_base64.rs +++ b/src/bytes_base64.rs @@ -43,10 +43,10 @@ impl BytesBase64 { v.push(0); } let mut result = vec![ - (v[0] & 0b11111100) >> 2, - (v[0] & 0b00000011) << 4 | (v[1] & 0b11110000) >> 4, - (v[1] & 0b00001111) << 2 | (v[2] & 0b11000000) >> 6, - (v[2] & 0b00111111), + (v[0] & 0b1111_1100) >> 2, + (v[0] & 0b0000_0011) << 4 | (v[1] & 0b1111_0000) >> 4, + (v[1] & 0b0000_1111) << 2 | (v[2] & 0b1100_0000) >> 6, + (v[2] & 0b0011_1111), ]; // removed padded bytes for _ in c.len()..3 { @@ -58,7 +58,6 @@ impl BytesBase64 { } pub fn to_bytes(&self) -> Bytes { - let BytesBase64(v) = self; fn to_bytes(c: &[u8]) -> Vec { let mut v = c.to_vec(); // pad with bytes for conversion @@ -66,9 +65,9 @@ impl BytesBase64 { v.push(0); } let mut result: Vec = vec![ - ((v[0] & 0b00111111) << 2) | ((v[1] & 0b00110000) >> 4), - ((v[1] & 0b00001111) << 4) | ((v[2] & 0b00111100) >> 2), - ((v[2] & 0b00000011) << 6) | (v[3] & 0b00111111), + ((v[0] & 0b0011_1111) << 2) | ((v[1] & 0b0011_0000) >> 4), + ((v[1] & 0b0000_1111) << 4) | ((v[2] & 0b0011_1100) >> 2), + ((v[2] & 0b0000_0011) << 6) | (v[3] & 0b0011_1111), ]; // removed padded bytes for _ in c.len()..4 { @@ -76,6 +75,7 @@ impl BytesBase64 { } result } + let BytesBase64(v) = self; Bytes(v.chunks(4).flat_map(to_bytes).collect()) } @@ -88,9 +88,7 @@ impl BytesBase64 { '0'..='9' => r.push((c as u8) - b'0' + 52), '+' => r.push(62), '/' => r.push(63), - '\n' => (), - '=' => (), - ' ' => (), + '\n' | '=' | ' ' => (), _ => { return Err(format!("Unexpected character '{}'", c)); } diff --git a/src/cbc.rs b/src/cbc.rs index 9311e54..b8a85f1 100644 --- a/src/cbc.rs +++ b/src/cbc.rs @@ -27,11 +27,11 @@ pub fn decrypt_aes_128_ecb_block(key: &[u8], data: &[u8]) -> Vec { pub fn encrypt(Bytes(key): &Bytes, Bytes(iv): &Bytes, Bytes(data): &Bytes) -> Bytes { let block_size = 16; let mut result: Vec = vec![]; - let mut prev_cipher: Vec = iv.to_vec(); // first xor input is IV + let mut prev_cipher: Vec = iv.clone(); // first xor input is IV for data in data.chunks(block_size) { let xored = crate::utils::xor(&prev_cipher, data); let mut cipher = enrypt_aes_128_ecb_block(key, &xored); - prev_cipher = cipher.to_vec(); // cipher is input for next xor + prev_cipher = cipher.clone(); // cipher is input for next xor result.append(&mut cipher); } Bytes(result) @@ -42,11 +42,11 @@ pub fn decrypt(Bytes(key): &Bytes, Bytes(iv): &Bytes, Bytes(data): &Bytes) -> By let cipher_type = symm::Cipher::aes_128_ecb(); let block_size = cipher_type.block_size(); let mut result: Vec = vec![]; - let mut prev_cipher: Vec = iv.to_vec(); // first xor input is IV + let mut prev_cipher: Vec = iv.clone(); // first xor input is IV for cipher in data.chunks(block_size) { let xored = decrypt_aes_128_ecb_block(key, cipher); let data = crate::utils::xor(&xored, &prev_cipher); - result.extend(data.to_vec()); + result.extend(data.clone()); prev_cipher = cipher.to_vec(); } Bytes(result) diff --git a/src/main.rs b/src/main.rs index 870fd41..4657ce5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -47,8 +47,6 @@ fn main() { set4::challenge28(); set4::challenge29(); set4::challenge30(); - set4::challenge31(); - } else { - set4::challenge31(); } + set4::challenge31(); } diff --git a/src/md4.rs b/src/md4.rs index b50e0d7..a993b21 100644 --- a/src/md4.rs +++ b/src/md4.rs @@ -30,8 +30,7 @@ impl Md4Core { while (buffer.len() + padding.len()) % BLOCK_BYTES != (BLOCK_BYTES - 8) { padding.push(0x0); } - padding.append(&mut (bit_len as u32).to_le_bytes().to_vec()); - padding.append(&mut ((bit_len >> 32) as u32).to_le_bytes().to_vec()); + padding.append(&mut bit_len.to_le_bytes().to_vec()); padding } @@ -141,8 +140,8 @@ pub fn hash(bytes: &Bytes) -> Bytes { pub fn authenticate(message: &Bytes, key: &Bytes) -> Bytes { let mut c = vec![]; - c.append(&mut key.0.to_vec()); - c.append(&mut message.0.to_vec()); + c.append(&mut key.0.clone()); + c.append(&mut message.0.clone()); hash(&Bytes(c)) } diff --git a/src/mt19937.rs b/src/mt19937.rs index 5ad5860..5d9c1b6 100644 --- a/src/mt19937.rs +++ b/src/mt19937.rs @@ -24,7 +24,7 @@ impl MT19937 { } pub fn seed(&mut self, seed: u32) { - const F: u32 = 1812433253; + const F: u32 = 1_812_433_253; self.mt[0] = seed; for i in 1..N { self.mt[i] = (Wrapping(F) * Wrapping(self.mt[i - 1] ^ (self.mt[i - 1] >> 30)) @@ -49,9 +49,9 @@ impl MT19937 { const S: u32 = 7; const T: u32 = 15; const U: u32 = 11; - const B: u32 = 0x9D2C5680; - const C: u32 = 0xEFC60000; - const D: u32 = 0xFFFFFFFF; + const B: u32 = 0x9D2C_5680; + const C: u32 = 0xEFC6_0000; + const D: u32 = 0xFFFF_FFFF; const L: u32 = 18; let mut y = self.mt[self.index]; diff --git a/src/mtcipher.rs b/src/mtcipher.rs index b11cdac..ad113c5 100644 --- a/src/mtcipher.rs +++ b/src/mtcipher.rs @@ -11,7 +11,7 @@ pub fn encrypt(key: u16, Bytes(data): &Bytes) -> Bytes { // Write the function that does this for MT19937 using a 16-bit seed. let mut mt = mt19937::MT19937::new(); - mt.seed(key as u32); + mt.seed(key.into()); let mut result: Vec = vec![]; for chunk in data.chunks(4) { diff --git a/src/parser.rs b/src/parser.rs index 564902b..5acef98 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -33,7 +33,7 @@ fn scan(code: &str, mut ix: usize, mut tokens: Tokens) -> Tokens { return tokens; } - let c: char = code[ix..ix + 1].chars().next().unwrap(); + let c: char = code[ix..].chars().next().unwrap(); if c.is_ascii_alphanumeric() || SPECIAL_CHARS.contains(&c) { return scan_identifier(code, ix, tokens); } diff --git a/src/set1.rs b/src/set1.rs index c445e22..a314f37 100644 --- a/src/set1.rs +++ b/src/set1.rs @@ -60,7 +60,7 @@ pub fn challenge5() { if enc == exp { println!("[okay] Challenge 5: {}", enc.to_hex()); } else { - println!("[fail] Challenge 5") + println!("[fail] Challenge 5"); } } @@ -72,7 +72,7 @@ pub fn challenge6() { for e in Iterator::zip(bytes.as_bytes().iter(), 0..bytes.len()) { if e.1 % width == 0 && e.1 > 0 { - output_vec.push(b'\n') + output_vec.push(b'\n'); } output_vec.push(*e.0); } @@ -167,13 +167,8 @@ pub fn challenge8() { let index = ratings.iter().position(|e| e == min_rating).unwrap(); let average = ratings.iter().sum::() as f32 / ratings.len() as f32; let partial_cipher = bytes_vector[index].to_hex()[..10].to_string(); - if index != expected_index { - panic!("Regression in challenge 8."); - } - println!( - "[okay] Challenge 8: Cipher {} [{}...] with rating {} (average = {}) is the solution.", - index, partial_cipher, min_rating, average - ); + assert!(index == expected_index, "Regression in challenge 8."); + println!("[okay] Challenge 8: Cipher {index} [{partial_cipher}...] with rating {min_rating} (average = {average}) is the solution."); // More elegant solution. let bytes_vector = utils::read_hex_lines("data/8.txt"); diff --git a/src/set2.rs b/src/set2.rs index 627ea2e..521cdec 100644 --- a/src/set2.rs +++ b/src/set2.rs @@ -50,7 +50,7 @@ pub fn challenge11() { let key = Bytes::random(16); // Under the hood, have the function append 5-10 bytes (count chosen randomly) // before the plaintext and 5-10 bytes after the plaintext. - let padded_data = pad_data(data.to_vec()); + let padded_data = pad_data(data.clone()); // Now, have the function choose to encrypt under ECB 1/2 the time, and under CBC // the other half (just use random IVs each time for CBC). Use rand(2) to decide // which to use. @@ -103,7 +103,7 @@ pub fn challenge12() { fn encryption_oracle(key: &Bytes, Bytes(data): &Bytes) -> Bytes { // Copy your oracle function to a new function that encrypts buffers under ECB mode using a consistent but unknown key // Now take that same function and have it append to the plaintext, BEFORE ENCRYPTING, the following string (from 12.txt): - let mut data = data.to_vec(); + let mut data = data.clone(); let mut string = utils::read_base64("data/12.txt"); data.append(&mut string.0); ecb::encrypt(key, &Bytes(data)) @@ -112,11 +112,11 @@ pub fn challenge12() { fn get_block_size(key: &Bytes) -> usize { // Detect cipher block size let mut v = vec![]; - let initial_cipher_len = encryption_oracle(key, &Bytes(v.to_vec())).0.len(); + let initial_cipher_len = encryption_oracle(key, &Bytes(v.clone())).0.len(); let mut new_cipher_len = initial_cipher_len; while initial_cipher_len == new_cipher_len { v.push(b'A'); - let cipher = encryption_oracle(key, &Bytes(v.to_vec())); + let cipher = encryption_oracle(key, &Bytes(v.clone())); new_cipher_len = cipher.0.len(); } new_cipher_len - initial_cipher_len @@ -137,20 +137,20 @@ pub fn challenge12() { let mut cleartext_block = vec![]; for padding_length in (0..block_size).rev() { let padding_text = vec![b'-'; padding_length]; - let expected = encryption_oracle(key, &Bytes(padding_text.to_vec())); + let expected = encryption_oracle(key, &Bytes(padding_text.clone())); let expected_block = expected.get_block(block_index, block_size); let mut known_text = if block_index == 0 { - padding_text.to_vec() + padding_text.clone() } else { let cleartext_offset = ((block_index - 1) * block_size) + (block_size - padding_length); cleartext[cleartext_offset..(cleartext_offset + padding_length)].to_vec() }; - known_text.append(&mut cleartext_block.to_vec()); + known_text.append(&mut cleartext_block.clone()); for i in 0..255 { - let mut guess_text = known_text.to_vec(); + let mut guess_text = known_text.clone(); guess_text.push(i); let cipher_block = encryption_oracle(key, &Bytes(guess_text)).get_block(0, block_size); @@ -183,9 +183,11 @@ pub fn challenge13() { fn profile_for(input: &str, key: &Bytes) -> Bytes { let mut r = String::new(); for c in input.chars() { - if !(c.is_ascii_alphabetic() || c == '.' || c == '@') { - panic!("profile_for: invalid char {}", c); - } + assert!( + c.is_ascii_alphabetic() || c == '.' || c == '@', + "profile_for: invalid char {}", + c + ); } r.push_str("email="); r.push_str(input); @@ -246,8 +248,8 @@ pub fn challenge14() { // know how to decode it because I cannot really run experiments. If I generate // a single random prefix it becomes rather trivial. I just have to find out how // long it is and then adjust the decoding routine. - let mut plaintext = random_prefix.to_vec(); - plaintext.append(&mut attacker_controlled.to_vec()); + let mut plaintext = random_prefix.clone(); + plaintext.append(&mut attacker_controlled.clone()); let mut target_bytes = utils::read_base64("data/12.txt").0; plaintext.append(&mut target_bytes); ecb::encrypt(random_key, &Bytes(plaintext)) @@ -285,7 +287,7 @@ pub fn challenge14() { for i in 0..block_size { let mut padding = vec![b'a'; i]; - padding.append(&mut duplicated_text.to_vec()); + padding.append(&mut duplicated_text.clone()); let cipher = encryption_oracle(prefix, key, &Bytes(padding)); if let Some((first_block, _)) = get_duplicated_block_indices(&cipher, block_size) { return block_size * first_block - i; @@ -313,11 +315,11 @@ pub fn challenge14() { let mut cleartext_block = vec![]; for padding_length in (0..block_size).rev() { let full_padding_text = vec![b'-'; prefix_padding_size + padding_length]; - let expected = encryption_oracle(prefix, key, &Bytes(full_padding_text.to_vec())); + let expected = encryption_oracle(prefix, key, &Bytes(full_padding_text.clone())); let expected_block = expected.get_block(block_index, block_size); let mut known_text = if block_index == first_block_index { - full_padding_text.to_vec() + full_padding_text.clone() } else { let mut prefix_padding = vec![b'-'; prefix_padding_size]; let cleartext_offset = ((block_index - first_block_index - 1) * block_size) @@ -328,10 +330,10 @@ pub fn challenge14() { ); prefix_padding }; - known_text.append(&mut cleartext_block.to_vec()); + known_text.append(&mut cleartext_block.clone()); for i in 0..255 { - let mut guess_text = known_text.to_vec(); + let mut guess_text = known_text.clone(); guess_text.push(i); let cipher_block = encryption_oracle(prefix, key, &Bytes(guess_text)) .get_block(first_block_index, block_size); @@ -373,9 +375,7 @@ pub fn challenge16() { fn encrypt(input: &str, key: &Bytes, iv: &Bytes) -> Bytes { let mut r = String::new(); for c in input.chars() { - if c == ';' || c == '=' { - panic!("encrypt: invalid char {}", c); - } + assert!(c != ';' && c != '=', "encrypt: invalid char {}", c); } r.push_str("comment1=cooking%20MCs;userdata="); r.push_str(input); diff --git a/src/set3.rs b/src/set3.rs index ffe00b0..4fdb4c0 100644 --- a/src/set3.rs +++ b/src/set3.rs @@ -16,7 +16,7 @@ pub fn challenge17() { // The first function should select at random one of the ten strings let cleartexts = utils::read_base64_lines("data/17.txt"); let index: usize = rand::thread_rng().gen_range(0..cleartexts.len()); - let mut cleartext = Bytes(cleartexts[index].0.to_vec()); + let mut cleartext = Bytes(cleartexts[index].0.clone()); // pad the string out to the 16-byte AES block size and cleartext.pad_pkcs7(16); @@ -39,22 +39,29 @@ pub fn challenge17() { let attack_block = |previous_block: &Bytes, cipher_block: &Bytes| -> Bytes { // Good explanation: https://robertheaton.com/2013/07/29/padding-oracle-attack/ - let block_size = cipher_block.len(); - let mut attack_vector = Bytes::random(block_size); + let block_size: u8 = cipher_block + .len() + .try_into() + .expect("block size should be less than 255"); + let mut attack_vector = Bytes::random(block_size.into()); let mut intermittent_result = vec![]; - for pad_byte in 1..=block_size { + for pad_byte in 1_u8..=block_size { // preset attack vector so that paddinig is [1], [2, 2], [3, 3, 3], and so on. - attack_vector.0[block_size - pad_byte] = pad_byte as u8; - for (i, intermittent_byte) in intermittent_result.iter().enumerate().take(pad_byte - 1) + let pad_byte_index: usize = (block_size - pad_byte).into(); + attack_vector.0[pad_byte_index] = pad_byte; + for (i, intermittent_byte) in intermittent_result + .iter() + .enumerate() + .take(pad_byte as usize - 1) { - attack_vector.0[block_size - 1 - i] = (pad_byte as u8) ^ intermittent_byte; + attack_vector.0[block_size as usize - 1 - i] = (pad_byte as u8) ^ intermittent_byte; } // guess attack vector so that padding is valid let guess_index = block_size - pad_byte; for guess in 0..=255 { - attack_vector.0[guess_index] = guess; + attack_vector.0[guess_index as usize] = guess; if decryption_oracle(&attack_vector, cipher_block) { // println!("{guess:#016b}"); let c = (guess as u8) ^ (pad_byte as u8); @@ -68,7 +75,7 @@ pub fn challenge17() { let xored: Vec = Iterator::zip(previous_block.0.iter(), intermittent_result) .map(|z| z.0 ^ z.1) .collect(); - assert_eq!(xored.len(), block_size); + assert_eq!(xored.len(), block_size.into()); Bytes(xored) }; @@ -88,7 +95,7 @@ pub fn challenge17() { } roundtrip.remove_pkcs7(16); let cleartexts = utils::read_base64_lines("data/17.txt"); - let cleartext = Bytes(cleartexts[cleartext_index].0.to_vec()); + let cleartext = Bytes(cleartexts[cleartext_index].0.clone()); assert_eq!(roundtrip, cleartext); println!("[okay] Challenge 17: {}", roundtrip.to_utf8()); } @@ -96,9 +103,10 @@ pub fn challenge17() { pub fn challenge18() { let key = Bytes::from_utf8("YELLOW SUBMARINE"); + let nonce = 1337; let cleartext = Bytes::from_utf8("Let's see if we can get the party started hard my friends."); - let cipher = ctr::encrypt(&key, 42351234, &cleartext); - let roundtrip = ctr::decrypt(&key, 42351234, &cipher); + let cipher = ctr::encrypt(&key, nonce, &cleartext); + let roundtrip = ctr::decrypt(&key, nonce, &cipher); assert_eq!(cleartext, roundtrip); let cipher = BytesBase64::from_base64( @@ -110,7 +118,7 @@ pub fn challenge18() { println!("[okay] Challenge 18: {cleartext}"); } -pub fn challenge19() { +fn challenge19_attack(ciphers: &[Bytes]) -> Vec>> { fn xor_to_char_set(letters: &Vec) -> HashMap>> { let mut h = HashMap::new(); for i in 0..255_u8 { @@ -144,83 +152,83 @@ pub fn challenge19() { letters } - fn attack(ciphers: &[Bytes]) -> Vec>> { - let ciphers_len = ciphers.len(); - let deciphered = vec![RefCell::new(vec![]); ciphers_len]; - let max_cipher_len = ciphers.iter().map(Bytes::len).max().unwrap_or(0); + let ciphers_len = ciphers.len(); + let deciphered = vec![RefCell::new(vec![]); ciphers_len]; + let max_cipher_len = ciphers.iter().map(Bytes::len).max().unwrap_or(0); - for byte_index in 0..max_cipher_len { - let letters = match byte_index { - // chars that work for 10 and 20 found via trial and error - 10 => ascii_letters(" _-.,;:'"), - 20 => ascii_letters(" _-.,;:?"), - _ => ascii_letters(" _-.,;:"), - }; - let lookup = xor_to_char_set(&letters); + for byte_index in 0..max_cipher_len { + let letters = match byte_index { + // chars that work for 10 and 20 found via trial and error + 10 => ascii_letters(" _-.,;:'"), + 20 => ascii_letters(" _-.,;:?"), + _ => ascii_letters(" _-.,;:"), + }; + let lookup = xor_to_char_set(&letters); - let target_bytes: Vec> = ciphers - .iter() - .map(|c| { - if c.len() > byte_index { - Some(c.0[byte_index]) - } else { - None - } - }) - .collect(); - let mut possible_chars: Vec> = ciphers - .iter() - .map(|_| letters.iter().cloned().collect()) - .collect(); - - for i in 0..ciphers_len { - for j in i..ciphers_len { - if target_bytes[i] == None || target_bytes[j] == None { - continue; - } - let xored = target_bytes[i].unwrap() ^ target_bytes[j].unwrap(); - let chars = lookup.get(&xored).unwrap().borrow(); - possible_chars[i] = possible_chars[i].intersection(&chars).copied().collect(); - possible_chars[j] = possible_chars[j].intersection(&chars).copied().collect(); + let target_bytes: Vec> = ciphers + .iter() + .map(|c| { + if c.len() > byte_index { + Some(c.0[byte_index]) + } else { + None } - } + }) + .collect(); + let mut possible_chars: Vec> = ciphers + .iter() + .map(|_| letters.iter().copied().collect()) + .collect(); - for cipher_index in 0..ciphers_len { - if ciphers[cipher_index].len() <= byte_index { + for i in 0..ciphers_len { + for j in i..ciphers_len { + if target_bytes[i] == None || target_bytes[j] == None { continue; } - let chars: Vec = possible_chars[cipher_index].iter().cloned().collect(); - match chars.len() { - 0 => { - // println!("No chars for {cipher_index} {byte_index}"); - deciphered[cipher_index].borrow_mut().push(b'?'); - } - 1 => { + let xored = target_bytes[i].unwrap() ^ target_bytes[j].unwrap(); + let chars = lookup.get(&xored).unwrap().borrow(); + possible_chars[i] = possible_chars[i].intersection(&chars).copied().collect(); + possible_chars[j] = possible_chars[j].intersection(&chars).copied().collect(); + } + } + + for cipher_index in 0..ciphers_len { + if ciphers[cipher_index].len() <= byte_index { + continue; + } + let chars: Vec = possible_chars[cipher_index].iter().copied().collect(); + match chars.len() { + 0 => { + // println!("No chars for {cipher_index} {byte_index}"); + deciphered[cipher_index].borrow_mut().push(b'?'); + } + 1 => { + deciphered[cipher_index] + .borrow_mut() + .push(u8_lower(chars[0])); + } + 2 => { + if u8_lower(chars[0]) == u8_lower(chars[1]) { deciphered[cipher_index] .borrow_mut() .push(u8_lower(chars[0])); - } - 2 => { - if u8_lower(chars[0]) == u8_lower(chars[1]) { - deciphered[cipher_index] - .borrow_mut() - .push(u8_lower(chars[0])); - } else { - // println!("Two {chars:?} {cipher_index} {byte_index}"); - deciphered[cipher_index].borrow_mut().push(b'^'); - } - } - _ => { + } else { // println!("Two {chars:?} {cipher_index} {byte_index}"); deciphered[cipher_index].borrow_mut().push(b'^'); } } + _ => { + // println!("Two {chars:?} {cipher_index} {byte_index}"); + deciphered[cipher_index].borrow_mut().push(b'^'); + } } } - - deciphered } + deciphered +} + +pub fn challenge19() { fn manual(decrypts: &[RefCell>]) { // Add manually guessed letters decrypts[0].borrow_mut()[30] = b'y'; @@ -244,15 +252,15 @@ pub fn challenge19() { let key = Bytes::from_utf8("YELLOW SUBMARINE"); let encrypt = |plaintext: &Bytes| -> Bytes { ctr::encrypt(&key, 0, plaintext) }; let ciphers: Vec = plaintexts.iter().map(encrypt).collect(); - let decrypts = attack(&ciphers); + let decrypts = challenge19_attack(&ciphers); manual(&decrypts); let first_line = Bytes(decrypts[0].borrow().to_vec()).to_utf8(); println!("[okay] Challenge 19: {first_line}"); } pub fn challenge20() { - fn attack(ciphers: Vec) -> Vec { - let min_cipher_len = ciphers.iter().map(|c| c.len()).min().unwrap_or(0); + fn attack(ciphers: &[Bytes]) -> Vec { + let min_cipher_len = ciphers.iter().map(Bytes::len).min().unwrap_or(0); let mut key: Vec = vec![]; for byte_index in 0..min_cipher_len { let bytes = Bytes(ciphers.iter().map(|c| c.0[byte_index]).collect()); @@ -270,7 +278,7 @@ pub fn challenge20() { let key = Bytes::from_utf8("YELLOW SUBMARINE"); let encrypt = |plaintext: &Bytes| -> Bytes { ctr::encrypt(&key, 0, plaintext) }; let ciphers: Vec = plaintexts.iter().map(encrypt).collect(); - let plaintexts = attack(ciphers); + let plaintexts = attack(&ciphers); println!("[okay] Challenge 20: {}", plaintexts[0].to_utf8()); } @@ -278,8 +286,16 @@ pub fn challenge20() { pub fn challenge21() { // Implement the MT19937 Mersenne Twister RNG let expected: Vec = vec![ - 0xD091BB5C, 0x22AE9EF6, 0xE7E1FAEE, 0xD5C31F79, 0x2082352C, 0xF807B7DF, 0xE9D30005, - 0x3895AFE1, 0xA1E24BBA, 0x4EE4092B, + 0xD091_BB5C, + 0x22AE_9EF6, + 0xE7E1_FAEE, + 0xD5C3_1F79, + 0x2082_352C, + 0xF807_B7DF, + 0xE9D3_0005, + 0x3895_AFE1, + 0xA1E2_4BBA, + 0x4EE4_092B, ]; let mut mt = mt19937::MT19937::new(); mt.seed(5489); @@ -326,8 +342,8 @@ pub fn challenge23() { const S: u32 = 7; const T: u32 = 15; const U: u32 = 11; - const B: u32 = 0x9D2C5680; - const C: u32 = 0xEFC60000; + const B: u32 = 0x9D2C_5680; + const C: u32 = 0xEFC6_0000; const L: u32 = 18; let mut y = x; @@ -339,8 +355,8 @@ pub fn challenge23() { } fn untemper(x: u32) -> u32 { - const B: u32 = 0x9D2C5680; - const C: u32 = 0xEFC60000; + const B: u32 = 0x9D2C_5680; + const C: u32 = 0xEFC6_0000; let mut y = x; // reverse y = y ^ (y >> L); L = 18; diff --git a/src/set4.rs b/src/set4.rs index 70b23b6..31d0553 100644 --- a/src/set4.rs +++ b/src/set4.rs @@ -203,21 +203,21 @@ pub fn challenge29() { for key_len in 1..128 { // get padding for key || orig-message let key_guessed = vec![b'z'; key_len]; // key-guessed - let mut bytes = key_guessed.to_vec(); - bytes.append(&mut message.0.to_vec()); // original-message + let mut bytes = key_guessed.clone(); + bytes.append(&mut message.0.clone()); // original-message let s1 = sha1::Sha1::default(); let glue_padding = s1.get_padding(&bytes); // glue-padding // forget MAC via fixture: make sure to fix sha1.h *and* sha1.byte_length let byte_length = (key_guessed.len() + message.len() + glue_padding.len()) as u64; let new_message = b"admin=true".to_vec(); // new-message - mac_forged = hash_fixated(&Bytes(new_message.to_vec()), &mac, byte_length); + mac_forged = hash_fixated(&Bytes(new_message.clone()), &mac, byte_length); // forge message: original-message || glue-padding || new-message - forged_message = message.0.to_vec(); + forged_message = message.0.clone(); forged_message.append(&mut glue_padding.clone()); forged_message.append(&mut new_message.clone()); - let r = sha1::verify(&Bytes(forged_message.to_vec()), &key, &mac_forged); + let r = sha1::verify(&Bytes(forged_message.clone()), &key, &mac_forged); if r { break; } @@ -274,20 +274,20 @@ pub fn challenge30() { for key_len in 1..128 { // get padding for key || orig-message let key_guessed = vec![b'z'; key_len]; // key-guessed - let mut bytes = key_guessed.to_vec(); - bytes.append(&mut message.0.to_vec()); // original-message + let mut bytes = key_guessed.clone(); + bytes.append(&mut message.0.clone()); // original-message let md4 = md4::Md4Core::default(); let glue_padding = md4.get_padding(&bytes); // glue-padding // forget MAC via fixture: make sure to fix md4.state *and* md4.byte_length let byte_length = (key_guessed.len() + message.len() + glue_padding.len()) as u64; let new_message = b"admin=true".to_vec(); // new-message - mac_forged = hash_fixated(&Bytes(new_message.to_vec()), &mac, byte_length); + mac_forged = hash_fixated(&Bytes(new_message.clone()), &mac, byte_length); // forge message: original-message || glue-padding || new-message - forged_message = message.0.to_vec(); - forged_message.append(&mut glue_padding.to_vec()); - forged_message.append(&mut new_message.to_vec()); + forged_message = message.0.clone(); + forged_message.append(&mut glue_padding.clone()); + forged_message.append(&mut new_message.clone()); let r = md4::verify(&Bytes(forged_message.clone()), &key, &mac_forged); if r { break; diff --git a/src/sha1.rs b/src/sha1.rs index b271855..cbff060 100644 --- a/src/sha1.rs +++ b/src/sha1.rs @@ -101,7 +101,7 @@ fn r4(block: &mut Block, v: u32, w: &mut u32, x: u32, y: u32, z: &mut u32, i: us impl Sha1 { #[inline] pub fn reset(&mut self) { - *self = Default::default(); + *self = Sha1::default(); } pub fn fix(&mut self, fixate: [u32; STATE_LEN], byte_len: u64) { @@ -227,8 +227,7 @@ impl Sha1 { // append the original message length as a 64-bit big-endian integer let bit_len: u64 = (self.byte_len + bytes.len() as u64) as u64 * 8; - padding.append(&mut ((bit_len >> 32) as u32).to_be_bytes().to_vec()); - padding.append(&mut (bit_len as u32).to_be_bytes().to_vec()); + padding.append(&mut bit_len.to_be_bytes().to_vec()); padding } diff --git a/src/utils.rs b/src/utils.rs index 4bab3c6..b50eddd 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -9,7 +9,10 @@ pub fn unix_timestamp() -> u32 { let since_the_epoch = start .duration_since(UNIX_EPOCH) .expect("Time went backwards"); - since_the_epoch.as_secs() as u32 + since_the_epoch + .as_secs() + .try_into() + .expect("Linux time no longer fits into 32 bits.") } pub fn read_base64(path: &str) -> Bytes {