Implement challenge 35
This commit is contained in:
@@ -61,4 +61,6 @@ fn main() {
|
||||
}
|
||||
set5::challenge33();
|
||||
set5::challenge34();
|
||||
set5::challenge35();
|
||||
set5::challenge36();
|
||||
}
|
||||
|
||||
105
src/set5.rs
105
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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user