100 lines
3.5 KiB
Rust
100 lines
3.5 KiB
Rust
use cryptonum::unsigned::*;
|
|
use cryptonum::signed::ModInv;
|
|
use digest::Digest;
|
|
use dsa::params::*;
|
|
use dsa::rfc6979::DSASignature;
|
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,ToASN1};
|
|
use std::cmp::min;
|
|
use utils::TranslateNums;
|
|
|
|
pub trait DSAPublicKey {
|
|
type Params : DSAParameters;
|
|
type L;
|
|
type N;
|
|
|
|
/// Generate a new public key given the parameters and public value.
|
|
fn new(params: Self::Params, y: Self::L) -> Self;
|
|
/// Verify the given signature against the given message, using the
|
|
/// appropriate hash function.
|
|
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<Self::N>) -> bool
|
|
where Hash: Digest;
|
|
}
|
|
|
|
pub struct DSAPubKey<Params,L> {
|
|
pub(crate) params: Params,
|
|
pub(crate) y: L
|
|
}
|
|
|
|
pub enum DSAPublic {
|
|
DSAPublicL1024N160(DSAPubKey<L1024N160,U1024>),
|
|
DSAPublicL2048N224(DSAPubKey<L2048N224,U2048>),
|
|
DSAPublicL2048N256(DSAPubKey<L2048N256,U2048>),
|
|
DSAPublicL3072N256(DSAPubKey<L3072N256,U3072>)
|
|
}
|
|
|
|
macro_rules! pubkey_impls {
|
|
($ptype: ident, $ltype: ident, $ntype: ident, $dbl: ident, $bdbl: ident) => {
|
|
impl DSAPublicKey for DSAPubKey<$ptype,$ltype>
|
|
{
|
|
type Params = $ptype;
|
|
type L = $ltype;
|
|
type N = $ntype;
|
|
|
|
fn new(params: $ptype, y: $ltype) -> DSAPubKey<$ptype,$ltype>
|
|
{
|
|
DSAPubKey{ params, y }
|
|
}
|
|
|
|
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<$ntype>) -> bool
|
|
where Hash: Digest
|
|
{
|
|
if sig.r >= self.params.q {
|
|
return false;
|
|
}
|
|
if sig.s >= self.params.q {
|
|
return false;
|
|
}
|
|
// w = (s')^-1 mod q;
|
|
if let Some(w) = sig.s.modinv(&self.params.q) {
|
|
// z = the leftmost min(N, outlen) bits of Hash(M').
|
|
let mut digest_bytes = <Hash>::digest(m).to_vec();
|
|
let len = min(digest_bytes.len(), $ptype::n_size() / 8);
|
|
digest_bytes.truncate(len);
|
|
let z = $ntype::from_bytes(&digest_bytes);
|
|
// u1 = (zw) mod q
|
|
let qdbl = $dbl::from(&self.params.q);
|
|
let u1 = $ltype::from( (&z * &w) % &qdbl );
|
|
// u2 = (rw) mod q
|
|
let u2 = $ltype::from( (&sig.r * &w) % &qdbl );
|
|
// v = (((g)^u1(y)^u2) mod p) mod q
|
|
let v_1 = self.params.g.modexp(&u1, &self.params.p);
|
|
let v_2 = self.y.modexp(&u2, &self.params.p);
|
|
let bigp = $bdbl::from(&self.params.p);
|
|
let v_first_mod = (v_1 * v_2) % bigp;
|
|
let v = $ltype::from(v_first_mod) % $ltype::from(&self.params.q);
|
|
// if v = r, then the signature is verified
|
|
return $ntype::from(v) == sig.r
|
|
}
|
|
|
|
false
|
|
}
|
|
}
|
|
|
|
impl ToASN1 for DSAPubKey<$ptype,$ltype> {
|
|
type Error = ASN1EncodeErr;
|
|
|
|
fn to_asn1_class(&self, c: ASN1Class)
|
|
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
|
{
|
|
let inty = self.y.to_num();
|
|
let yblock = ASN1Block::Integer(c, 0, inty);
|
|
Ok(vec![yblock])
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
pubkey_impls!(L1024N160, U1024, U192, U384, U2048);
|
|
pubkey_impls!(L2048N224, U2048, U256, U512, U4096);
|
|
pubkey_impls!(L2048N256, U2048, U256, U512, U4096);
|
|
pubkey_impls!(L3072N256, U3072, U256, U512, U6144); |