123 lines
4.1 KiB
Rust
123 lines
4.1 KiB
Rust
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(¶ms.g, &x, ¶ms.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(¶ms.g, &x, ¶ms.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)?;
|
||
|
||
// 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;
|
||
|
||
// 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, ¶ms.q)?;
|
||
let u1 = &(&h(&msg)? * &w) % ¶ms.q;
|
||
let u2 = &(&sig.r * &w) % ¶ms.q;
|
||
|
||
// v := ((g^u1 * y^u2) % p) % q)
|
||
let mut v1 = BigNum::new()?;
|
||
v1.mod_exp(¶ms.g, &u1, ¶ms.p, &mut ctx)?;
|
||
let mut v2 = BigNum::new()?;
|
||
v2.mod_exp(&self.y, &u2, ¶ms.p, &mut ctx)?;
|
||
let v = &(&(&v1 * &v2) % ¶ms.p) % ¶ms.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, ¶ms.q)? * &(&(&sig.s * &sig.k) - &h(msg)?)) % ¶ms.q;
|
||
Ok(x)
|
||
}
|
||
|
||
pub fn h(message: &Bytes) -> Result<BigNum, ErrorStack> {
|
||
let mut s1 = sha1::Sha1::default();
|
||
BigNum::from_slice(&(s1.hash(message).0))
|
||
}
|