Refactor code based on clippy suggestions
This commit is contained in:
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"rust-analyzer.checkOnSave.command": "clippy",
|
||||
}
|
||||
21
src/bytes.rs
21
src/bytes.rs
@@ -11,13 +11,16 @@ impl Bytes {
|
||||
}
|
||||
|
||||
pub fn from_utf8(s: &str) -> Bytes {
|
||||
Bytes(s.as_bytes().iter().map(|c| c.clone()).collect())
|
||||
Bytes(s.as_bytes().to_vec())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn to_utf8(&self) -> String {
|
||||
let Bytes(v) = self;
|
||||
String::from(std::str::from_utf8(&v).unwrap())
|
||||
String::from(std::str::from_utf8(v).unwrap())
|
||||
}
|
||||
|
||||
pub fn to_sub_utf8(&self, length: usize) -> String {
|
||||
Bytes(self.0[..length].to_vec()).to_utf8()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
@@ -69,7 +72,7 @@ impl Bytes {
|
||||
pub fn is_ascii(&self) -> bool {
|
||||
let Bytes(v) = self;
|
||||
for &c in v.iter() {
|
||||
if c < 32 || c > 127 {
|
||||
if !(32..=127).contains(&c) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -103,7 +106,7 @@ impl Bytes {
|
||||
h.last().unwrap().1
|
||||
}
|
||||
|
||||
pub fn pad_pkcs7(&mut self, block_size: usize) -> () {
|
||||
pub fn pad_pkcs7(&mut self, block_size: usize) {
|
||||
let Bytes(v) = self;
|
||||
let padding_value = (block_size - v.len() % block_size) as u8;
|
||||
for _ in 0..padding_value {
|
||||
@@ -118,7 +121,7 @@ impl Bytes {
|
||||
let last_block_index = self.len() / block_size - 1;
|
||||
let last_block = self.get_block(last_block_index, block_size).0;
|
||||
let pad_byte = last_block[block_size - 1];
|
||||
if pad_byte < 1 || pad_byte > 16 {
|
||||
if !(1..=16).contains(&pad_byte) {
|
||||
return false;
|
||||
}
|
||||
for i in 0..(pad_byte as usize) {
|
||||
@@ -127,10 +130,10 @@ impl Bytes {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
true
|
||||
}
|
||||
|
||||
pub fn remove_pkcs7(&mut self, block_size: usize) -> () {
|
||||
pub fn remove_pkcs7(&mut self, block_size: usize) {
|
||||
if !self.has_valid_pkcs7(block_size) {
|
||||
return;
|
||||
}
|
||||
@@ -141,7 +144,7 @@ impl Bytes {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flip_bit(&mut self, byte_index: usize, bit_index: usize) -> () {
|
||||
pub fn flip_bit(&mut self, byte_index: usize, bit_index: usize) {
|
||||
let Bytes(v) = self;
|
||||
let flip_mask: u8 = 0b1 << bit_index;
|
||||
v[byte_index] ^= flip_mask;
|
||||
|
||||
@@ -6,7 +6,31 @@ pub struct BytesBase64(pub Vec<u8>);
|
||||
|
||||
impl std::fmt::Display for BytesBase64 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Base64({})", self.to_string())
|
||||
let BytesBase64(digits) = self;
|
||||
let mut r: Vec<u8> = digits
|
||||
.iter()
|
||||
.map(|d| match d {
|
||||
0..=25 => *d + b'A',
|
||||
26..=51 => *d - 26 + b'a',
|
||||
52..=61 => *d - 52 + b'0',
|
||||
62 => b'+',
|
||||
63 => b'/',
|
||||
_ => panic!("Unexpected base64 digit '{}'", d),
|
||||
})
|
||||
.collect();
|
||||
// Handle padding
|
||||
let pad = b'=';
|
||||
match r.len() % 4 {
|
||||
0 => (),
|
||||
2 => {
|
||||
r.push(pad);
|
||||
r.push(pad);
|
||||
}
|
||||
3 => r.push(pad),
|
||||
_ => panic!("Unexpected lenght for padding '{}'", r.len()),
|
||||
}
|
||||
let s = str::from_utf8(r.as_slice()).unwrap().to_string();
|
||||
write!(f, "{}", s)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +46,7 @@ impl BytesBase64 {
|
||||
(v[0] & 0b11111100) >> 2,
|
||||
(v[0] & 0b00000011) << 4 | (v[1] & 0b11110000) >> 4,
|
||||
(v[1] & 0b00001111) << 2 | (v[2] & 0b11000000) >> 6,
|
||||
(v[2] & 0b00111111) << 0,
|
||||
(v[2] & 0b00111111),
|
||||
];
|
||||
// removed padded bytes
|
||||
for _ in c.len()..3 {
|
||||
@@ -30,7 +54,7 @@ impl BytesBase64 {
|
||||
}
|
||||
result
|
||||
}
|
||||
BytesBase64(bytes.chunks(3).map(|c| to_base64(c)).flatten().collect())
|
||||
BytesBase64(bytes.chunks(3).flat_map(to_base64).collect())
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Bytes {
|
||||
@@ -44,7 +68,7 @@ impl BytesBase64 {
|
||||
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) >> 0),
|
||||
((v[2] & 0b00000011) << 6) | (v[3] & 0b00111111),
|
||||
];
|
||||
// removed padded bytes
|
||||
for _ in c.len()..4 {
|
||||
@@ -52,16 +76,16 @@ impl BytesBase64 {
|
||||
}
|
||||
result
|
||||
}
|
||||
Bytes(v.chunks(4).map(|c| to_bytes(c)).flatten().collect())
|
||||
Bytes(v.chunks(4).flat_map(to_bytes).collect())
|
||||
}
|
||||
|
||||
pub fn from_base64(s: &str) -> Result<BytesBase64, String> {
|
||||
let mut r: Vec<u8> = Vec::with_capacity(s.len());
|
||||
for c in s.chars() {
|
||||
match c {
|
||||
'A'..='Z' => r.push((c as u8) - ('A' as u8)),
|
||||
'a'..='z' => r.push((c as u8) - ('a' as u8) + 26),
|
||||
'0'..='9' => r.push((c as u8) - ('0' as u8) + 52),
|
||||
'A'..='Z' => r.push((c as u8) - b'A'),
|
||||
'a'..='z' => r.push((c as u8) - b'a' + 26),
|
||||
'0'..='9' => r.push((c as u8) - b'0' + 52),
|
||||
'+' => r.push(62),
|
||||
'/' => r.push(63),
|
||||
'\n' => (),
|
||||
@@ -74,31 +98,4 @@ impl BytesBase64 {
|
||||
}
|
||||
Ok(BytesBase64(r))
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let BytesBase64(digits) = self;
|
||||
let mut r: Vec<u8> = digits
|
||||
.iter()
|
||||
.map(|d| match d {
|
||||
0..=25 => *d + ('A' as u8),
|
||||
26..=51 => *d - 26 + ('a' as u8),
|
||||
52..=61 => *d - 52 + ('0' as u8),
|
||||
62 => '+' as u8,
|
||||
63 => '/' as u8,
|
||||
_ => panic!("Unexpected base64 digit '{}'", d),
|
||||
})
|
||||
.collect();
|
||||
// Handle padding
|
||||
let pad = '=' as u8;
|
||||
match r.len() % 4 {
|
||||
0 => (),
|
||||
2 => {
|
||||
r.push(pad);
|
||||
r.push(pad);
|
||||
}
|
||||
3 => r.push(pad),
|
||||
_ => panic!("Unexpected lenght for padding '{}'", r.len()),
|
||||
}
|
||||
str::from_utf8(r.as_slice()).unwrap().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ pub fn decrypt(Bytes(key): &Bytes, Bytes(iv): &Bytes, Bytes(data): &Bytes) -> By
|
||||
let mut result: Vec<u8> = vec![];
|
||||
let mut prev_cipher: Vec<u8> = iv.to_vec(); // first xor input is IV
|
||||
for cipher in data.chunks(block_size) {
|
||||
let xored = decrypt_aes_128_ecb_block(key, &cipher);
|
||||
let xored = decrypt_aes_128_ecb_block(key, cipher);
|
||||
let data = crate::utils::xor(&xored, &prev_cipher);
|
||||
result.extend(data.to_vec());
|
||||
prev_cipher = cipher.to_vec();
|
||||
|
||||
@@ -6,17 +6,15 @@ pub fn encrypt(key: &Bytes, nonce: u64, data: &Bytes) -> Bytes {
|
||||
}
|
||||
|
||||
pub fn decrypt(Bytes(key): &Bytes, nonce: u64, Bytes(data): &Bytes) -> Bytes {
|
||||
let mut counter: u64 = 0;
|
||||
let cipher_type = symm::Cipher::aes_128_ecb();
|
||||
let block_size = cipher_type.block_size();
|
||||
let mut result: Vec<u8> = vec![];
|
||||
for cipher in data.chunks(block_size) {
|
||||
for (counter, cipher) in (0_u64..).zip(data.chunks(block_size)) {
|
||||
let mut keyinput = nonce.to_le_bytes().to_vec();
|
||||
keyinput.append(&mut counter.to_le_bytes().to_vec());
|
||||
let keystream = crate::cbc::enrypt_aes_128_ecb_block(key, &keyinput);
|
||||
let mut data = crate::utils::xor(&keystream, &cipher.to_vec());
|
||||
let mut data = crate::utils::xor(&keystream, cipher);
|
||||
result.append(&mut data);
|
||||
counter += 1;
|
||||
}
|
||||
Bytes(result)
|
||||
}
|
||||
|
||||
10
src/ecb.rs
10
src/ecb.rs
@@ -4,19 +4,17 @@ use openssl::symm;
|
||||
pub fn encrypt(Bytes(key): &Bytes, Bytes(data): &Bytes) -> Bytes {
|
||||
let cipher = symm::Cipher::aes_128_ecb();
|
||||
let data = symm::encrypt(cipher, key, None, data);
|
||||
let result = match data {
|
||||
match data {
|
||||
Ok(data) => Bytes(data),
|
||||
Err(err) => panic!("{}", err.to_string()),
|
||||
};
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decrypt(Bytes(key): &Bytes, Bytes(data): &Bytes) -> Bytes {
|
||||
let cipher = symm::Cipher::aes_128_ecb();
|
||||
let data = symm::decrypt(cipher, key, None, data);
|
||||
let result = match data {
|
||||
match data {
|
||||
Ok(data) => Bytes(data),
|
||||
Err(err) => panic!("{}", err.to_string()),
|
||||
};
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ mod sha1;
|
||||
mod utils;
|
||||
|
||||
fn main() {
|
||||
const RUN_ALL: bool = false;
|
||||
const RUN_ALL: bool = true;
|
||||
if RUN_ALL {
|
||||
set1::challenge1();
|
||||
set1::challenge2();
|
||||
|
||||
17
src/md4.rs
17
src/md4.rs
@@ -26,8 +26,7 @@ impl Md4Core {
|
||||
.wrapping_add(buffer.len() as u64)
|
||||
.wrapping_mul(8);
|
||||
|
||||
let mut padding = vec![];
|
||||
padding.push(0x80);
|
||||
let mut padding = vec![0x80];
|
||||
while (buffer.len() + padding.len()) % BLOCK_BYTES != (BLOCK_BYTES - 8) {
|
||||
padding.push(0x0);
|
||||
}
|
||||
@@ -42,13 +41,7 @@ impl Md4Core {
|
||||
compress(&mut self.state, &bytes.try_into().unwrap());
|
||||
}
|
||||
|
||||
Bytes(
|
||||
self.state
|
||||
.iter()
|
||||
.map(|i| i.to_le_bytes())
|
||||
.flatten()
|
||||
.collect(),
|
||||
)
|
||||
Bytes(self.state.iter().flat_map(|i| i.to_le_bytes()).collect())
|
||||
}
|
||||
|
||||
pub fn hash(&mut self, bytes: &Bytes) -> Bytes {
|
||||
@@ -64,9 +57,7 @@ impl Md4Core {
|
||||
}
|
||||
|
||||
pub fn fix(&mut self, fixate: [u32; 4], byte_len: u64) {
|
||||
for i in 0..4 {
|
||||
self.state[i] = fixate[i];
|
||||
}
|
||||
self.state[..4].copy_from_slice(&fixate[..4]);
|
||||
self.byte_len = byte_len;
|
||||
}
|
||||
}
|
||||
@@ -156,5 +147,5 @@ pub fn authenticate(message: &Bytes, key: &Bytes) -> Bytes {
|
||||
}
|
||||
|
||||
pub fn verify(message: &Bytes, key: &Bytes, mac: &Bytes) -> bool {
|
||||
return authenticate(&message, &key) == *mac;
|
||||
authenticate(message, key) == *mac
|
||||
}
|
||||
|
||||
@@ -40,10 +40,10 @@ impl MT19937 {
|
||||
}
|
||||
|
||||
pub fn extract_number(&mut self) -> u32 {
|
||||
if self.index == N {
|
||||
self.twist();
|
||||
} else if self.index > N {
|
||||
panic!("Generator was never seeded");
|
||||
match self.index.cmp(&N) {
|
||||
std::cmp::Ordering::Equal => self.twist(),
|
||||
std::cmp::Ordering::Greater => panic!("Generator was never seeded"),
|
||||
std::cmp::Ordering::Less => (),
|
||||
}
|
||||
|
||||
const S: u32 = 7;
|
||||
|
||||
@@ -16,7 +16,7 @@ pub fn parse_key_value(text: &str) -> HashMap<String, String> {
|
||||
let mut result = HashMap::new();
|
||||
tokens = scan(text, 0, tokens);
|
||||
for token_chunk in tokens.chunks(4) {
|
||||
match &token_chunk[..] {
|
||||
match token_chunk {
|
||||
[Token::Identifier(key), Token::Equal, Token::Identifier(value), Token::Ampersand] => {
|
||||
result.insert(key.to_string(), value.to_string());
|
||||
}
|
||||
@@ -54,8 +54,8 @@ fn scan(code: &str, mut ix: usize, mut tokens: Tokens) -> Tokens {
|
||||
|
||||
fn scan_identifier(code: &str, mut ix: usize, mut tokens: Tokens) -> Tokens {
|
||||
let start_ix = ix;
|
||||
let mut chars = code[ix..].chars();
|
||||
while let Some(c) = chars.next() {
|
||||
let chars = code[ix..].chars();
|
||||
for c in chars {
|
||||
if c.is_ascii_alphanumeric() || SPECIAL_CHARS.contains(&c) {
|
||||
ix += 1;
|
||||
} else {
|
||||
|
||||
17
src/set1.rs
17
src/set1.rs
@@ -72,13 +72,13 @@ 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('\n' as u8)
|
||||
output_vec.push(b'\n')
|
||||
}
|
||||
output_vec.push(*e.0);
|
||||
}
|
||||
output_vec.push('\n' as u8);
|
||||
output_vec.push(b'\n');
|
||||
let mut f = std::fs::File::create(path).unwrap();
|
||||
f.write(&output_vec).unwrap();
|
||||
f.write_all(&output_vec).unwrap();
|
||||
}
|
||||
|
||||
fn _test_roundtrip() {
|
||||
@@ -104,7 +104,7 @@ pub fn challenge6() {
|
||||
fn guess_key_size(bytes: &Bytes) -> usize {
|
||||
let (mut lowest_rating, mut lowest_size) = (f32::MAX, 0);
|
||||
for key_size in 2..40 {
|
||||
let rating = rate(&bytes, key_size);
|
||||
let rating = rate(bytes, key_size);
|
||||
if rating < lowest_rating {
|
||||
lowest_rating = rating;
|
||||
lowest_size = key_size;
|
||||
@@ -129,12 +129,7 @@ pub fn challenge6() {
|
||||
let bytes = utils::read_base64("data/6.txt");
|
||||
let key_size = guess_key_size(&bytes);
|
||||
let bytes_tranposed = transpose(&bytes, key_size);
|
||||
let key = Bytes(
|
||||
bytes_tranposed
|
||||
.iter()
|
||||
.map(|b| Bytes::guess_key(&b))
|
||||
.collect(),
|
||||
);
|
||||
let key = Bytes(bytes_tranposed.iter().map(Bytes::guess_key).collect());
|
||||
let msg = Bytes::xor_cycle(&bytes, &key).to_utf8();
|
||||
|
||||
let partial_msg = msg[..20].to_string();
|
||||
@@ -169,7 +164,7 @@ pub fn challenge8() {
|
||||
|
||||
let expected_index: usize = 132;
|
||||
let bytes_vector = utils::read_hex_lines("data/8.txt");
|
||||
let ratings: Vec<u32> = bytes_vector.iter().map(|b| rate(&b, 16)).collect();
|
||||
let ratings: Vec<u32> = bytes_vector.iter().map(|b| rate(b, 16)).collect();
|
||||
let min_rating = ratings.iter().min().unwrap();
|
||||
let index = ratings.iter().position(|e| e == min_rating).unwrap();
|
||||
let average = ratings.iter().sum::<u32>() as f32 / ratings.len() as f32;
|
||||
|
||||
105
src/set2.rs
105
src/set2.rs
@@ -32,8 +32,8 @@ pub fn challenge10() {
|
||||
pub fn challenge11() {
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum EncryptionType {
|
||||
CBC,
|
||||
ECB,
|
||||
Cbc,
|
||||
Ecb,
|
||||
}
|
||||
|
||||
fn pad_data(mut v: Vec<u8>) -> Bytes {
|
||||
@@ -56,10 +56,10 @@ pub fn challenge11() {
|
||||
// which to use.
|
||||
let zero_or_one: u32 = rand::thread_rng().gen_range(0..2);
|
||||
let (data, encryption_type) = if zero_or_one == 1 {
|
||||
(ecb::encrypt(&key, &padded_data), EncryptionType::ECB)
|
||||
(ecb::encrypt(&key, &padded_data), EncryptionType::Ecb)
|
||||
} else {
|
||||
let iv = Bytes::random(16);
|
||||
(cbc::encrypt(&key, &iv, &padded_data), EncryptionType::CBC)
|
||||
(cbc::encrypt(&key, &iv, &padded_data), EncryptionType::Cbc)
|
||||
};
|
||||
(data, encryption_type)
|
||||
}
|
||||
@@ -69,9 +69,9 @@ pub fn challenge11() {
|
||||
// with a piece of code that, pointed at a block box that might be encrypting ECB
|
||||
// or CBC, tells you which one is happening.
|
||||
if data.has_duplicated_cycle(16) {
|
||||
EncryptionType::ECB
|
||||
EncryptionType::Ecb
|
||||
} else {
|
||||
EncryptionType::CBC
|
||||
EncryptionType::Cbc
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,44 +106,38 @@ pub fn challenge12() {
|
||||
let mut data = data.to_vec();
|
||||
let mut string = utils::read_base64("data/12.txt");
|
||||
data.append(&mut string.0);
|
||||
let cipher = ecb::encrypt(&key, &Bytes(data));
|
||||
cipher
|
||||
ecb::encrypt(key, &Bytes(data))
|
||||
}
|
||||
|
||||
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.to_vec())).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.to_vec()));
|
||||
new_cipher_len = cipher.0.len();
|
||||
}
|
||||
let key_length = new_cipher_len - initial_cipher_len;
|
||||
key_length
|
||||
new_cipher_len - initial_cipher_len
|
||||
}
|
||||
|
||||
fn is_encryption_ecb(key: &Bytes) -> bool {
|
||||
let data = Bytes::from_utf8("aaaabbbbccccddddaaaabbbbccccdddd");
|
||||
let cipher = encryption_oracle(&key, &data);
|
||||
if cipher.has_duplicated_cycle(16) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
let cipher = encryption_oracle(key, &data);
|
||||
cipher.has_duplicated_cycle(16)
|
||||
}
|
||||
|
||||
fn decode(key: &Bytes) -> Bytes {
|
||||
let block_size = get_block_size(&key);
|
||||
let block_count = encryption_oracle(&key, &Bytes(vec![])).0.len() / block_size;
|
||||
let block_size = get_block_size(key);
|
||||
let block_count = encryption_oracle(key, &Bytes(vec![])).0.len() / block_size;
|
||||
let mut cleartext = vec![];
|
||||
|
||||
for block_index in 0..block_count {
|
||||
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.to_vec()));
|
||||
let expected_block = expected.get_block(block_index, block_size);
|
||||
|
||||
let mut known_text = if block_index == 0 {
|
||||
@@ -159,7 +153,7 @@ pub fn challenge12() {
|
||||
let mut guess_text = known_text.to_vec();
|
||||
guess_text.push(i);
|
||||
let cipher_block =
|
||||
encryption_oracle(&key, &Bytes(guess_text)).get_block(0, block_size);
|
||||
encryption_oracle(key, &Bytes(guess_text)).get_block(0, block_size);
|
||||
if cipher_block.0 == expected_block.0 {
|
||||
cleartext_block.push(i);
|
||||
break;
|
||||
@@ -173,7 +167,7 @@ pub fn challenge12() {
|
||||
|
||||
let key = Bytes::random(16); // consistent but unknown key
|
||||
assert_eq!(get_block_size(&key), 16); // 1. discover block size
|
||||
assert_eq!(is_encryption_ecb(&key), true); // 2. confirm oracle uses ecb
|
||||
assert!(is_encryption_ecb(&key)); // 2. confirm oracle uses ecb
|
||||
let roundtrip_text = decode(&key); // 3.-6.
|
||||
let cleartext = utils::read_base64("data/12.txt");
|
||||
|
||||
@@ -182,10 +176,7 @@ pub fn challenge12() {
|
||||
// byte, encrypt it, and then compare it to the result of the encryption
|
||||
// oracle, but this approach is fine too.
|
||||
assert_eq!(roundtrip_text.0[..138], cleartext.0);
|
||||
println!(
|
||||
"[okay] Challenge 12: {}",
|
||||
roundtrip_text.to_utf8()[..17].to_string()
|
||||
);
|
||||
println!("[okay] Challenge 12: {}", roundtrip_text.to_sub_utf8(17));
|
||||
}
|
||||
|
||||
pub fn challenge13() {
|
||||
@@ -199,11 +190,11 @@ pub fn challenge13() {
|
||||
r.push_str("email=");
|
||||
r.push_str(input);
|
||||
r.push_str("&uid=1337&role=user");
|
||||
ecb::encrypt(&key, &Bytes(r.as_bytes().to_vec()))
|
||||
ecb::encrypt(key, &Bytes(r.as_bytes().to_vec()))
|
||||
}
|
||||
|
||||
fn decrypt(key: &Bytes, data: &Bytes) -> HashMap<String, String> {
|
||||
let c = ecb::decrypt(&key, &data);
|
||||
let c = ecb::decrypt(key, data);
|
||||
parser::parse_key_value(&c.to_utf8())
|
||||
}
|
||||
|
||||
@@ -218,19 +209,19 @@ pub fn challenge13() {
|
||||
// ________________________________
|
||||
// 0..34..78..bc..f0..34..78..bc..f0..34..78..bc..f
|
||||
// email=aaaaa@a.com&uid=1337&role=user
|
||||
let p = profile_for("aaaaa@a.com", &key);
|
||||
let p = profile_for("aaaaa@a.com", key);
|
||||
r.append(&mut p.0[0..32].to_vec());
|
||||
|
||||
// ----------------
|
||||
// 0..34..78..bc..f0..34..78..bc..f0..34..78..bc..f
|
||||
// email=aaaaaaa@a.admin&uid=1337&role=user
|
||||
let p = profile_for("aaaaaaa@a.admin", &key);
|
||||
let p = profile_for("aaaaaaa@a.admin", key);
|
||||
r.append(&mut p.0[16..32].to_vec());
|
||||
|
||||
// ----------------
|
||||
// 0..34..78..bc..f0..34..78..bc..f0..34..78..bc..f
|
||||
// email=aaaaaaaa@a.admin&uid=1337&role=user
|
||||
let p = profile_for("aaaaaaaa@a.admin", &key);
|
||||
let p = profile_for("aaaaaaaa@a.admin", key);
|
||||
r.append(&mut p.0[32..48].to_vec());
|
||||
|
||||
Bytes(r)
|
||||
@@ -259,8 +250,7 @@ pub fn challenge14() {
|
||||
plaintext.append(&mut attacker_controlled.to_vec());
|
||||
let mut target_bytes = utils::read_base64("data/12.txt").0;
|
||||
plaintext.append(&mut target_bytes);
|
||||
let cipher = ecb::encrypt(&random_key, &Bytes(plaintext));
|
||||
cipher
|
||||
ecb::encrypt(random_key, &Bytes(plaintext))
|
||||
}
|
||||
|
||||
fn get_block_size(prefix: &Bytes, key: &Bytes) -> usize {
|
||||
@@ -270,12 +260,9 @@ pub fn challenge14() {
|
||||
|
||||
for i in 1..10 {
|
||||
let block_size = i * 16;
|
||||
match get_duplicated_block_indices(&cipher, block_size) {
|
||||
Some((_, _)) => {
|
||||
if let Some((_, _)) = get_duplicated_block_indices(&cipher, block_size) {
|
||||
return block_size;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
@@ -293,19 +280,16 @@ pub fn challenge14() {
|
||||
}
|
||||
|
||||
fn get_prefix_size(prefix: &Bytes, key: &Bytes) -> usize {
|
||||
let block_size = get_block_size(&prefix, &key);
|
||||
let block_size = get_block_size(prefix, key);
|
||||
let duplicated_text = Bytes::from_utf8("aaaabbbbccccddddaaaabbbbccccdddd").0;
|
||||
|
||||
for i in 0..block_size {
|
||||
let mut padding = vec![b'a'; i];
|
||||
padding.append(&mut duplicated_text.to_vec());
|
||||
let cipher = encryption_oracle(prefix, key, &Bytes(padding));
|
||||
match get_duplicated_block_indices(&cipher, block_size) {
|
||||
Some((first_block, _)) => {
|
||||
if let Some((first_block, _)) = get_duplicated_block_indices(&cipher, block_size) {
|
||||
return block_size * first_block - i;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
@@ -315,7 +299,7 @@ pub fn challenge14() {
|
||||
let prefix_size = get_prefix_size(prefix, key);
|
||||
let prefix_padding_size = block_size - (prefix_size % block_size);
|
||||
let prefix_padding = Bytes(vec![b'a'; prefix_padding_size]);
|
||||
let block_count = encryption_oracle(&prefix, &key, &prefix_padding).len() / block_size;
|
||||
let block_count = encryption_oracle(prefix, key, &prefix_padding).len() / block_size;
|
||||
let first_block_index = (prefix_size + prefix_padding_size) / block_size;
|
||||
let mut cleartext = vec![];
|
||||
|
||||
@@ -371,36 +355,17 @@ pub fn challenge14() {
|
||||
let roundtrip_text = decode(&prefix, &key);
|
||||
let cleartext = utils::read_base64("data/12.txt");
|
||||
assert_eq!(roundtrip_text, cleartext);
|
||||
println!(
|
||||
"[okay] Challenge 14: {}",
|
||||
roundtrip_text.to_utf8()[..17].to_string()
|
||||
);
|
||||
println!("[okay] Challenge 14: {}", roundtrip_text.to_sub_utf8(17));
|
||||
}
|
||||
|
||||
pub fn challenge15() {
|
||||
assert_eq!(
|
||||
Bytes::from_utf8("ICE ICE BABY\u{4}\u{4}\u{4}").has_valid_pkcs7(16),
|
||||
false
|
||||
);
|
||||
assert_eq!(
|
||||
Bytes::from_utf8("ICE ICE BABY\u{4}\u{4}\u{4}\u{4}").has_valid_pkcs7(16),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
Bytes::from_utf8("ICE ICE BABY\u{3}\u{3}\u{4}\u{4}").has_valid_pkcs7(16),
|
||||
false
|
||||
);
|
||||
assert_eq!(
|
||||
Bytes::from_utf8("ICE ICE BABY!!!\u{0}").has_valid_pkcs7(16),
|
||||
false
|
||||
);
|
||||
assert_eq!(
|
||||
Bytes::from_utf8("ICE ICE BABY!!!\u{1}").has_valid_pkcs7(16),
|
||||
true
|
||||
);
|
||||
assert!(!Bytes::from_utf8("ICE ICE BABY\u{4}\u{4}\u{4}").has_valid_pkcs7(16));
|
||||
assert!(!Bytes::from_utf8("ICE ICE BABY\u{3}\u{3}\u{4}\u{4}").has_valid_pkcs7(16));
|
||||
assert!(!Bytes::from_utf8("ICE ICE BABY!!!\u{0}").has_valid_pkcs7(16));
|
||||
assert!(Bytes::from_utf8("ICE ICE BABY!!!\u{1}").has_valid_pkcs7(16));
|
||||
let mut bytes = Bytes::from_utf8("ICE ICE BABY\u{3}\u{3}\u{4}\u{4}");
|
||||
bytes.pad_pkcs7(16);
|
||||
assert_eq!(bytes.has_valid_pkcs7(16), true);
|
||||
assert!(bytes.has_valid_pkcs7(16));
|
||||
println!("[okay] Challenge 15: PKCS7 works");
|
||||
}
|
||||
|
||||
@@ -417,7 +382,7 @@ pub fn challenge16() {
|
||||
r.push_str(";comment2=%20like%20a%20pound%20of%20bacon");
|
||||
let mut cleartext = Bytes(r.as_bytes().to_vec());
|
||||
cleartext.pad_pkcs7(16);
|
||||
cbc::encrypt(&key, &iv, &cleartext)
|
||||
cbc::encrypt(key, iv, &cleartext)
|
||||
}
|
||||
|
||||
let iv = Bytes::random(16);
|
||||
|
||||
32
src/set3.rs
32
src/set3.rs
@@ -46,8 +46,9 @@ pub fn challenge17() {
|
||||
for pad_byte in 1..=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 in 0..(pad_byte - 1) {
|
||||
attack_vector.0[block_size - 1 - i] = (pad_byte as u8) ^ intermittent_result[i];
|
||||
for (i, intermittent_byte) in intermittent_result.iter().enumerate().take(pad_byte - 1)
|
||||
{
|
||||
attack_vector.0[block_size - 1 - i] = (pad_byte as u8) ^ intermittent_byte;
|
||||
}
|
||||
|
||||
// guess attack vector so that padding is valid
|
||||
@@ -129,7 +130,7 @@ pub fn challenge19() {
|
||||
}
|
||||
|
||||
fn u8_lower(s: u8) -> u8 {
|
||||
if s >= b'A' && s <= b'Z' {
|
||||
if (b'A'..=b'Z').contains(&s) {
|
||||
return s + 32;
|
||||
}
|
||||
s
|
||||
@@ -220,7 +221,7 @@ pub fn challenge19() {
|
||||
deciphered
|
||||
}
|
||||
|
||||
fn manual(decrypts: &Vec<RefCell<Vec<u8>>>) {
|
||||
fn manual(decrypts: &[RefCell<Vec<u8>>]) {
|
||||
// Add manually guessed letters
|
||||
decrypts[0].borrow_mut()[30] = b'y';
|
||||
decrypts[2].borrow_mut()[30] = b'y';
|
||||
@@ -242,16 +243,11 @@ pub fn challenge19() {
|
||||
let plaintexts = utils::read_base64_lines("data/19.txt");
|
||||
let key = Bytes::from_utf8("YELLOW SUBMARINE");
|
||||
let encrypt = |plaintext: &Bytes| -> Bytes { ctr::encrypt(&key, 0, plaintext) };
|
||||
let ciphers: Vec<Bytes> = plaintexts.iter().map(|ct| encrypt(&ct)).collect();
|
||||
let ciphers: Vec<Bytes> = plaintexts.iter().map(encrypt).collect();
|
||||
let decrypts = attack(ciphers);
|
||||
manual(&decrypts);
|
||||
for row in decrypts {
|
||||
println!(
|
||||
"[okay] Challenge 19: {}",
|
||||
Bytes(row.borrow().to_vec()).to_utf8()
|
||||
);
|
||||
break;
|
||||
}
|
||||
let first_line = Bytes(decrypts[0].borrow().to_vec()).to_utf8();
|
||||
println!("[okay] Challenge 19: {first_line}");
|
||||
}
|
||||
|
||||
pub fn challenge20() {
|
||||
@@ -273,7 +269,7 @@ pub fn challenge20() {
|
||||
let plaintexts = utils::read_base64_lines("data/20.txt");
|
||||
let key = Bytes::from_utf8("YELLOW SUBMARINE");
|
||||
let encrypt = |plaintext: &Bytes| -> Bytes { ctr::encrypt(&key, 0, plaintext) };
|
||||
let ciphers: Vec<Bytes> = plaintexts.iter().map(|ct| encrypt(&ct)).collect();
|
||||
let ciphers: Vec<Bytes> = plaintexts.iter().map(encrypt).collect();
|
||||
let plaintexts = attack(ciphers);
|
||||
|
||||
println!("[okay] Challenge 20: {}", plaintexts[0].to_utf8());
|
||||
@@ -287,8 +283,8 @@ pub fn challenge21() {
|
||||
];
|
||||
let mut mt = mt19937::MT19937::new();
|
||||
mt.seed(5489);
|
||||
for i in 0..expected.len() {
|
||||
assert_eq!(mt.extract_number(), expected[i]);
|
||||
for e in expected {
|
||||
assert_eq!(mt.extract_number(), e);
|
||||
}
|
||||
println!("[okay] Challenge 21: implemented MT19937");
|
||||
}
|
||||
@@ -442,7 +438,7 @@ pub fn challenge24() {
|
||||
// brute force bb!
|
||||
for key in 0..u16::MAX {
|
||||
let mut found_key = true;
|
||||
let roundtrip = mtcipher::decrypt(key, &cipher);
|
||||
let roundtrip = mtcipher::decrypt(key, cipher);
|
||||
// check if the last 14 chars are 'A' - if yes, we found the key
|
||||
for i in (cipher_len - 14)..cipher_len {
|
||||
if roundtrip.0[i] != b'A' {
|
||||
@@ -500,9 +496,9 @@ pub fn challenge24() {
|
||||
false
|
||||
}
|
||||
|
||||
assert_eq!(is_time_token(&token), true);
|
||||
assert!(is_time_token(&token));
|
||||
let non_token = Bytes(vec![b'z', 16]);
|
||||
assert_eq!(is_time_token(&non_token), false);
|
||||
assert!(!is_time_token(&non_token));
|
||||
|
||||
println!("[okay] Challenge 24: MT19937 stream cipher implemented and cracked");
|
||||
}
|
||||
|
||||
16
src/set4.rs
16
src/set4.rs
@@ -17,9 +17,7 @@ pub fn challenge25() {
|
||||
panic!("challenge25 - edit - out of bounds");
|
||||
}
|
||||
|
||||
for i in 0..newtext.len() {
|
||||
plaintext.0[offset + i] = newtext[i];
|
||||
}
|
||||
plaintext.0[offset..(newtext.len() + offset)].copy_from_slice(&newtext[..]);
|
||||
ctr::encrypt(key, 0, &plaintext)
|
||||
}
|
||||
|
||||
@@ -64,12 +62,12 @@ pub fn challenge26() {
|
||||
// comment1=cooking%20MCs;userdata=aaaaaaaaaaaaaaaa;comment2=%20like%20a%20pound%20of%20bacon
|
||||
// comment1=cooking%20MCs;userdata=fobar;admin=true;comment2=%20like%20a%20pound%20of%20bacon
|
||||
let input = "aaaaaaaaaaaaaaaa";
|
||||
let cipher = encrypt(&input, &key);
|
||||
let cipher = encrypt(input, &key);
|
||||
let keystream = utils::xor(&cipher.0[32..48], &Bytes::from_utf8(input).0);
|
||||
|
||||
let input = "fobar;admin=true";
|
||||
let mut flipped_cipher = cipher.0[0..32].to_vec();
|
||||
flipped_cipher.append(&mut utils::xor(&keystream, &input.as_bytes()));
|
||||
flipped_cipher.append(&mut utils::xor(&keystream, input.as_bytes()));
|
||||
flipped_cipher.append(&mut cipher.0[48..cipher.len()].to_vec());
|
||||
|
||||
let cleartext = ctr::decrypt(&key, 0, &Bytes(flipped_cipher));
|
||||
@@ -84,7 +82,7 @@ pub fn challenge27() {
|
||||
// AES-CBC(P_1, P_2, P_3) -> C_1, C_2, C_3
|
||||
let mut ct = Bytes::from_utf8("comment1=cooking%20MCs;userdata=secretsaucenouse");
|
||||
ct.pad_pkcs7(16);
|
||||
cbc::encrypt(&key, &key, &ct)
|
||||
cbc::encrypt(key, key, &ct)
|
||||
}
|
||||
|
||||
fn decrypt(key: &Bytes, cipher: &Bytes) -> Result<Bytes, Bytes> {
|
||||
@@ -93,7 +91,7 @@ pub fn challenge27() {
|
||||
// values). Noncompliant messages should raise an exception or return an
|
||||
// error that includes the decrypted plaintext (this happens all the
|
||||
// time in real systems, for what it's worth).
|
||||
let mut cleartext = cbc::decrypt(&key, &key, &cipher);
|
||||
let mut cleartext = cbc::decrypt(key, key, cipher);
|
||||
cleartext.remove_pkcs7(16);
|
||||
match std::str::from_utf8(&cleartext.0) {
|
||||
Ok(_) => Ok(cleartext),
|
||||
@@ -191,7 +189,7 @@ pub fn challenge29() {
|
||||
// With the registers "fixated", hash the additional data you want to
|
||||
// forge.
|
||||
s.fix(fixate.try_into().unwrap(), byte_len);
|
||||
s.hash(&bytes)
|
||||
s.hash(bytes)
|
||||
}
|
||||
|
||||
// use random
|
||||
@@ -263,7 +261,7 @@ pub fn challenge30() {
|
||||
.map(|c| u32::from_le_bytes(c.try_into().unwrap()))
|
||||
.collect();
|
||||
m.fix(fixate.try_into().unwrap(), byte_len);
|
||||
m.hash(&bytes)
|
||||
m.hash(bytes)
|
||||
}
|
||||
|
||||
let key = Bytes::random_range(2, 64);
|
||||
|
||||
25
src/sha1.rs
25
src/sha1.rs
@@ -39,14 +39,14 @@ fn bytes_to_block(bytes: &[u8]) -> Block {
|
||||
}
|
||||
|
||||
fn rol(value: u32, bits: usize) -> u32 {
|
||||
return (value << bits) | (value >> (32 - bits));
|
||||
(value << bits) | (value >> (32 - bits))
|
||||
}
|
||||
|
||||
fn blk(block: &Block, i: usize) -> u32 {
|
||||
return rol(
|
||||
rol(
|
||||
block[(i + 13) & 15] ^ block[(i + 8) & 15] ^ block[(i + 2) & 15] ^ block[i],
|
||||
1,
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
fn r0(block: &Block, v: u32, w: &mut u32, x: u32, y: u32, z: &mut u32, i: usize) {
|
||||
@@ -105,9 +105,7 @@ impl Sha1 {
|
||||
}
|
||||
|
||||
pub fn fix(&mut self, fixate: [u32; STATE_LEN], byte_len: u64) {
|
||||
for i in 0..5 {
|
||||
self.h[i] = fixate[i];
|
||||
}
|
||||
self.h[..5].copy_from_slice(&fixate[..5]);
|
||||
self.byte_len = byte_len;
|
||||
}
|
||||
|
||||
@@ -219,10 +217,8 @@ impl Sha1 {
|
||||
}
|
||||
|
||||
pub fn get_padding(&self, bytes: &Vec<u8>) -> Vec<u8> {
|
||||
let mut padding = vec![];
|
||||
|
||||
// append 0x80 to the message
|
||||
padding.push(0x80);
|
||||
let mut padding = vec![0x80];
|
||||
|
||||
// append 0 ≤ k < 64 bytes so that message.len() ≡ 56 (mod 64)
|
||||
while (bytes.len() + padding.len()) % BLOCK_BYTES != (BLOCK_BYTES - 8) {
|
||||
@@ -240,7 +236,7 @@ impl Sha1 {
|
||||
let mut final_bytes = vec![];
|
||||
for bytes in bytes.0.chunks(BLOCK_BYTES) {
|
||||
if bytes.len() == BLOCK_BYTES {
|
||||
self.update(&bytes);
|
||||
self.update(bytes);
|
||||
} else {
|
||||
final_bytes = bytes.to_vec();
|
||||
}
|
||||
@@ -248,9 +244,9 @@ impl Sha1 {
|
||||
let mut padding = self.get_padding(&final_bytes);
|
||||
final_bytes.append(&mut padding);
|
||||
for bytes in final_bytes.chunks(BLOCK_BYTES) {
|
||||
self.update(&bytes);
|
||||
self.update(bytes);
|
||||
}
|
||||
Bytes(self.h.iter().map(|i| i.to_be_bytes()).flatten().collect())
|
||||
Bytes(self.h.iter().flat_map(|i| i.to_be_bytes()).collect())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,10 +259,9 @@ pub fn authenticate(message: &Bytes, key: &Bytes) -> Bytes {
|
||||
c.append(&mut message.0.to_vec());
|
||||
// how to concatenate better: https://stackoverflow.com/a/56490417
|
||||
let mut sha1 = Sha1::default();
|
||||
let r = sha1.hash(&Bytes(c));
|
||||
r
|
||||
sha1.hash(&Bytes(c))
|
||||
}
|
||||
|
||||
pub fn verify(message: &Bytes, key: &Bytes, mac: &Bytes) -> bool {
|
||||
return authenticate(&message, &key) == *mac;
|
||||
authenticate(message, key) == *mac
|
||||
}
|
||||
|
||||
@@ -25,8 +25,10 @@ pub fn read_base64_lines(path: &str) -> Vec<Bytes> {
|
||||
let br = BufReader::new(file);
|
||||
br.lines()
|
||||
.map(|line| {
|
||||
BytesBase64::from_base64(&line.expect(&format!("Failed to read line in {}", path)))
|
||||
.expect(&format!("Invalid base64 in {}", path))
|
||||
BytesBase64::from_base64(
|
||||
&line.unwrap_or_else(|_| panic!("Failed to read line in {}", path)),
|
||||
)
|
||||
.unwrap_or_else(|_| panic!("Invalid base64 in {}", path))
|
||||
.to_bytes()
|
||||
})
|
||||
.collect()
|
||||
|
||||
Reference in New Issue
Block a user