From 9a5544f5a03504278f97b6f365393eed2d439fdb Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Sat, 15 Oct 2022 14:53:39 -0400 Subject: [PATCH] Implement E=3 RSA broadcast attack to finish set 5 --- src/main.rs | 12 +++++++----- src/rsa.rs | 4 ++-- src/set5.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- src/set6.rs | 4 ++++ 4 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 src/set6.rs diff --git a/src/main.rs b/src/main.rs index 07a06dd..69d49b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ mod set2; mod set3; mod set4; mod set5; +mod set6; mod sha1; mod srp; mod utils; @@ -61,10 +62,11 @@ fn main() { set5::challenge33(); set5::challenge34(); set5::challenge35(); - set5::challenge36(); - set5::challenge37().unwrap_or_else(|| println!("[FAIL] challenge 37")); + set5::challenge36().unwrap_or_else(|| println!("[fail] challenge 36")); + set5::challenge37().unwrap_or_else(|| println!("[fail] challenge 37")); } - set5::challenge38().unwrap_or_else(|| println!("[FAIL] challenge 38")); - set5::challenge39().unwrap_or_else(|| println!("[FAIL] challenge 39")); - set5::challenge40().unwrap_or_else(|| println!("[FAIL] challenge 40")); + set5::challenge38().unwrap_or_else(|| println!("[fail] challenge 38")); + set5::challenge39().unwrap_or_else(|| println!("[fail] challenge 39")); + set5::challenge40().unwrap_or_else(|| println!("[fail] challenge 40")); + set6::challenge41().unwrap_or_else(|| println!("[fail] challenge 41")); } diff --git a/src/rsa.rs b/src/rsa.rs index 0c7d2b1..b65c72a 100644 --- a/src/rsa.rs +++ b/src/rsa.rs @@ -29,8 +29,8 @@ impl Keypair { } pub struct RsaPublicKey { - e: BigNum, - n: BigNum, + pub e: BigNum, + pub n: BigNum, } pub struct RsaPrivateKey { diff --git a/src/set5.rs b/src/set5.rs index 67309c3..803c61c 100644 --- a/src/set5.rs +++ b/src/set5.rs @@ -537,6 +537,50 @@ pub fn challenge39() -> Option<()> { } pub fn challenge40() -> Option<()> { - // println!("[xxxx] Challenge 40: implement an E=3 RSA Broadcast attack"); - None + let m = BigNum::from_u32(1337).ok()?; + + // 1. Capturing any 3 of the ciphertexts and their corresponding pubkeys + let (p_0, _) = rsa::rsa_gen_keys().ok()?; + let (p_1, _) = rsa::rsa_gen_keys().ok()?; + let (p_2, _) = rsa::rsa_gen_keys().ok()?; + let c_0 = rsa::rsa_encrypt(&m, &p_0).ok()?; + let c_1 = rsa::rsa_encrypt(&m, &p_1).ok()?; + let c_2 = rsa::rsa_encrypt(&m, &p_2).ok()?; + + // 2. Using the CRT to solve for the number represented by the three ciphertexts (which are + // residues mod their respective pubkeys) + let rsa::RsaPublicKey { e: _, n: n_0 } = p_0; + let rsa::RsaPublicKey { e: _, n: n_1 } = p_1; + let rsa::RsaPublicKey { e: _, n: n_2 } = p_2; + + // N_012 is the product of all three moduli + let n_012 = &(&n_0 * &n_1) * &n_2; + let m_s_0 = &n_1 * &n_2; + let m_s_1 = &n_0 * &n_2; + let m_s_2 = &n_0 * &n_1; + + // result = + // (c_0 * m_s_0 * invmod(m_s_0, n_0)) + + // (c_1 * m_s_1 * invmod(m_s_1, n_1)) + + // (c_2 * m_s_2 * invmod(m_s_2, n_2)) mod N_012 + let result = &(&(&(&(&c_0 * &m_s_0) * &rsa::invmod(&m_s_0, &n_0).ok()?) + + &(&(&c_1 * &m_s_1) * &rsa::invmod(&m_s_1, &n_1).ok()?)) + + &(&(&c_2 * &m_s_2) * &rsa::invmod(&m_s_2, &n_2).ok()?)) + % &n_012; + + // 3. Taking the cube root of the resulting number + fn cube_root(n: &BigNum) -> Option { + let b = BigUint::from_bytes_be(&n.to_vec()); + let b = b.nth_root(3); + BigNum::from_slice(&b.to_bytes_be()).ok() + } + + let m_cubed = &(&m * &m) * &m; + assert_eq!(m_cubed, result, "CRT implementation did not work"); + + let c = cube_root(&result)?; + assert_eq!(c, m, "cube root implementation did not work"); + + println!("[okay] Challenge 40: implement an E=3 RSA Broadcast attack"); + Some(()) } diff --git a/src/set6.rs b/src/set6.rs new file mode 100644 index 0000000..a4cdb30 --- /dev/null +++ b/src/set6.rs @@ -0,0 +1,4 @@ +pub fn challenge41() -> Option<()> { + // println!("[xxxx] Challenge 41: TBD"); + None +}