use cryptonum::unsigned::*; use cryptonum::signed::ModInv; use digest::{BlockInput,Digest,Input,FixedOutput,Reset}; use dsa::params::*; use dsa::rfc6979::*; use hmac::{Hmac,Mac}; pub trait DSAPrivateKey { type Params; type L; type N; /// Generate a new private key using the given DSA parameters and private /// key value. fn new(params: Self::Params, x: Self::N) -> Self; /// Generate a DSA signature for the given message, using the appropriate /// hash included in the type invocation. fn sign(&self, m: &[u8]) -> DSASignature where Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset, Hmac: Mac; } pub struct DSAPrivKey { pub(crate) params: Params, pub(crate) x: N } pub enum DSAPrivate { DSA1024Private(DSAPrivKey), DSA2048SmallPrivate(DSAPrivKey), DSA2048Private(DSAPrivKey), DSA3072Private(DSAPrivKey) } macro_rules! privkey_impls { ($ptype: ident, $ltype: ident, $ntype: ident, $big: ident, $bigger: ident, $biggest: ident) => { impl DSAPrivateKey for DSAPrivKey<$ptype,$ntype> { type Params = $ptype; type L = $ltype; type N = $ntype; fn new(params: $ptype, x: $ntype) -> DSAPrivKey<$ptype,$ntype> { DSAPrivKey{ params, x } } fn sign(&self, m: &[u8]) -> DSASignature<$ntype> where Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset, Hmac: Mac { // This algorithm is per RFC 6979, which has a nice, relatively // straightforward description of how to do DSA signing. // // 1. H(m) is transformed into an integer modulo q using the bits2int // transform and an extra modular reduction: // // h = bits2int(H(m)) mod q // // As was noted in the description of bits2octets, the extra // modular reduction is no more than a conditional subtraction. // let h1 = ::digest(m); let n = $ptype::n_size(); let h0: $ntype = bits2int(&h1, $ptype::n_size()); let q = &self.params.q; let h = h0 % q; // 2. A random value modulo q, dubbed k, is generated. That value // shall not be 0; hence, it lies in the [1, q-1] range. Most // of the remainder of this document will revolve around the // process used to generate k. In plain DSA or ECDSA, k should // be selected through a random selection that chooses a value // among the q-1 possible values with uniform probability. for k in KIterator::::new(&h1, n, q, &self.x) { // 3. A value r (modulo q) is computed from k and the key // parameters: // * For DSA: // r = g^k mod p mod q // // (The exponentiation is performed modulo p, yielding a // number between 0 and p-1, which is then further reduced // modulo q.) // * For ECDSA ... // // If r turns out to be zero, a new k should be selected and r // computed again (this is an utterly improbable occurrence). let bigk = $ltype::from(&k); let bigr = self.params.g.modexp(&bigk, &self.params.p) % $ltype::from(q); if bigr.is_zero() { continue; } let r = $ntype::from(bigr); // 4. The value s (modulo q) is computed: // // s = (h+x*r)/k mod q // // The pair (r, s) is the signature. if let Some(kinv) = k.modinv(&q) { let xr = &self.x * &r; let top = xr + $big::from(&h); let left = top * $bigger::from(kinv); let bigs = left % $biggest::from(q); return DSASignature::new(r, $ntype::from(bigs)); } } panic!("The world is broken; couldn't find a k in sign()."); } } }; } privkey_impls!(L1024N160, U1024, U192, U384, U448, U896); privkey_impls!(L2048N224, U2048, U256, U512, U576, U1152); privkey_impls!(L2048N256, U2048, U256, U512, U576, U1152); privkey_impls!(L3072N256, U3072, U256, U512, U576, U1152);