Refactor code based on clippy suggestions

This commit is contained in:
2022-08-25 17:45:16 -04:00
parent 9a9b5335f1
commit b97b2fe6d0
16 changed files with 145 additions and 204 deletions

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"rust-analyzer.checkOnSave.command": "clippy",
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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,11 +260,8 @@ pub fn challenge14() {
for i in 1..10 {
let block_size = i * 16;
match get_duplicated_block_indices(&cipher, block_size) {
Some((_, _)) => {
return block_size;
}
_ => (),
if let Some((_, _)) = get_duplicated_block_indices(&cipher, block_size) {
return block_size;
}
}
0
@@ -293,18 +280,15 @@ 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, _)) => {
return block_size * first_block - i;
}
_ => (),
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);

View File

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

View File

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

View File

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

View File

@@ -25,9 +25,11 @@ 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))
.to_bytes()
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()
}