From 49d590ea4462e16ed3f10592f1f30bd46452af85 Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Sat, 3 Sep 2022 08:59:16 -0400 Subject: [PATCH] Implement challenge 35 --- src/main.rs | 2 + src/set5.rs | 105 +++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 93 insertions(+), 14 deletions(-) diff --git a/src/main.rs b/src/main.rs index f46cdf7..63ac4d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -61,4 +61,6 @@ fn main() { } set5::challenge33(); set5::challenge34(); + set5::challenge35(); + set5::challenge36(); } diff --git a/src/set5.rs b/src/set5.rs index 470b715..1f02677 100644 --- a/src/set5.rs +++ b/src/set5.rs @@ -1,7 +1,6 @@ use crate::bytes::Bytes; -use crate::cbc; use crate::rsa; -use crate::sha1::Sha1; +use num_bigint::BigUint; use num_bigint::ToBigUint; use rand::Rng; @@ -155,6 +154,19 @@ mod challenge34 { message } } + + pub fn decrypt_with_s(cipher: &Bytes, s: &BigUint) -> Bytes { + const BLOCK_SIZE: usize = 16; + let mut sha1 = Sha1::default(); + let key = Bytes(sha1.hash(&Bytes(s.to_bytes_be())).0[0..16].to_vec()); + + let cipher_len = cipher.len(); + let iv = Bytes(cipher.0[(cipher_len - BLOCK_SIZE)..cipher_len].to_vec()); + let cipher = Bytes(cipher.0[0..cipher_len - BLOCK_SIZE].to_vec()); + let mut message = cbc::decrypt(&key, &iv, &cipher); + message.remove_pkcs7(BLOCK_SIZE); + message + } } pub fn challenge34() { @@ -220,23 +232,88 @@ pub fn challenge34() { } fn attack(cipher: &Bytes) -> Bytes { - const BLOCK_SIZE: usize = 16; - // Do the DH math on this quickly to see what that does to the predictability of the key. - // Math: with p = A; s = (A ** b) % p becomes (p ** b) % p = 0 => s = 0 + // With p = A; s = (A ** b) % p becomes (p ** b) % p = 0 => s = 0 let s = 0_u8.to_biguint().unwrap(); - let mut sha1 = Sha1::default(); - let key = Bytes(sha1.hash(&Bytes(s.to_bytes_be())).0[0..16].to_vec()); - - let cipher_len = cipher.len(); - let iv = Bytes(cipher.0[(cipher_len - BLOCK_SIZE)..cipher_len].to_vec()); - let cipher = Bytes(cipher.0[0..cipher_len - BLOCK_SIZE].to_vec()); - let mut message = cbc::decrypt(&key, &iv, &cipher); - message.remove_pkcs7(BLOCK_SIZE); - message + challenge34::decrypt_with_s(cipher, &s) } echo(); echo_mitm(); println!("[okay] Challenge 34: implement MITM key-fixing attack on DH"); } + +pub fn challenge35() { + fn echo(message: &Bytes, g: &BigUint, p: &BigUint) -> (Bytes, Bytes) { + let mut a = challenge34::Bot::new(p.clone(), &g); + let mut b = challenge34::Bot::new(p.clone(), &g); + a.exchange_keys(&b.exchange_keys(&a.get_public_key())); + assert_eq!(a.s, b.s, "crypto is broken"); + + let cipher_a = a.encrypt(&message); + let message_b = b.decrypt(&cipher_a); + let cipher_b = b.encrypt(&message_b); + let roundtrip = a.decrypt(&cipher_b); + assert_eq!(*message, roundtrip, "we broke it fam"); + (cipher_a, cipher_b) + } + + fn attack_g1(cipher: &Bytes) -> Bytes { + // A = (g ** a) % p, g = 1 -> A = 1 + // s = (A ** b) % p, A = 1 -> s = 1 + let s = 1_u8.to_biguint().unwrap(); + challenge34::decrypt_with_s(cipher, &s) + } + + fn attack_g_is_p(cipher: &Bytes) -> Bytes { + // A = (g ** a) % p, g = p -> A = 0 + // s = (A ** b) % p, A = 0 -> s = 0 + let s = 0_u8.to_biguint().unwrap(); + challenge34::decrypt_with_s(cipher, &s) + } + + fn attack_g_is_p_minus_one(cipher: &Bytes, p: &BigUint) -> Bytes { + // A = (g ** a) % p, g = p - 1 -> A = 1 | (p - 1) + // s = (A ** b) % p, A = 1 | (p - 1) -> s = 1 | (p - 1) + let s1 = 1_u8.to_biguint().unwrap(); + let s2 = p - 1_u8.to_biguint().unwrap(); + let m1 = challenge34::decrypt_with_s(cipher, &s1); + let m2 = challenge34::decrypt_with_s(cipher, &s2); + + match m1.ascii_score().cmp(&m2.ascii_score()) { + std::cmp::Ordering::Greater => m1, + std::cmp::Ordering::Less => m2, + std::cmp::Ordering::Equal => panic!("how can they be equal?"), + } + } + + // Do the MITM attack again, but play with "g". Write attacks for each. + let m = Bytes::from_utf8("Quick to the point, to the point, no faking"); + let p = challenge33::load_large_prime(); + let g = 2_u8.to_biguint().unwrap(); + echo(&m, &g, &p); + + // g = 1 + let g = 1_u8.to_biguint().unwrap(); + let (c1, c2) = echo(&m, &g, &p); + assert_eq!(attack_g1(&c1), m, "failed to attack g = 1"); + assert_eq!(attack_g1(&c2), m, "failed to attack g = 1"); + + // g = p + let g = p.clone(); + let (c1, c2) = echo(&m, &g, &p); + assert_eq!(attack_g_is_p(&c1), m, "failed to attack g = p"); + assert_eq!(attack_g_is_p(&c2), m, "failed to attack g = p"); + + // g = p - 1 + let g = p.clone() - 1_u8.to_biguint().unwrap(); + let (c1, c2) = echo(&m, &g, &p); + assert_eq!(attack_g_is_p_minus_one(&c1, &p), m, "failed g = p - 1"); + assert_eq!(attack_g_is_p_minus_one(&c2, &p), m, "failed g = p - 1"); + + println!("[okay] Challenge 35: implement MITM with malicious g attack on DH"); +} + +pub fn challenge36() { + println!("[xxxx] Challenge 36: xxxx"); +}