Files
simple_crypto/src/dsa/private.rs

119 lines
4.8 KiB
Rust

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<Hash>(&self, m: &[u8]) -> DSASignature<Self::N>
where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac;
}
pub struct DSAPrivKey<Params,N>
{
pub(crate) params: Params,
pub(crate) x: N
}
pub enum DSAPrivate {
DSA1024Private(DSAPrivKey<L1024N160,U192>),
DSA2048SmallPrivate(DSAPrivKey<L2048N224,U256>),
DSA2048Private(DSAPrivKey<L2048N256,U256>),
DSA3072Private(DSAPrivKey<L3072N256,U256>)
}
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<Hash>(&self, m: &[u8]) -> DSASignature<$ntype>
where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: 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 = <Hash>::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::<Hash,$ntype>::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);