Resolve more linter warnings
parent
0951a6ab3e
commit
bac75acd2c
27
src/bytes.rs
27
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<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())
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -47,8 +47,6 @@ fn main() {
|
|||
set4::challenge28();
|
||||
set4::challenge29();
|
||||
set4::challenge30();
|
||||
set4::challenge31();
|
||||
} else {
|
||||
set4::challenge31();
|
||||
}
|
||||
set4::challenge31();
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
13
src/set1.rs
13
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::<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");
|
||||
|
|
42
src/set2.rs
42
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);
|
||||
|
|
182
src/set3.rs
182
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<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;
|
||||
|
|
22
src/set4.rs
22
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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue