cryptopals/src/dsa.rs

122 lines
4.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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,
pub k: 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, 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> {
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, k })
}
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)
}
}
pub fn recover_x(params: &DsaParameters, msg: &Bytes, sig: &DsaSig) -> Result<BigNum, ErrorStack> {
// (s * k) - H(msg)
// x = ---------------- mod q
// r
let x = &(&rsa::invmod(&sig.r, &params.q)? * &(&(&sig.s * &sig.k) - &h(msg)?)) % &params.q;
Ok(x)
}
pub fn h(message: &Bytes) -> Result<BigNum, ErrorStack> {
let mut s1 = sha1::Sha1::default();
BigNum::from_slice(&(s1.hash(message).0))
}