Resolve more linter warnings

main
Felix Martin 2022-08-27 14:47:56 -04:00
parent 0951a6ab3e
commit bac75acd2c
14 changed files with 175 additions and 172 deletions

View File

@ -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<Vec<u8>, 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<u32> = Iterator::zip(a.iter(), b.iter())
.map(|z| (*(z.0) ^ *(z.1)).count_ones())

View File

@ -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<u8> {
let mut v = c.to_vec();
// pad with bytes for conversion
@ -66,9 +65,9 @@ impl BytesBase64 {
v.push(0);
}
let mut result: Vec<u8> = 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));
}

View File

@ -27,11 +27,11 @@ pub fn decrypt_aes_128_ecb_block(key: &[u8], data: &[u8]) -> Vec<u8> {
pub fn encrypt(Bytes(key): &Bytes, Bytes(iv): &Bytes, Bytes(data): &Bytes) -> Bytes {
let block_size = 16;
let mut result: Vec<u8> = vec![];
let mut prev_cipher: Vec<u8> = iv.to_vec(); // first xor input is IV
let mut prev_cipher: Vec<u8> = 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<u8> = vec![];
let mut prev_cipher: Vec<u8> = iv.to_vec(); // first xor input is IV
let mut prev_cipher: Vec<u8> = 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)

View File

@ -47,8 +47,6 @@ fn main() {
set4::challenge28();
set4::challenge29();
set4::challenge30();
set4::challenge31();
} else {
set4::challenge31();
}
set4::challenge31();
}

View File

@ -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))
}

View File

@ -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];

View File

@ -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<u8> = vec![];
for chunk in data.chunks(4) {

View File

@ -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);
}

View File

@ -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::<u32>() 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");

View File

@ -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);

View File

@ -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<u8> = 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<RefCell<Vec<u8>>> {
fn xor_to_char_set(letters: &Vec<u8>) -> HashMap<u8, RefCell<HashSet<u8>>> {
let mut h = HashMap::new();
for i in 0..255_u8 {
@ -144,83 +152,83 @@ pub fn challenge19() {
letters
}
fn attack(ciphers: &[Bytes]) -> Vec<RefCell<Vec<u8>>> {
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<Option<u8>> = ciphers
.iter()
.map(|c| {
if c.len() > byte_index {
Some(c.0[byte_index])
} else {
None
}
})
.collect();
let mut possible_chars: Vec<HashSet<u8>> = 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<Option<u8>> = ciphers
.iter()
.map(|c| {
if c.len() > byte_index {
Some(c.0[byte_index])
} else {
None
}
}
})
.collect();
let mut possible_chars: Vec<HashSet<u8>> = 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<u8> = 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<u8> = 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<Vec<u8>>]) {
// 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<Bytes> = 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<Bytes>) -> Vec<Bytes> {
let min_cipher_len = ciphers.iter().map(|c| c.len()).min().unwrap_or(0);
fn attack(ciphers: &[Bytes]) -> Vec<Bytes> {
let min_cipher_len = ciphers.iter().map(Bytes::len).min().unwrap_or(0);
let mut key: Vec<u8> = 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<Bytes> = 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<u32> = 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;

View File

@ -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;

View File

@ -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
}

View File

@ -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 {