Solve challenge 43

main
Felix Martin 2023-01-02 14:42:45 -05:00
parent 86d4442b36
commit e3ab3af101
3 changed files with 87 additions and 6 deletions

View File

@ -44,7 +44,14 @@ impl DsaKeys {
params.q.rand_range(&mut x)?;
// Compute y := g^x mod p
y.mod_exp(&params.g, &x, &params.p, &mut ctx)?;
Ok(Self { x: x, y: y })
Ok(Self { x, y })
}
pub fn new_from_x(params: &DsaParameters, x: BigNum) -> Result<Self, ErrorStack> {
let mut ctx = BigNumContext::new()?;
let mut y = BigNum::new()?;
y.mod_exp(&params.g, &x, &params.p, &mut ctx)?;
Ok(Self { x, y })
}
pub fn sign(&self, params: &DsaParameters, msg: &Bytes) -> Result<DsaSig, ErrorStack> {
@ -108,7 +115,7 @@ pub fn recover_x(params: &DsaParameters, msg: &Bytes, sig: &DsaSig) -> Result<Bi
Ok(x)
}
fn h(message: &Bytes) -> Result<BigNum, ErrorStack> {
pub fn h(message: &Bytes) -> Result<BigNum, ErrorStack> {
let mut s1 = sha1::Sha1::default();
BigNum::from_slice(&(s1.hash(message).0))
}

View File

@ -68,8 +68,9 @@ fn main() {
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"));
set6::challenge42().unwrap_or_else(|| println!("[fail] challenge 42"));
}
set6::challenge41().unwrap_or_else(|| println!("[fail] challenge 41"));
set6::challenge42().unwrap_or_else(|| println!("[fail] challenge 42"));
set6::challenge43().unwrap_or_else(|| println!("[fail] challenge 43"));
set6::challenge44().unwrap_or_else(|| println!("[fail] challenge 44"));
}

View File

@ -96,8 +96,55 @@ pub fn challenge42() -> Option<()> {
Some(())
}
pub mod challenge43 {
use crate::bytes::Bytes;
use crate::dsa;
use crate::rsa;
use openssl::bn::BigNum;
use openssl::error::ErrorStack;
pub fn recover_x() -> Result<Option<BigNum>, ErrorStack> {
// I used the parameters above.
let params = dsa::DsaParameters::new()?;
// I generated a keypair. My pubkey y is given:
let y = BigNum::from_hex_str("84ad4719d044495496a3201c8ff484feb45b962e7302e56a392aee4abab3e4bdebf2955b4736012f21a08084056b19bcd7fee56048e004e44984e2f411788efdc837a0d2e5abb7b555039fd243ac01f0fb2ed1dec568280ce678e931868d23eb095fde9d3779191b8c0299d6e07bbb283e6633451e535c45513b2d33c99ea17")?;
// I signed the following message.
let msg = Bytes::from_utf8("For those that envy a MC it can be hazardous to your health\nSo be friendly, a matter of life and death, just like a etch-a-sketch\n");
// My SHA1 for this string was d2d0714f014a9784047eaeccf956520045c45265.
assert_eq!(
dsa::h(&msg)?,
BigNum::from_hex_str("d2d0714f014a9784047eaeccf956520045c45265")?
);
// They provide s and r as decimal integers and not hex strings. I
// converted the decimals to hex. I took me a couple of hours to figure
// that out.
let mut sig = dsa::DsaSig {
r: BigNum::from_hex_str("60019cacdc56eedf8e080984bfa898c8c5c419a8")?,
s: BigNum::from_hex_str("961f2062efc3c68db965a90c924cf76580ec1bbc")?,
k: BigNum::from_u32(0)?,
};
let msg_h = dsa::h(&msg)?;
let r_inv = rsa::invmod(&sig.r, &params.q)?;
// I signed this string with a broken implemention of DSA that generated "k"
// values between 0 and 2^16. What's my private key?
for k in 0..2_u32.pow(16) {
// I get the signature.
sig.k = BigNum::from_u32(k)?;
let x = &(&r_inv * &(&(&sig.s * &sig.k) - &msg_h)) % &params.q;
let keys = dsa::DsaKeys::new_from_x(&params, x)?;
if y == keys.y {
return Ok(Some(keys.x));
}
}
Ok(None)
}
}
pub fn challenge43() -> Option<()> {
println!("[xxxx] Challenge 43: TBD");
println!("[okay] Challenge 43: DSA key recovery from nonce");
let msg = Bytes::from_utf8("hello, world!");
let params = dsa::DsaParameters::new().ok()?;
let keys = dsa::DsaKeys::new(&params).ok()?;
@ -106,7 +153,33 @@ pub fn challenge43() -> Option<()> {
assert!(result, "verify failed unexpectedly");
let recovered_x = dsa::recover_x(&params, &msg, &sig).ok()?;
assert_eq!(recovered_x, keys.x, "DSA recovery failed");
assert_eq!(recovered_x, keys.x, "DSA x recovery failed");
let recovered_keys = dsa::DsaKeys::new_from_x(&params, recovered_x).ok()?;
assert_eq!(recovered_keys.y, keys.y, "DSA y recovery failed");
let msg = Bytes::from_utf8("hello world!");
let result = keys.verify(&params, &msg, &sig).ok()?;
assert!(!result, "verify succeeded unexpectedly");
// Its SHA-1 fingerprint (after being converted to hex) is:
// 0954edd5e0afe5542a4adf012611a91912a3ec16
let x = challenge43::recover_x().ok()??;
let x_as_hex_str = x.to_hex_str().ok()?.to_ascii_lowercase();
assert_eq!(
dsa::h(&Bytes::from_utf8(x_as_hex_str.as_ref())).ok()?,
BigNum::from_hex_str("0954edd5e0afe5542a4adf012611a91912a3ec16").ok()?,
"Recovery from none failed"
);
Some(())
}
pub fn challenge44() -> Option<()> {
println!("[xxxx] Challenge 44: DSA nonce recovery from repeated nonce");
let msg = Bytes::from_utf8("hello, world!");
let params = dsa::DsaParameters::new().ok()?;
let keys = dsa::DsaKeys::new(&params).ok()?;
let sig = keys.sign(&params, &msg).ok()?;
let result = keys.verify(&params, &msg, &sig).ok()?;
assert!(result, "verify failed unexpectedly");
None
}