Implement DSA sign and verify to get started with challenge 43

This commit is contained in:
2022-12-18 14:11:46 -05:00
parent 6133d17f92
commit 6f936afa21
4 changed files with 121 additions and 6 deletions

105
src/dsa.rs Normal file
View File

@@ -0,0 +1,105 @@
use crate::bytes::Bytes;
use crate::rsa;
use crate::sha1;
use openssl::bn::BigNum;
use openssl::bn::BigNumContext;
use openssl::error::ErrorStack;
#[derive(Debug)]
pub struct DsaParameters {
pub p: BigNum,
pub q: BigNum,
pub g: BigNum,
}
#[derive(Debug)]
pub struct DsaKeys {
pub x: BigNum,
pub y: BigNum,
}
#[derive(Debug)]
pub struct DsaSig {
pub r: BigNum,
pub s: BigNum,
}
impl DsaParameters {
pub fn new() -> Result<Self, ErrorStack> {
Ok(Self {
p: BigNum::from_hex_str("800000000000000089e1855218a0e7dac38136ffafa72eda7859f2171e25e65eac698c1702578b07dc2a1076da241c76c62d374d8389ea5aeffd3226a0530cc565f3bf6b50929139ebeac04f48c3c84afb796d61e5a4f9a8fda812ab59494232c7d2b4deb50aa18ee9e132bfa85ac4374d7f9091abc3d015efc871a584471bb1")?,
q: BigNum::from_hex_str("f4f47f05794b256174bba6e9b396a7707e563c5b")?,
g: BigNum::from_hex_str("5958c9d3898b224b12672c0b98e06c60df923cb8bc999d119458fef538b8fa4046c8db53039db620c094c9fa077ef389b5322a559946a71903f990f1f7e0e025e2d7f7cf494aff1a0470f5b64c36b625a097f1651fe775323556fe00b3608c887892878480e99041be601a62166ca6894bdd41a7054ec89f756ba9fc95302291")?,
})
}
}
impl DsaKeys {
pub fn new(params: &DsaParameters) -> Result<Self, ErrorStack> {
let mut ctx = BigNumContext::new()?;
let mut x = BigNum::new()?;
let mut y = BigNum::new()?;
// Choose an integer x randomly from { 1 … q 1 }
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 })
}
pub fn sign(&self, params: &DsaParameters, msg: &Bytes) -> Result<DsaSig, ErrorStack> {
let mut ctx = BigNumContext::new()?;
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(&params.g, &k, &params.p, &mut ctx)?;
r = &r % &params.q;
}
// Compute s := (k^(1) * ( H ( m ) + x r ) ) mod q.
let s = &(&rsa::invmod(&k, &params.q)? * &(&h(msg)? + &(&self.x * &r))) % &params.q;
// In the unlikely case that s=0, crash.
assert!(s != zero, "s is zero");
Ok(DsaSig { r, s })
}
pub fn verify(
&self,
params: &DsaParameters,
msg: &Bytes,
sig: &DsaSig,
) -> Result<bool, ErrorStack> {
let mut ctx = BigNumContext::new()?;
let zero = BigNum::from_u32(0)?;
// Verify that 0 < r < q and 0 < s < q
if !(zero < sig.r && sig.r < params.q && zero < sig.s && sig.s < params.q) {
return Ok(false);
}
// Compute w := s^(1) mod q
let w = rsa::invmod(&sig.s, &params.q)?;
let u1 = &(&h(&msg)? * &w) % &params.q;
let u2 = &(&sig.r * &w) % &params.q;
// v := ((g^u1 * y^u2) % p) % q)
let mut v1 = BigNum::new()?;
v1.mod_exp(&params.g, &u1, &params.p, &mut ctx)?;
let mut v2 = BigNum::new()?;
v2.mod_exp(&self.y, &u2, &params.p, &mut ctx)?;
let v = &(&(&v1 * &v2) % &params.p) % &params.q;
// The signature is valid if and only if v = r
Ok(v == sig.r)
}
}
fn h(message: &Bytes) -> Result<BigNum, ErrorStack> {
let mut s1 = sha1::Sha1::default();
BigNum::from_slice(&(s1.hash(message).0))
}

View File

@@ -8,6 +8,7 @@ mod bytes;
mod bytes_base64;
mod cbc;
mod ctr;
mod dsa;
mod ecb;
mod md4;
mod mt19937;
@@ -62,12 +63,12 @@ fn main() {
set5::challenge33();
set5::challenge34();
set5::challenge35();
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::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"));
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"));

View File

@@ -583,6 +583,6 @@ pub fn challenge40() -> Option<()> {
// let c = rsa::rsa_padding_remove_pkcs1(&c, n_0.num_bytes()).ok()?;
assert_eq!(c, m, "cube root implementation did not work");
println!("[okay] Challenge 40: implement an E=3 RSA Broadcast attack");
println!("[okay] Challenge 40: implement an e=3 RSA Broadcast attack");
Some(())
}

View File

@@ -1,3 +1,5 @@
use crate::bytes::Bytes;
use crate::dsa;
use crate::rsa;
use num_bigint::BigUint;
use openssl::bn::BigNum;
@@ -96,5 +98,12 @@ pub fn challenge42() -> Option<()> {
pub fn challenge43() -> Option<()> {
println!("[xxxx] Challenge 43: TBD");
let msg = Bytes::from_utf8("hello, world!");
let params = dsa::DsaParameters::new().ok()?;
let keys = dsa::DsaKeys::new(&params).ok()?;
let s = keys.sign(&params, &msg).ok()?;
let r = keys.verify(&params, &msg, &s).ok()?;
assert!(r, "verify failed unexpectedly");
Some(())
}