Solve challenge 45 DSA parameter tampering
This commit is contained in:
15
src/dsa.rs
15
src/dsa.rs
@@ -59,13 +59,14 @@ impl DsaKeys {
|
||||
let mut k = BigNum::new()?;
|
||||
let mut r = BigNum::from_u32(0)?;
|
||||
let zero = BigNum::from_u32(0)?;
|
||||
while r == zero {
|
||||
// Choose an integer k randomly from { 1 … q − 1 }
|
||||
params.q.rand_range(&mut k)?;
|
||||
// Compute r := (g^k mod p) mod q. In the unlikely case that r=0, start again.
|
||||
r.mod_exp(¶ms.g, &k, ¶ms.p, &mut ctx)?;
|
||||
r = &r % ¶ms.q;
|
||||
}
|
||||
|
||||
// Choose an integer k randomly from { 1 … q − 1 }
|
||||
params.q.rand_range(&mut k)?;
|
||||
// Compute r := (g^k mod p) mod q.
|
||||
r.mod_exp(¶ms.g, &k, ¶ms.p, &mut ctx)?;
|
||||
r = &r % ¶ms.q;
|
||||
// In the unlikely case that r=0, crash.
|
||||
assert!(r != zero, "r is zero");
|
||||
|
||||
// Compute s := (k^(−1) * ( H ( m ) + x r ) ) mod q.
|
||||
let s = &(&rsa::invmod(&k, ¶ms.q)? * &(&h(msg)? + &(&self.x * &r))) % ¶ms.q;
|
||||
|
||||
@@ -75,4 +75,5 @@ fn main() {
|
||||
set6::challenge43().unwrap_or_else(|| println!("[fail] challenge 43"));
|
||||
set6::challenge44().unwrap_or_else(|| println!("[fail] challenge 44"));
|
||||
set6::challenge45().unwrap_or_else(|| println!("[fail] challenge 45"));
|
||||
set6::challenge46().unwrap_or_else(|| println!("[fail] challenge 46"));
|
||||
}
|
||||
|
||||
60
src/set6.rs
60
src/set6.rs
@@ -282,6 +282,64 @@ pub fn challenge44() -> Option<()> {
|
||||
}
|
||||
|
||||
pub fn challenge45() -> Option<()> {
|
||||
println!("[xxxx] Challenge 45: DSA parameter tampering");
|
||||
// Part 1: 0 mod p
|
||||
//
|
||||
// Use the parameters from the previous exercise, but substitute 0 for "g". Generate a
|
||||
// signature. You will notice something bad.
|
||||
//
|
||||
// Observation:
|
||||
//
|
||||
// - If g=0, because of r := (g^k mod p) mod q, it follows r=0.
|
||||
// - When verifying, v := ((g^u1 * y^u2) % p) % q).
|
||||
// - Therefore, v=0, and v == r is always true for any signature.
|
||||
//
|
||||
// Our implementation catches this case, both for signing and verifying.
|
||||
|
||||
// Part 2: 1 mod p
|
||||
let mut params = dsa::DsaParameters::new().ok()?;
|
||||
fn generate_magic_signature(
|
||||
params: &mut dsa::DsaParameters,
|
||||
) -> Result<dsa::DsaSig, ErrorStack> {
|
||||
let mut ctx = BigNumContext::new()?;
|
||||
|
||||
//Now, try (p+1) as "g". With this "g", you can generate a magic signature s, r for any DSA
|
||||
//public key that will validate against any string.
|
||||
params.g = ¶ms.p + &BigNum::from_u32(1)?;
|
||||
|
||||
// For arbitrary z:
|
||||
// r = ((y**z) % p) % q
|
||||
let mut r = BigNum::from_u32(0)?;
|
||||
let z = BigNum::from_u32(1337)?;
|
||||
r.mod_exp(¶ms.g, &z, ¶ms.p, &mut ctx)?;
|
||||
r = &r % ¶ms.q;
|
||||
|
||||
// r
|
||||
// s = --- % q
|
||||
// z
|
||||
let s = &rsa::invmod(&z, ¶ms.q)? * &r;
|
||||
|
||||
// k doesn't matter
|
||||
let k = BigNum::from_u32(0)?;
|
||||
|
||||
Ok(dsa::DsaSig { r, s, k })
|
||||
}
|
||||
|
||||
let sig = generate_magic_signature(&mut params).ok()?;
|
||||
let keys = dsa::DsaKeys::new(¶ms).ok()?;
|
||||
|
||||
let msg = Bytes::from_utf8("Hello, world");
|
||||
let result = keys.verify(¶ms, &msg, &sig).ok()?;
|
||||
assert!(result, "verify failed unexpectedly");
|
||||
|
||||
let msg = Bytes::from_utf8("Goodbye, world");
|
||||
let result = keys.verify(¶ms, &msg, &sig).ok()?;
|
||||
assert!(result, "verify failed unexpectedly");
|
||||
|
||||
println!("[okay] Challenge 45: DSA parameter tampering");
|
||||
Some(())
|
||||
}
|
||||
|
||||
pub fn challenge46() -> Option<()> {
|
||||
println!("[xxxx] Challenge 46: RSA parity oracle");
|
||||
None
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user