Finish challenge 29 - I didn't find it trivial tbh

This commit is contained in:
2022-08-19 18:39:29 -04:00
parent 65fe5a7f96
commit c12b1c45a6
4 changed files with 139 additions and 71 deletions

View File

@@ -1,11 +1,9 @@
#![allow(arithmetic_overflow)]
use crate::{bytes::Bytes, cbc, ctr, parser, sha1, utils};
use crate::{bytes::Bytes, cbc, ctr, ecb, parser, sha1, utils};
pub fn challenge25() {
let cipher = utils::read_base64("data/25.txt");
let key = Bytes::from_utf8("YELLOW SUBMARINE");
let plaintext = crate::ecb::decrypt(&key, &cipher);
let plaintext = ecb::decrypt(&key, &cipher);
let key = Bytes::random(16);
let nonce: u64 = 0; // otherwise edit would require the nonce too?
@@ -32,8 +30,8 @@ pub fn challenge25() {
let ciphertext = ctr::encrypt(&key, nonce, &plaintext);
let newtext = vec![b'a'; ciphertext.len()];
let cipher_newtext = edit(&ciphertext, &key, 0, &newtext);
let keystream = crate::utils::xor(&newtext, &cipher_newtext.0);
let recovered_plaintext = Bytes(crate::utils::xor(&keystream, &ciphertext.0));
let keystream = utils::xor(&newtext, &cipher_newtext.0);
let recovered_plaintext = Bytes(utils::xor(&keystream, &ciphertext.0));
assert_eq!(plaintext, recovered_plaintext);
println!("[okay] Challenge 25: recovered AES CTR plaintext via edit");
@@ -140,50 +138,99 @@ pub fn challenge27() {
}
pub fn challenge28() {
let mut sha1 = sha1::Sha1::default();
let i1 = Bytes(vec![b'a'; 64]);
let e1 = Bytes::from_hex("0098ba824b5c16427bd7a1122a5a442a25ec644d");
let o1 = sha1::hash(&i1);
let o1 = sha1.hash(&i1);
assert_eq!(e1, o1);
sha1.reset();
let i2 = Bytes(vec![b'a'; 128]);
let e2 = Bytes::from_hex("ad5b3fdbcb526778c2839d2f151ea753995e26a0");
let o2 = sha1::hash(&i2);
let o2 = sha1.hash(&i2);
assert_eq!(e2, o2);
sha1.reset();
let i3 = Bytes(vec![b'a'; 3]);
let e3 = Bytes::from_hex("7e240de74fb1ed08fa08d38063f6a6a91462a815");
let o3 = sha1::hash(&i3);
let o3 = sha1.hash(&i3);
assert_eq!(e3, o3);
sha1.reset();
let i4 = Bytes(vec![]);
let e4 = Bytes::from_hex("da39a3ee5e6b4b0d3255bfef95601890afd80709");
let o4 = sha1::hash(&i4);
let o4 = sha1.hash(&i4);
assert_eq!(e4, o4);
fn authenticate(message: &Bytes, key: &Bytes) -> Bytes {
// Write a function to authenticate a message under a secret key by using a
// secret-prefix MAC, which is simply:
// SHA1(key || message)
let mut c = vec![];
c.append(&mut key.0.to_vec());
c.append(&mut message.0.to_vec());
// how to concatenate better: https://stackoverflow.com/a/56490417
sha1::hash(&Bytes(c))
}
// Verify that you cannot tamper with the message without breaking the MAC
// you've produced, and that you can't produce a new MAC without knowing the
// secret key.
let mut message = Bytes::from_utf8("love, love, love");
let key = Bytes::from_utf8("kisses!");
let auth = authenticate(&message, &key);
let mac = sha1::authenticate(&message, &key);
message.flip_bit(2, 3);
let auth_tempered = authenticate(&message, &key);
assert!(auth != auth_tempered);
assert!(!sha1::verify(&message, &key, &mac));
println!("[okay] Challenge 28: implemented SHA-1");
}
pub fn challenge29() {
println!("[xxxx] Challenge 29: TBD");
fn hash_fixated(bytes: &Bytes, fixture: &Bytes, byte_len: u64) -> Bytes {
// Now, take the SHA-1 secret-prefix MAC of the message you want to forge --- this is just
// a SHA-1 hash --- and break it into 32 bit SHA-1 registers (SHA-1 calls them "a", "b",
// "c", &c).
let mut s = sha1::Sha1::default();
let fixate: Vec<u32> = fixture
.0
.chunks(4)
.map(|c| u32::from_be_bytes(c.try_into().unwrap()))
.collect();
// Modify your SHA-1 implementation so that callers can pass in new
// values for "a", "b", "c" &c (they normally start at magic numbers).
// With the registers "fixated", hash the additional data you want to
// forge.
s.fix(fixate.try_into().unwrap(), byte_len);
s.hash(&bytes)
}
// use random
let key = Bytes::random_range(2, 64);
let message = Bytes::from_utf8(
"comment1=cooking%20MCs;userdata=foo;comment2=%20like%20a%20pound%20of%20bacon",
);
let mac = sha1::authenticate(&message, &key);
assert!(sha1::verify(&message, &key, &mac));
let mut forged_message = vec![];
let mut mac_forged = Bytes(vec![]);
for key_len in 1..128 {
// get padding for key || orig-message
let key_guessed = vec![b'z'; key_len]; // key-guessed
let mut bytes = key_guessed.to_vec();
bytes.append(&mut message.0.to_vec()); // original-message
let s1 = sha1::Sha1::default();
let glue_padding = s1.get_padding(&bytes); // glue-padding
// forget MAC via fixture: make sure to fix sha1.h *and* sha1.byte_length
let byte_length = (key_guessed.len() + message.len() + glue_padding.len()) as u64;
let new_message = b"admin=true".to_vec(); // new-message
mac_forged = hash_fixated(&Bytes(new_message.to_vec()), &mac, byte_length);
// forge message: original-message || glue-padding || new-message
forged_message = message.0.to_vec();
forged_message.append(&mut glue_padding.to_vec());
forged_message.append(&mut new_message.to_vec());
let r = sha1::verify(&Bytes(forged_message.to_vec()), &key, &mac_forged);
if r {
break;
}
}
assert!(sha1::verify(&Bytes(forged_message), &key, &mac_forged));
println!("[okay] Challenge 29: forged SHA-1 keyed MAC successfully");
}
pub fn challenge30() {
println!("[xxxx] Challenge 30: tbd");
}