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