From 62cb2768880d5f6c9b1c637895960e78aee3c6f4 Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Sat, 8 Dec 2018 10:59:14 -0600 Subject: [PATCH] DSA support! --- Cargo.toml | 1 + src/dsa/errors.rs | 20 ++ src/dsa/mod.rs | 67 ++++++ src/dsa/params.rs | 191 ++++++++++++++++ src/dsa/private.rs | 111 ++++++++++ src/dsa/public.rs | 87 ++++++++ src/dsa/rfc6979.rs | 365 ++++++++++++++++++++++++++++++ src/dsa/tests.rs | 536 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 8 +- src/rsa/public.rs | 28 +-- src/utils.rs | 18 +- 11 files changed, 1409 insertions(+), 23 deletions(-) create mode 100644 src/dsa/errors.rs create mode 100644 src/dsa/mod.rs create mode 100644 src/dsa/params.rs create mode 100644 src/dsa/private.rs create mode 100644 src/dsa/public.rs create mode 100644 src/dsa/rfc6979.rs create mode 100644 src/dsa/tests.rs diff --git a/Cargo.toml b/Cargo.toml index f246537..048598f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ repository = "https://github.com/acw/simple_crypto" byteorder = "^1.2.7" cryptonum = { path = "../cryptonum" } digest = "^0.8.0" +hmac = "^0.7.0" num = "^0.2.0" rand = "^0.6.0" sha-1 = "^0.8.1" diff --git a/src/dsa/errors.rs b/src/dsa/errors.rs new file mode 100644 index 0000000..27c1e9e --- /dev/null +++ b/src/dsa/errors.rs @@ -0,0 +1,20 @@ +use simple_asn1::ASN1DecodeErr; +use rand; + +#[derive(Debug)] +pub enum DSAError { + RandomGenError(rand::Error), + ASN1DecodeErr(ASN1DecodeErr) +} + +impl From for DSAError { + fn from(e: rand::Error) -> DSAError { + DSAError::RandomGenError(e) + } +} + +impl From for DSAError { + fn from(e: ASN1DecodeErr) -> DSAError { + DSAError::ASN1DecodeErr(e) + } +} \ No newline at end of file diff --git a/src/dsa/mod.rs b/src/dsa/mod.rs new file mode 100644 index 0000000..a44e4a3 --- /dev/null +++ b/src/dsa/mod.rs @@ -0,0 +1,67 @@ +mod errors; +mod params; +mod private; +mod public; +mod rfc6979; +#[cfg(test)] +mod tests; + +pub use self::params::*; +pub use self::private::*; +pub use self::public::*; + +use cryptonum::unsigned::*; +use rand::Rng; +use rand::distributions::Standard; + +pub struct DSAKeyPair +{ + pub private: DSAPrivKey, + pub public: DSAPubKey +} + +pub trait DSAKeyGeneration

+{ + fn generate(params: &P, rng: &mut G) -> Self; +} + +macro_rules! generate_dsa_pair { + ($ptype: ident, $ltype: ident, $ntype: ident, $nbig: ident) => { + impl DSAKeyGeneration<$ptype> for DSAKeyPair<$ptype,$ltype,$ntype> + where + DSAPrivKey<$ptype,$ntype>: DSAPrivateKey<$ptype,$ltype,$ntype>, + { + fn generate(params: &$ptype, rng: &mut G) -> Self + { + // 1. N = len(q); L = len(p); + let n = $ptype::n_size(); + // 2. If the (L,N) pair is invalid, then return an ERROR indicator, + // Invalid_x, and Invalid_y. + // 3. requested_security_strength = the security strength associated + // with the (L, N) pair; see SP 800-57. + // 4. Obtain a string of N+64 returned_bits from an RBG with a security + // strength of requested_security_strength or more. If an ERROR + // indication is returned, then return an ERROR indication, + // Invalid_x, and Invalid_y. + let returned_bits: Vec = rng.sample_iter(&Standard).take(n + 8).collect(); + // 5. Convert returned_bits to the (non-negative) integer c. + let c = $nbig::from_bytes(&returned_bits); + // 6. x = (c mod (q-1)) + 1. + let one = $nbig::from(1 as u64); + let qbig = $nbig::from(¶ms.q); + let x = $ntype::from( (&c % (&qbig - &one)) + &one ); + // 7. y = g^x mod p + let y = params.g.modexp(&$ltype::from(&x), ¶ms.p); + // 8. Return SUCCESS, x, and y. + let private = DSAPrivKey::new(params.clone(), x); + let public = DSAPubKey::new(params.clone(), y); + DSAKeyPair { private, public } + } + } + }; +} + +generate_dsa_pair!(L1024N160, U1024, U192, U256); +generate_dsa_pair!(L2048N224, U2048, U256, U384); +generate_dsa_pair!(L2048N256, U2048, U256, U384); +generate_dsa_pair!(L3072N256, U3072, U256, U384); \ No newline at end of file diff --git a/src/dsa/params.rs b/src/dsa/params.rs new file mode 100644 index 0000000..f808b7c --- /dev/null +++ b/src/dsa/params.rs @@ -0,0 +1,191 @@ +use cryptonum::unsigned::{CryptoNum,Decoder,Encoder,ModExp,PrimeGen}; +use cryptonum::unsigned::{U192,U256,U1024,U2048,U3072}; +use digest::Digest; +use sha2::Sha256; +use rand::Rng; + +pub trait DSAParameters +{ + fn new(p: L, g: L, q: N) -> Self; + fn generate(rng: &mut G) -> Self; + fn n_size() -> usize; + fn l_size() -> usize; + + fn n_bits(&self) -> usize { + Self::n_size() + } +} + +macro_rules! generate_parameters { + ($name: ident, $ltype: ident, $ntype: ident, $l: expr, $n: expr) => { + #[derive(Clone)] + pub struct $name { + pub p: $ltype, + pub g: $ltype, + pub q: $ntype + } + + impl DSAParameters<$ltype,$ntype> for $name + { + fn new(p: $ltype, g: $ltype, q: $ntype) -> $name + { + $name{ p: p, g: g, q: q } + } + + fn generate(rng: &mut G) -> $name + { + let (p, q, _, _) = $name::generate_primes(rng); + let g = $name::generate_g(rng, &p, &q); + $name{ p: p, g: g, q: q } + } + + fn l_size() -> usize { + $l + } + + fn n_size() -> usize { + $n + } + } + + impl $name + { + fn generate_primes(rng: &mut G) -> ($ltype,$ntype,U256,usize) + { + // This is A.1.1.2 from FIPS 186-4, with seedlen hardcoded to 256 + // (since that's guaranteed to be >= N), and with the hash + // hardcoded as SHA-256. + #[allow(non_snake_case)] + let L = $ltype::bit_length(); + #[allow(non_snake_case)] + let N = $ntype::bit_length(); + let seedlen = 256; + let outlen = 256; + // + // 1. Check that the (L,N) pair is in the list of acceptable + // (L,N) pairs (see Section 4.2). If the pair is not in the + // list, then return INVALID. + // [This is always true.] + // + // 2. If (seedlen < N), then return INVALID. + // [This is always true.] + // + // 3. n = L/outlen – 1. + let n = ((L + 255) / 256) - 1; + // 4. b = L – 1 – (n ∗ outlen). + let b = L - 1 - (n * outlen); + loop { + // 5. Get an arbitrary sequence of seedlen bits as the + // domain_parameter_seed. + let domain_parameter_seed: U256 = rng.gen(); + // 6. U = Hash (domain_parameter_seed) mod 2^(N–1). + let mut ubytes = hash(&domain_parameter_seed, 32); + while ubytes.len() > (N / 8) { ubytes.remove(0); } + #[allow(non_snake_case)] + let U = $ntype::from_bytes(&ubytes); + // 7. q = 2^(N–1) + U + 1 – (U mod 2). + let ulow = if U.is_even() { 0 } else { 1 }; + let mut q = $ntype::from(1u64) << (N - 1); + q += U; + q += $ntype::from(1u64 + ulow); + // 8. Test whether or not q is prime as specified in Appendix C.3. + let q_is_prime = q.probably_prime(rng, 40); + // 9. If q is not a prime, then go to step 5. + if !q_is_prime { + continue; + } + // 10. offset = 1. + let mut offset = 1; + // 11. For counter = 0 to (4L – 1) do + for counter in 0..(4*L)-1 { + // 11.1 For j = 0 to n do + // Vj = Hash ((domain_parameter_seed + offset + j) mod 2^seedlen). + #[allow(non_snake_case)] + let mut V = Vec::new(); + for j in 0..n { + let val = &domain_parameter_seed + U256::from(offset + j); + let bytes = hash(&val, 32); + assert_eq!(seedlen, bytes.len()); + V.push(bytes); + } + // 11.2 W = V_0 + ( V_1 ∗ 2^outlen) + ... + ( V_(n–1) ∗ 2^(n –1) ∗ outlen) + ((V_n mod 2^b) ∗ 2^(n ∗ outlen). + #[allow(non_snake_case)] + let mut W = $ltype::zero(); + for (idx, val) in V.iter().enumerate() { + if idx < n { + let mut base = val.clone(); + let baselen = base.len(); + base.resize(baselen + (idx * (outlen / 8)), 0); + W += $ltype::from_bytes(&base); + } else { + let base = $ltype::from_bytes(val); + let twob = $ltype::from(1u64) << b; + let val = base % twob; + W += val << (n * outlen); + } + } + // 11.3 X = W + 2^(L – 1). + // Comment: 0 ≤ W < 2 L – 1 ; hence, 2 L – 1 ≤ X < 2 L . + #[allow(non_snake_case)] + let mut X = $ltype::from(1u64) << (L - 1); + X += W; + // 11.4 c = X mod 2q. + let c = &X % ($ltype::from(&q) << 1); + // 11.5 p = X – ( c – 1). + // Comment: p ≡ 1 ( mod 2 q) . + let p = &X - (c - $ltype::from(1u64)); + // 11.6 If ( p < 2L – 1), then go to step 11.9. + if p >= $ltype::from((2*L) - 1) { + // 11.7 Test whether or not p is prime as specified in Appendix C .3. + if p.probably_prime(rng, 40) { + // 11.8 If p is determined to be prime, then return VALID and the values of p , q and (optionally) the values of domain_parameter_seed and counter . + return (p, q, domain_parameter_seed, counter); + } + } + // 11.9 offset = offset + n + 1. + offset = offset + n + 1; + } + } + } + + fn generate_g(rng: &mut G, p: &$ltype, q: &$ntype) -> $ltype + { + let bigq = $ltype::from(q); + let p_minus_1 = p - $ltype::from(1u64); + // This is A.2.1 (Unverifiable Generation of g) from FIPS 186-4. + // 1. e = (p – 1) / q. + let e = (p - $ltype::from(1u64)) / bigq; + loop { + // 2. Set h = any integer satisfying 1 < h < ( p – 1), such that + // h differs from any value previously tried. Note that h could + // be obtained from a random number generator or from a counter + // that changes after each use. + let h = rng.gen_range($ltype::from(2u64), &p_minus_1); + // 3. g = h^e mod p. + let g = h.modexp(&e, p); + // 4. If ( g = 1), then go to step 2. + if g != $ltype::from(1u64) { + // 5. Return g + return g; + } + } + } + } + }; +} + +generate_parameters!(L1024N160, U1024, U192, 1024, 160); +generate_parameters!(L2048N224, U2048, U256, 2048, 224); +generate_parameters!(L2048N256, U2048, U256, 2048, 256); +generate_parameters!(L3072N256, U3072, U256, 3072, 256); + +fn hash(x: &T, len: usize) -> Vec + where T: Encoder +{ + let mut base = x.to_bytes(); + let bytelen = len / 8; + while base.len() < bytelen { + base.insert(0,0); + } + Sha256::digest(&base).as_slice().to_vec() +} \ No newline at end of file diff --git a/src/dsa/private.rs b/src/dsa/private.rs new file mode 100644 index 0000000..5e87deb --- /dev/null +++ b/src/dsa/private.rs @@ -0,0 +1,111 @@ +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 { + /// Generate a new private key using the given DSA parameters and private + /// key value. + fn new(params: Params, x: 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<$ptype,$ltype,$ntype> for DSAPrivKey<$ptype,$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); \ No newline at end of file diff --git a/src/dsa/public.rs b/src/dsa/public.rs new file mode 100644 index 0000000..415c5d6 --- /dev/null +++ b/src/dsa/public.rs @@ -0,0 +1,87 @@ +use cryptonum::unsigned::*; +use cryptonum::signed::ModInv; +use digest::Digest; +use dsa::params::*; +use dsa::rfc6979::DSASignature; +use num::BigInt; +use simple_asn1::{ToASN1,ASN1Block,ASN1Class,ASN1EncodeErr}; +use std::cmp::min; +use utils::TranslateNums; + +pub trait DSAPublicKey { + /// Generate a new public key given the parameters and public value. + fn new(params: Params, y: L) -> Self; + /// Verify the given signature against the given message, using the + /// appropriate hash function. + fn verify(&self, m: &[u8], sig: &DSASignature) -> bool + where Hash: Digest; +} + +pub struct DSAPubKey { + pub(crate) params: Params, + pub(crate) y: L +} + +macro_rules! pubkey_impls { + ($ptype: ident, $ltype: ident, $ntype: ident, $dbl: ident, $bdbl: ident) => { + impl DSAPublicKey<$ptype,$ltype,$ntype> for DSAPubKey<$ptype,$ltype> + { + fn new(params: $ptype, y: $ltype) -> DSAPubKey<$ptype,$ltype> + { + DSAPubKey{ params, y } + } + + fn verify(&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 = ::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,ASN1EncodeErr> + { + let uinty = self.y.to_num(); + let inty = BigInt::from(uinty); + 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); \ No newline at end of file diff --git a/src/dsa/rfc6979.rs b/src/dsa/rfc6979.rs new file mode 100644 index 0000000..7b3fd92 --- /dev/null +++ b/src/dsa/rfc6979.rs @@ -0,0 +1,365 @@ +use cryptonum::unsigned::{CryptoNum,Decoder,Encoder,U512}; +use digest::{BlockInput,Digest,FixedOutput,Input,Reset}; +use digest::generic_array::ArrayLength; +use hmac::{Hmac,Mac}; +use num::BigInt; +use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr}; +use simple_asn1::{FromASN1,ToASN1}; +use utils::TranslateNums; + +#[derive(Debug,PartialEq)] +pub struct DSASignature +{ + pub r: N, + pub s: N +} + +impl DSASignature +{ + pub fn new(r: N, s: N) -> DSASignature + { + DSASignature{ r, s } + } +} + +#[allow(non_snake_case)] +pub struct KIterator + where + H: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset, + N: Clone + Encoder + From + PartialOrd, + Hmac: Mac, + U512: From +{ + hmac_k: Hmac, + V: Vec, + q: N, + qlen: usize +} + +impl KIterator + where + H: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset, + N: Clone + Encoder + From + PartialOrd, + Hmac: Mac, + U512: From +{ + pub fn new(h1: &[u8], qlen: usize, q: &N, x: &N) -> KIterator + { + // Given the input message m, the following process is applied: + // + // a. Process m through the hash function H, yielding: + // + // h1 = H(m) + // + // (h1 is a sequence of hlen bits). + // + let hlen = h1.len(); + // b. Set: + // + // V = 0x01 0x01 0x01 ... 0x01 + // + // such that the length of V, in bits, is equal to 8*ceil(hlen/8). + // For instance, on an octet-based system, if H is SHA-256, then + // V is set to a sequence of 32 octets of value 1. Note that in + // this step and all subsequent steps, we use the same H function + // as the one used in step 'a' to process the input message; this + // choice will be discussed in more detail in Section 3.6. + // + #[allow(non_snake_case)] + let mut V = Vec::new(); + V.resize(hlen, 0x01); + // c. Set: + // + // K = 0x00 0x00 0x00 ... 0x00 + // + // such that the length of K, in bits, is equal to 8*ceil(hlen/8). + #[allow(non_snake_case)] + let mut K = Vec::new(); + K.resize(hlen, 0x00); + // d. Set: + // + // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1)) + // + // where '||' denotes concatenation. In other words, we compute + // HMAC with key K, over the concatenation of the following, in + // order: the current value of V, a sequence of eight bits of value + // 0, the encoding of the (EC)DSA private key x, and the hashed + // message (possibly truncated and extended as specified by the + // bits2octets transform). The HMAC result is the new value of K. + // Note that the private key x is in the [1, q-1] range, hence a + // proper input for int2octets, yielding rlen bits of output, i.e., + // an integral number of octets (rlen is a multiple of 8). + let xbytes = int2octets(x, qlen); + let h1bytes = bits2octets(h1, q, qlen); + let mut input = Vec::new(); + input.extend_from_slice(&V); + input.push(0x00); + input.extend_from_slice(&xbytes); + input.extend_from_slice(&h1bytes); + K = hmac(&K, &input); + // e. Set: + // + // V = HMAC_K(V) + V = hmac(&K, &V); + // f. Set: + // + // K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1)) + // + // Note that the "internal octet" is 0x01 this time. + input = Vec::new(); + input.extend_from_slice(&V); + input.push(0x01); + input.extend_from_slice(&xbytes); + input.extend_from_slice(&h1bytes); + K = hmac(&K, &input); + // g. Set: + // + // V = HMAC_K(V) + V = hmac(&K, &V); + // h is for later ... + KIterator { + hmac_k: Hmac::::new_varkey(&K).unwrap(), + V: V, + q: q.clone(), + qlen: qlen + } + } +} + +impl Iterator for KIterator + where + H: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset, + N: Clone + CryptoNum + Encoder + From + PartialOrd, + Hmac: Mac, + U512: From +{ + type Item = N; + + fn next(&mut self) -> Option + { + loop { + // h. Apply the following algorithm until a proper value is found + // for k: + // + // 1. Set T to the empty sequence. The length of T (in bits) is + // denoted tlen; thus, at that point, tlen = 0. + let mut t = Vec::new(); + // + // 2. While tlen < qlen, do the following: + // + // V = HMAC_K(V) + // T = T || V + let target = (self.qlen + 7) / 8; + while t.len() < target { + self.V = runhmac(&self.hmac_k, &self.V); + t.extend_from_slice(&self.V); + } + // + // 3. Compute: + // + // k = bits2int(T) + let resk: N = bits2int(&t, self.qlen); + // + // If that value of k is within the [1,q-1] range, and is + // suitable for DSA or ECDSA (i.e., it results in an r value + // that is not 0; see Section 3.4), then the generation of k + // is finished. The obtained value of k is used in DSA or + // ECDSA. Otherwise, compute: + // + // K = HMAC_K(V || 0x00) + let mut input = self.V.clone(); + input.push(0x00); + #[allow(non_snake_case)] + let K = runhmac(&self.hmac_k, &input); + // V = HMAC_K(V) + self.hmac_k = Hmac::::new_varkey(&K).unwrap(); + self.V = runhmac(&self.hmac_k, &self.V); + // + // and loop (try to generate a new T, and so on). + // + if !resk.is_zero() && (resk < self.q) { + return Some(resk); + } + } + } +} + +pub fn bits2int>(x: &[u8], qlen: usize) -> X +{ + let mut value = U512::from_bytes(x); + let vlen = x.len() * 8; + + if vlen > qlen { + value >>= vlen - qlen; + } + + X::from(value) +} + +fn bits2octets(x: &[u8], q: &X, qlen: usize) -> Vec + where + X: Clone + From, + U512: From +{ + let z1: U512 = bits2int(x, qlen); + let qbig = U512::from(q.clone()); + let res = if z1 > qbig { z1 - qbig } else { z1 }; + int2octets(&res, qlen) +} + +fn int2octets(x: &X, qlen_bits: usize) -> Vec + where X: Encoder +{ + let qlen_bytes = (qlen_bits + 7) / 8; + let mut base = x.to_bytes(); + + while base.len() < qlen_bytes { + base.insert(0,0); + } + + while base.len() > qlen_bytes { + base.remove(0); + } + + base +} + +fn runhmac(base: &Hmac, m: &[u8]) -> Vec + where + H: Clone + BlockInput + Default + Input + FixedOutput + Reset, + Hmac: Clone + Mac, + H::BlockSize : ArrayLength +{ + let mut runner = base.clone(); + runner.input(&m); + runner.result().code().as_slice().to_vec() +} + +fn hmac(k: &[u8], m: &[u8]) -> Vec + where + H: BlockInput + Clone + Default + Input + FixedOutput + Reset, + Hmac: Clone + Mac, + H::BlockSize : ArrayLength +{ + let mut runner = Hmac::::new_varkey(&k).unwrap(); + runner.input(&m); + runner.result().code().as_slice().to_vec() +} + +#[derive(Clone,Debug,PartialEq)] +pub enum DSADecodeError { + ASN1Error(ASN1DecodeErr), + NoSignatureFound, + NegativeSigValues, + RValueTooBig, SValueTooBig +} + +impl From for DSADecodeError { + fn from(a: ASN1DecodeErr) -> DSADecodeError { + DSADecodeError::ASN1Error(a) + } +} + +impl FromASN1 for DSASignature + where N: TranslateNums +{ + type Error = DSADecodeError; + + fn from_asn1(v: &[ASN1Block]) + -> Result<(DSASignature,&[ASN1Block]),DSADecodeError> + { + match v.split_first() { + Some((&ASN1Block::Sequence(_,_,ref info), rest)) + if info.len() == 2 => + { + match (&info[0], &info[1]) { + (&ASN1Block::Integer(_,_,ref rint), + &ASN1Block::Integer(_,_,ref sint)) => { + match (rint.to_biguint(), sint.to_biguint()) { + (Some(rnum), Some(snum)) => { + let r = N::from_num(rnum).ok_or(DSADecodeError::RValueTooBig)?; + let s = N::from_num(snum).ok_or(DSADecodeError::SValueTooBig)?; + Ok((DSASignature{ r, s }, rest)) + + } + _ => + Err(DSADecodeError::NegativeSigValues) + } + } + _ => Err(DSADecodeError::NoSignatureFound) + } + } + _ => Err(DSADecodeError::NoSignatureFound) + } + } +} + +impl ToASN1 for DSASignature + where N: TranslateNums +{ + type Error = ASN1EncodeErr; + + fn to_asn1_class(&self, c: ASN1Class) + -> Result,ASN1EncodeErr> + { + let rb = ASN1Block::Integer(c, 0, BigInt::from(self.r.to_num())); + let sb = ASN1Block::Integer(c, 0, BigInt::from(self.s.to_num())); + Ok(vec![ASN1Block::Sequence(c, 0, vec![rb,sb])]) + } +} + +#[cfg(test)] +mod tests { + use cryptonum::unsigned::U192; + use sha2::Sha256; + use super::*; + + const QBYTES: [u8; 21] = [0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x01, 0x08, 0xA2, 0xE0, 0xCC, + 0x0D, 0x99, 0xF8, 0xA5, 0xEF]; + const XBYTES: [u8; 21] = [0x00, 0x9A, 0x4D, 0x67, 0x92, 0x29, 0x5A, 0x7F, + 0x73, 0x0F, 0xC3, 0xF2, 0xB4, 0x9C, 0xBC, 0x0F, + 0x62, 0xE8, 0x62, 0x27, 0x2F]; + const H1: [u8; 32] = [0xAF, 0x2B, 0xDB, 0xE1, 0xAA, 0x9B, 0x6E, 0xC1, + 0xE2, 0xAD, 0xE1, 0xD6, 0x94, 0xF4, 0x1F, 0xC7, + 0x1A, 0x83, 0x1D, 0x02, 0x68, 0xE9, 0x89, 0x15, + 0x62, 0x11, 0x3D, 0x8A, 0x62, 0xAD, 0xD1, 0xBF]; + + #[test] + fn int2octets_example() { + let x = U192::from_bytes(&XBYTES); + let octets = int2octets(&x, 163); + let target = vec![0x00, 0x9A, 0x4D, 0x67, 0x92, 0x29, 0x5A, 0x7F, + 0x73, 0x0F, 0xC3, 0xF2, 0xB4, 0x9C, 0xBC, 0x0F, + 0x62, 0xE8, 0x62, 0x27, 0x2F]; + assert_eq!(octets, target); + } + + #[test] + fn bits2octets_example() { + let q = U192::from_bytes(&QBYTES); + let octets = bits2octets(&H1, &q, 163); + let target = vec![0x01, 0x79, 0x5E, 0xDF, 0x0D, 0x54, 0xDB, 0x76, + 0x0F, 0x15, 0x6D, 0x0D, 0xAC, 0x04, 0xC0, 0x32, + 0x2B, 0x3A, 0x20, 0x42, 0x24]; + assert_eq!(octets, target); + } + + #[test] + fn k_gen_example() { + let q = U192::from_bytes(&QBYTES); + let x = U192::from_bytes(&XBYTES); + let mut iter = KIterator::::new(&H1, 163, &q, &x); + match iter.next() { + None => + assert!(false), + Some(x) => { + let target = vec![0x02, 0x3A, 0xF4, 0x07, 0x4C, 0x90, 0xA0, + 0x2B, 0x3F, 0xE6, 0x1D, 0x28, 0x6D, 0x5C, + 0x87, 0xF4, 0x25, 0xE6, 0xBD, 0xD8, 0x1B]; + let x2 = U192::from_bytes(&target); + assert_eq!(x, x2); + } + } + } +} \ No newline at end of file diff --git a/src/dsa/tests.rs b/src/dsa/tests.rs new file mode 100644 index 0000000..9a7494b --- /dev/null +++ b/src/dsa/tests.rs @@ -0,0 +1,536 @@ +use digest::Digest; +use sha1::Sha1; +use sha2::{Sha224,Sha256,Sha384,Sha512}; +use simple_asn1::{der_decode,der_encode}; +use super::*; +use dsa::rfc6979::KIterator; + +macro_rules! run_rfc6979_test { + ($hash: ty, $ntype: ident, $val: ident, $public: ident, $private: ident, + k $k: expr, + r $r: expr, + s $s: expr) => ({ + let h1 = <$hash>::digest(&$val); + let rbytes = $r; + let sbytes = $s; + let r = $ntype::from_bytes(&rbytes); + let s = $ntype::from_bytes(&sbytes); + let mut iter = KIterator::<$hash,$ntype>::new(&h1, $public.params.n_bits(), + &$public.params.q, + &$private.x); + let mut k1 = iter.next().unwrap().to_bytes().to_vec(); + while k1.len() > $k.len() { + assert_eq!(k1[0], 0); + k1.remove(0); + } + assert_eq!($k, k1); + let sig = $private.sign::<$hash>(&$val); + assert_eq!(sig.r, r); + assert_eq!(sig.s, s); + assert!($public.verify::<$hash>(&$val, &sig)); + let blocks = der_encode(&sig).unwrap(); + let sig2 = der_decode(&blocks).unwrap(); + assert_eq!(sig, sig2); + }) +} + +// these appendix_* tests are out of RFC6979 +#[test] +fn appendix_a21() { + let pbytes = vec![0x86, 0xF5, 0xCA, 0x03, 0xDC, 0xFE, 0xB2, 0x25, + 0x06, 0x3F, 0xF8, 0x30, 0xA0, 0xC7, 0x69, 0xB9, + 0xDD, 0x9D, 0x61, 0x53, 0xAD, 0x91, 0xD7, 0xCE, + 0x27, 0xF7, 0x87, 0xC4, 0x32, 0x78, 0xB4, 0x47, + 0xE6, 0x53, 0x3B, 0x86, 0xB1, 0x8B, 0xED, 0x6E, + 0x8A, 0x48, 0xB7, 0x84, 0xA1, 0x4C, 0x25, 0x2C, + 0x5B, 0xE0, 0xDB, 0xF6, 0x0B, 0x86, 0xD6, 0x38, + 0x5B, 0xD2, 0xF1, 0x2F, 0xB7, 0x63, 0xED, 0x88, + 0x73, 0xAB, 0xFD, 0x3F, 0x5B, 0xA2, 0xE0, 0xA8, + 0xC0, 0xA5, 0x90, 0x82, 0xEA, 0xC0, 0x56, 0x93, + 0x5E, 0x52, 0x9D, 0xAF, 0x7C, 0x61, 0x04, 0x67, + 0x89, 0x9C, 0x77, 0xAD, 0xED, 0xFC, 0x84, 0x6C, + 0x88, 0x18, 0x70, 0xB7, 0xB1, 0x9B, 0x2B, 0x58, + 0xF9, 0xBE, 0x05, 0x21, 0xA1, 0x70, 0x02, 0xE3, + 0xBD, 0xD6, 0xB8, 0x66, 0x85, 0xEE, 0x90, 0xB3, + 0xD9, 0xA1, 0xB0, 0x2B, 0x78, 0x2B, 0x17, 0x79]; + let qbytes = vec![0x99, 0x6F, 0x96, 0x7F, 0x6C, 0x8E, 0x38, 0x8D, + 0x9E, 0x28, 0xD0, 0x1E, 0x20, 0x5F, 0xBA, 0x95, + 0x7A, 0x56, 0x98, 0xB1]; + let gbytes = vec![0x07, 0xB0, 0xF9, 0x25, 0x46, 0x15, 0x0B, 0x62, + 0x51, 0x4B, 0xB7, 0x71, 0xE2, 0xA0, 0xC0, 0xCE, + 0x38, 0x7F, 0x03, 0xBD, 0xA6, 0xC5, 0x6B, 0x50, + 0x52, 0x09, 0xFF, 0x25, 0xFD, 0x3C, 0x13, 0x3D, + 0x89, 0xBB, 0xCD, 0x97, 0xE9, 0x04, 0xE0, 0x91, + 0x14, 0xD9, 0xA7, 0xDE, 0xFD, 0xEA, 0xDF, 0xC9, + 0x07, 0x8E, 0xA5, 0x44, 0xD2, 0xE4, 0x01, 0xAE, + 0xEC, 0xC4, 0x0B, 0xB9, 0xFB, 0xBF, 0x78, 0xFD, + 0x87, 0x99, 0x5A, 0x10, 0xA1, 0xC2, 0x7C, 0xB7, + 0x78, 0x9B, 0x59, 0x4B, 0xA7, 0xEF, 0xB5, 0xC4, + 0x32, 0x6A, 0x9F, 0xE5, 0x9A, 0x07, 0x0E, 0x13, + 0x6D, 0xB7, 0x71, 0x75, 0x46, 0x4A, 0xDC, 0xA4, + 0x17, 0xBE, 0x5D, 0xCE, 0x2F, 0x40, 0xD1, 0x0A, + 0x46, 0xA3, 0xA3, 0x94, 0x3F, 0x26, 0xAB, 0x7F, + 0xD9, 0xC0, 0x39, 0x8F, 0xF8, 0xC7, 0x6E, 0xE0, + 0xA5, 0x68, 0x26, 0xA8, 0xA8, 0x8F, 0x1D, 0xBD]; + let xbytes = vec![0x41, 0x16, 0x02, 0xCB, 0x19, 0xA6, 0xCC, 0xC3, + 0x44, 0x94, 0xD7, 0x9D, 0x98, 0xEF, 0x1E, 0x7E, + 0xD5, 0xAF, 0x25, 0xF7]; + let ybytes = vec![0x5D, 0xF5, 0xE0, 0x1D, 0xED, 0x31, 0xD0, 0x29, + 0x7E, 0x27, 0x4E, 0x16, 0x91, 0xC1, 0x92, 0xFE, + 0x58, 0x68, 0xFE, 0xF9, 0xE1, 0x9A, 0x84, 0x77, + 0x64, 0x54, 0xB1, 0x00, 0xCF, 0x16, 0xF6, 0x53, + 0x92, 0x19, 0x5A, 0x38, 0xB9, 0x05, 0x23, 0xE2, + 0x54, 0x2E, 0xE6, 0x18, 0x71, 0xC0, 0x44, 0x0C, + 0xB8, 0x7C, 0x32, 0x2F, 0xC4, 0xB4, 0xD2, 0xEC, + 0x5E, 0x1E, 0x7E, 0xC7, 0x66, 0xE1, 0xBE, 0x8D, + 0x4C, 0xE9, 0x35, 0x43, 0x7D, 0xC1, 0x1C, 0x3C, + 0x8F, 0xD4, 0x26, 0x33, 0x89, 0x33, 0xEB, 0xFE, + 0x73, 0x9C, 0xB3, 0x46, 0x5F, 0x4D, 0x36, 0x68, + 0xC5, 0xE4, 0x73, 0x50, 0x82, 0x53, 0xB1, 0xE6, + 0x82, 0xF6, 0x5C, 0xBD, 0xC4, 0xFA, 0xE9, 0x3C, + 0x2E, 0xA2, 0x12, 0x39, 0x0E, 0x54, 0x90, 0x5A, + 0x86, 0xE2, 0x22, 0x31, 0x70, 0xB4, 0x4E, 0xAA, + 0x7D, 0xA5, 0xDD, 0x9F, 0xFC, 0xFB, 0x7F, 0x3B]; + // + let p = U1024::from_bytes(&pbytes); + let q = U192::from_bytes(&qbytes); + let g = U1024::from_bytes(&gbytes); + let params = L1024N160::new(p, g, q); + let x = U192::from_bytes(&xbytes); + let y = U1024::from_bytes(&ybytes); + let private = DSAPrivKey::::new(params.clone(), x); + let public = DSAPubKey::::new(params.clone(), y); + // + let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII + let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII + // With SHA-1, message = "sample": + // k = 7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B + // r = 2E1A0C2562B2912CAAF89186FB0F42001585DA55 + // s = 29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5 + run_rfc6979_test!(Sha1, U192, sample, public, private, + k vec![0x7B, 0xDB, 0x6B, 0x0F, 0xF7, 0x56, 0xE1, 0xBB, + 0x5D, 0x53, 0x58, 0x3E, 0xF9, 0x79, 0x08, 0x2F, + 0x9A, 0xD5, 0xBD, 0x5B], + r vec![0x2E, 0x1A, 0x0C, 0x25, 0x62, 0xB2, 0x91, 0x2C, + 0xAA, 0xF8, 0x91, 0x86, 0xFB, 0x0F, 0x42, 0x00, + 0x15, 0x85, 0xDA, 0x55], + s vec![0x29, 0xEF, 0xB6, 0xB0, 0xAF, 0xF2, 0xD7, 0xA6, + 0x8E, 0xB7, 0x0C, 0xA3, 0x13, 0x02, 0x22, 0x53, + 0xB9, 0xA8, 0x8D, 0xF5]); + // With SHA-224, message = "sample": + // k = 562097C06782D60C3037BA7BE104774344687649 + // r = 4BC3B686AEA70145856814A6F1BB53346F02101E + // s = 410697B92295D994D21EDD2F4ADA85566F6F94C1 + run_rfc6979_test!(Sha224, U192, sample, public, private, + k vec![0x56, 0x20, 0x97, 0xC0, 0x67, 0x82, 0xD6, 0x0C, + 0x30, 0x37, 0xBA, 0x7B, 0xE1, 0x04, 0x77, 0x43, + 0x44, 0x68, 0x76, 0x49], + r vec![0x4B, 0xC3, 0xB6, 0x86, 0xAE, 0xA7, 0x01, 0x45, + 0x85, 0x68, 0x14, 0xA6, 0xF1, 0xBB, 0x53, 0x34, + 0x6F, 0x02, 0x10, 0x1E], + s vec![0x41, 0x06, 0x97, 0xB9, 0x22, 0x95, 0xD9, 0x94, + 0xD2, 0x1E, 0xDD, 0x2F, 0x4A, 0xDA, 0x85, 0x56, + 0x6F, 0x6F, 0x94, 0xC1]); + // With SHA-256, message = "sample": + // k = 519BA0546D0C39202A7D34D7DFA5E760B318BCFB + // r = 81F2F5850BE5BC123C43F71A3033E9384611C545 + // s = 4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89 + run_rfc6979_test!(Sha256, U192, sample, public, private, + k vec![0x51, 0x9B, 0xA0, 0x54, 0x6D, 0x0C, 0x39, 0x20, + 0x2A, 0x7D, 0x34, 0xD7, 0xDF, 0xA5, 0xE7, 0x60, + 0xB3, 0x18, 0xBC, 0xFB], + r vec![0x81, 0xF2, 0xF5, 0x85, 0x0B, 0xE5, 0xBC, 0x12, + 0x3C, 0x43, 0xF7, 0x1A, 0x30, 0x33, 0xE9, 0x38, + 0x46, 0x11, 0xC5, 0x45], + s vec![0x4C, 0xDD, 0x91, 0x4B, 0x65, 0xEB, 0x6C, 0x66, + 0xA8, 0xAA, 0xAD, 0x27, 0x29, 0x9B, 0xEE, 0x6B, + 0x03, 0x5F, 0x5E, 0x89]); + // With SHA-384, message = "sample": + // k = 95897CD7BBB944AA932DBC579C1C09EB6FCFC595 + // r = 07F2108557EE0E3921BC1774F1CA9B410B4CE65A + // s = 54DF70456C86FAC10FAB47C1949AB83F2C6F7595 + run_rfc6979_test!(Sha384, U192, sample, public, private, + k vec![0x95, 0x89, 0x7C, 0xD7, 0xBB, 0xB9, 0x44, 0xAA, + 0x93, 0x2D, 0xBC, 0x57, 0x9C, 0x1C, 0x09, 0xEB, + 0x6F, 0xCF, 0xC5, 0x95], + r vec![0x07, 0xF2, 0x10, 0x85, 0x57, 0xEE, 0x0E, 0x39, + 0x21, 0xBC, 0x17, 0x74, 0xF1, 0xCA, 0x9B, 0x41, + 0x0B, 0x4C, 0xE6, 0x5A], + s vec![0x54, 0xDF, 0x70, 0x45, 0x6C, 0x86, 0xFA, 0xC1, + 0x0F, 0xAB, 0x47, 0xC1, 0x94, 0x9A, 0xB8, 0x3F, + 0x2C, 0x6F, 0x75, 0x95]); + // With SHA-512, message = "sample": + // k = 09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B + // r = 16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B + // s = 02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C + run_rfc6979_test!(Sha512, U192, sample, public, private, + k vec![0x09, 0xEC, 0xE7, 0xCA, 0x27, 0xD0, 0xF5, 0xA4, + 0xDD, 0x4E, 0x55, 0x6C, 0x9D, 0xF1, 0xD2, 0x1D, + 0x28, 0x10, 0x4F, 0x8B], + r vec![0x16, 0xC3, 0x49, 0x1F, 0x9B, 0x8C, 0x3F, 0xBB, + 0xDD, 0x5E, 0x7A, 0x7B, 0x66, 0x70, 0x57, 0xF0, + 0xD8, 0xEE, 0x8E, 0x1B], + s vec![0x02, 0xC3, 0x6A, 0x12, 0x7A, 0x7B, 0x89, 0xED, + 0xBB, 0x72, 0xE4, 0xFF, 0xBC, 0x71, 0xDA, 0xBC, + 0x7D, 0x4F, 0xC6, 0x9C]); + // With SHA-1, message = "test": + // k = 5C842DF4F9E344EE09F056838B42C7A17F4A6433 + // r = 42AB2052FD43E123F0607F115052A67DCD9C5C77 + // s = 183916B0230D45B9931491D4C6B0BD2FB4AAF088 + run_rfc6979_test!(Sha1, U192, test, public, private, + k vec![0x5C, 0x84, 0x2D, 0xF4, 0xF9, 0xE3, 0x44, 0xEE, + 0x09, 0xF0, 0x56, 0x83, 0x8B, 0x42, 0xC7, 0xA1, + 0x7F, 0x4A, 0x64, 0x33], + r vec![0x42, 0xAB, 0x20, 0x52, 0xFD, 0x43, 0xE1, 0x23, + 0xF0, 0x60, 0x7F, 0x11, 0x50, 0x52, 0xA6, 0x7D, + 0xCD, 0x9C, 0x5C, 0x77], + s vec![0x18, 0x39, 0x16, 0xB0, 0x23, 0x0D, 0x45, 0xB9, + 0x93, 0x14, 0x91, 0xD4, 0xC6, 0xB0, 0xBD, 0x2F, + 0xB4, 0xAA, 0xF0, 0x88]); + // With SHA-224, message = "test": + // k = 4598B8EFC1A53BC8AECD58D1ABBB0C0C71E67297 + // r = 6868E9964E36C1689F6037F91F28D5F2C30610F2 + // s = 49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F + run_rfc6979_test!(Sha224, U192, test, public, private, + k vec![0x45, 0x98, 0xB8, 0xEF, 0xC1, 0xA5, 0x3B, 0xC8, + 0xAE, 0xCD, 0x58, 0xD1, 0xAB, 0xBB, 0x0C, 0x0C, + 0x71, 0xE6, 0x72, 0x97], + r vec![0x68, 0x68, 0xE9, 0x96, 0x4E, 0x36, 0xC1, 0x68, + 0x9F, 0x60, 0x37, 0xF9, 0x1F, 0x28, 0xD5, 0xF2, + 0xC3, 0x06, 0x10, 0xF2], + s vec![0x49, 0xCE, 0xC3, 0xAC, 0xDC, 0x83, 0x01, 0x8C, + 0x5B, 0xD2, 0x67, 0x4E, 0xCA, 0xAD, 0x35, 0xB8, + 0xCD, 0x22, 0x94, 0x0F]); + // With SHA-256, message = "test": + // k = 5A67592E8128E03A417B0484410FB72C0B630E1A + // r = 22518C127299B0F6FDC9872B282B9E70D0790812 + // s = 6837EC18F150D55DE95B5E29BE7AF5D01E4FE160 + run_rfc6979_test!(Sha256, U192, test, public, private, + k vec![0x5A, 0x67, 0x59, 0x2E, 0x81, 0x28, 0xE0, 0x3A, + 0x41, 0x7B, 0x04, 0x84, 0x41, 0x0F, 0xB7, 0x2C, + 0x0B, 0x63, 0x0E, 0x1A], + r vec![0x22, 0x51, 0x8C, 0x12, 0x72, 0x99, 0xB0, 0xF6, + 0xFD, 0xC9, 0x87, 0x2B, 0x28, 0x2B, 0x9E, 0x70, + 0xD0, 0x79, 0x08, 0x12], + s vec![0x68, 0x37, 0xEC, 0x18, 0xF1, 0x50, 0xD5, 0x5D, + 0xE9, 0x5B, 0x5E, 0x29, 0xBE, 0x7A, 0xF5, 0xD0, + 0x1E, 0x4F, 0xE1, 0x60]); + // With SHA-384, message = "test": + // k = 220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89 + // r = 854CF929B58D73C3CBFDC421E8D5430CD6DB5E66 + // s = 91D0E0F53E22F898D158380676A871A157CDA622 + run_rfc6979_test!(Sha384, U192, test, public, private, + k vec![0x22, 0x01, 0x56, 0xB7, 0x61, 0xF6, 0xCA, 0x5E, + 0x6C, 0x9F, 0x1B, 0x9C, 0xF9, 0xC2, 0x4B, 0xE2, + 0x5F, 0x98, 0xCD, 0x89], + r vec![0x85, 0x4C, 0xF9, 0x29, 0xB5, 0x8D, 0x73, 0xC3, + 0xCB, 0xFD, 0xC4, 0x21, 0xE8, 0xD5, 0x43, 0x0C, + 0xD6, 0xDB, 0x5E, 0x66], + s vec![0x91, 0xD0, 0xE0, 0xF5, 0x3E, 0x22, 0xF8, 0x98, + 0xD1, 0x58, 0x38, 0x06, 0x76, 0xA8, 0x71, 0xA1, + 0x57, 0xCD, 0xA6, 0x22]); + // With SHA-512, message = "test": + // k = 65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C + // r = 8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0 + // s = 7C670C7AD72B6C050C109E1790008097125433E8 + run_rfc6979_test!(Sha512, U192, test, public, private, + k vec![0x65, 0xD2, 0xC2, 0xEE, 0xB1, 0x75, 0xE3, 0x70, + 0xF2, 0x8C, 0x75, 0xBF, 0xCD, 0xC0, 0x28, 0xD2, + 0x2C, 0x7D, 0xBE, 0x9C], + r vec![0x8E, 0xA4, 0x7E, 0x47, 0x5B, 0xA8, 0xAC, 0x6F, + 0x2D, 0x82, 0x1D, 0xA3, 0xBD, 0x21, 0x2D, 0x11, + 0xA3, 0xDE, 0xB9, 0xA0], + s vec![0x7C, 0x67, 0x0C, 0x7A, 0xD7, 0x2B, 0x6C, 0x05, + 0x0C, 0x10, 0x9E, 0x17, 0x90, 0x00, 0x80, 0x97, + 0x12, 0x54, 0x33, 0xE8]); +} + +#[test] +fn appendix_a22() { + let pbytes = vec![0x9D,0xB6,0xFB,0x59,0x51,0xB6,0x6B,0xB6, + 0xFE,0x1E,0x14,0x0F,0x1D,0x2C,0xE5,0x50, + 0x23,0x74,0x16,0x1F,0xD6,0x53,0x8D,0xF1, + 0x64,0x82,0x18,0x64,0x2F,0x0B,0x5C,0x48, + 0xC8,0xF7,0xA4,0x1A,0xAD,0xFA,0x18,0x73, + 0x24,0xB8,0x76,0x74,0xFA,0x18,0x22,0xB0, + 0x0F,0x1E,0xCF,0x81,0x36,0x94,0x3D,0x7C, + 0x55,0x75,0x72,0x64,0xE5,0xA1,0xA4,0x4F, + 0xFE,0x01,0x2E,0x99,0x36,0xE0,0x0C,0x1D, + 0x3E,0x93,0x10,0xB0,0x1C,0x7D,0x17,0x98, + 0x05,0xD3,0x05,0x8B,0x2A,0x9F,0x4B,0xB6, + 0xF9,0x71,0x6B,0xFE,0x61,0x17,0xC6,0xB5, + 0xB3,0xCC,0x4D,0x9B,0xE3,0x41,0x10,0x4A, + 0xD4,0xA8,0x0A,0xD6,0xC9,0x4E,0x00,0x5F, + 0x4B,0x99,0x3E,0x14,0xF0,0x91,0xEB,0x51, + 0x74,0x3B,0xF3,0x30,0x50,0xC3,0x8D,0xE2, + 0x35,0x56,0x7E,0x1B,0x34,0xC3,0xD6,0xA5, + 0xC0,0xCE,0xAA,0x1A,0x0F,0x36,0x82,0x13, + 0xC3,0xD1,0x98,0x43,0xD0,0xB4,0xB0,0x9D, + 0xCB,0x9F,0xC7,0x2D,0x39,0xC8,0xDE,0x41, + 0xF1,0xBF,0x14,0xD4,0xBB,0x45,0x63,0xCA, + 0x28,0x37,0x16,0x21,0xCA,0xD3,0x32,0x4B, + 0x6A,0x2D,0x39,0x21,0x45,0xBE,0xBF,0xAC, + 0x74,0x88,0x05,0x23,0x6F,0x5C,0xA2,0xFE, + 0x92,0xB8,0x71,0xCD,0x8F,0x9C,0x36,0xD3, + 0x29,0x2B,0x55,0x09,0xCA,0x8C,0xAA,0x77, + 0xA2,0xAD,0xFC,0x7B,0xFD,0x77,0xDD,0xA6, + 0xF7,0x11,0x25,0xA7,0x45,0x6F,0xEA,0x15, + 0x3E,0x43,0x32,0x56,0xA2,0x26,0x1C,0x6A, + 0x06,0xED,0x36,0x93,0x79,0x7E,0x79,0x95, + 0xFA,0xD5,0xAA,0xBB,0xCF,0xBE,0x3E,0xDA, + 0x27,0x41,0xE3,0x75,0x40,0x4A,0xE2,0x5B]; + let qbytes = vec![0xF2,0xC3,0x11,0x93,0x74,0xCE,0x76,0xC9, + 0x35,0x69,0x90,0xB4,0x65,0x37,0x4A,0x17, + 0xF2,0x3F,0x9E,0xD3,0x50,0x89,0xBD,0x96, + 0x9F,0x61,0xC6,0xDD,0xE9,0x99,0x8C,0x1F]; + let gbytes = vec![0x5C,0x7F,0xF6,0xB0,0x6F,0x8F,0x14,0x3F, + 0xE8,0x28,0x84,0x33,0x49,0x3E,0x47,0x69, + 0xC4,0xD9,0x88,0xAC,0xE5,0xBE,0x25,0xA0, + 0xE2,0x48,0x09,0x67,0x07,0x16,0xC6,0x13, + 0xD7,0xB0,0xCE,0xE6,0x93,0x2F,0x8F,0xAA, + 0x7C,0x44,0xD2,0xCB,0x24,0x52,0x3D,0xA5, + 0x3F,0xBE,0x4F,0x6E,0xC3,0x59,0x58,0x92, + 0xD1,0xAA,0x58,0xC4,0x32,0x8A,0x06,0xC4, + 0x6A,0x15,0x66,0x2E,0x7E,0xAA,0x70,0x3A, + 0x1D,0xEC,0xF8,0xBB,0xB2,0xD0,0x5D,0xBE, + 0x2E,0xB9,0x56,0xC1,0x42,0xA3,0x38,0x66, + 0x1D,0x10,0x46,0x1C,0x0D,0x13,0x54,0x72, + 0x08,0x50,0x57,0xF3,0x49,0x43,0x09,0xFF, + 0xA7,0x3C,0x61,0x1F,0x78,0xB3,0x2A,0xDB, + 0xB5,0x74,0x0C,0x36,0x1C,0x9F,0x35,0xBE, + 0x90,0x99,0x7D,0xB2,0x01,0x4E,0x2E,0xF5, + 0xAA,0x61,0x78,0x2F,0x52,0xAB,0xEB,0x8B, + 0xD6,0x43,0x2C,0x4D,0xD0,0x97,0xBC,0x54, + 0x23,0xB2,0x85,0xDA,0xFB,0x60,0xDC,0x36, + 0x4E,0x81,0x61,0xF4,0xA2,0xA3,0x5A,0xCA, + 0x3A,0x10,0xB1,0xC4,0xD2,0x03,0xCC,0x76, + 0xA4,0x70,0xA3,0x3A,0xFD,0xCB,0xDD,0x92, + 0x95,0x98,0x59,0xAB,0xD8,0xB5,0x6E,0x17, + 0x25,0x25,0x2D,0x78,0xEA,0xC6,0x6E,0x71, + 0xBA,0x9A,0xE3,0xF1,0xDD,0x24,0x87,0x19, + 0x98,0x74,0x39,0x3C,0xD4,0xD8,0x32,0x18, + 0x68,0x00,0x65,0x47,0x60,0xE1,0xE3,0x4C, + 0x09,0xE4,0xD1,0x55,0x17,0x9F,0x9E,0xC0, + 0xDC,0x44,0x73,0xF9,0x96,0xBD,0xCE,0x6E, + 0xED,0x1C,0xAB,0xED,0x8B,0x6F,0x11,0x6F, + 0x7A,0xD9,0xCF,0x50,0x5D,0xF0,0xF9,0x98, + 0xE3,0x4A,0xB2,0x75,0x14,0xB0,0xFF,0xE7]; + let xbytes = vec![0x69,0xC7,0x54,0x8C,0x21,0xD0,0xDF,0xEA, + 0x6B,0x9A,0x51,0xC9,0xEA,0xD4,0xE2,0x7C, + 0x33,0xD3,0xB3,0xF1,0x80,0x31,0x6E,0x5B, + 0xCA,0xB9,0x2C,0x93,0x3F,0x0E,0x4D,0xBC]; + let ybytes = vec![0x66,0x70,0x98,0xC6,0x54,0x42,0x6C,0x78, + 0xD7,0xF8,0x20,0x1E,0xAC,0x6C,0x20,0x3E, + 0xF0,0x30,0xD4,0x36,0x05,0x03,0x2C,0x2F, + 0x1F,0xA9,0x37,0xE5,0x23,0x7D,0xBD,0x94, + 0x9F,0x34,0xA0,0xA2,0x56,0x4F,0xE1,0x26, + 0xDC,0x8B,0x71,0x5C,0x51,0x41,0x80,0x2C, + 0xE0,0x97,0x9C,0x82,0x46,0x46,0x3C,0x40, + 0xE6,0xB6,0xBD,0xAA,0x25,0x13,0xFA,0x61, + 0x17,0x28,0x71,0x6C,0x2E,0x4F,0xD5,0x3B, + 0xC9,0x5B,0x89,0xE6,0x99,0x49,0xD9,0x65, + 0x12,0xE8,0x73,0xB9,0xC8,0xF8,0xDF,0xD4, + 0x99,0xCC,0x31,0x28,0x82,0x56,0x1A,0xDE, + 0xCB,0x31,0xF6,0x58,0xE9,0x34,0xC0,0xC1, + 0x97,0xF2,0xC4,0xD9,0x6B,0x05,0xCB,0xAD, + 0x67,0x38,0x1E,0x7B,0x76,0x88,0x91,0xE4, + 0xDA,0x38,0x43,0xD2,0x4D,0x94,0xCD,0xFB, + 0x51,0x26,0xE9,0xB8,0xBF,0x21,0xE8,0x35, + 0x8E,0xE0,0xE0,0xA3,0x0E,0xF1,0x3F,0xD6, + 0xA6,0x64,0xC0,0xDC,0xE3,0x73,0x1F,0x7F, + 0xB4,0x9A,0x48,0x45,0xA4,0xFD,0x82,0x54, + 0x68,0x79,0x72,0xA2,0xD3,0x82,0x59,0x9C, + 0x9B,0xAC,0x4E,0x0E,0xD7,0x99,0x81,0x93, + 0x07,0x89,0x13,0x03,0x25,0x58,0x13,0x49, + 0x76,0x41,0x0B,0x89,0xD2,0xC1,0x71,0xD1, + 0x23,0xAC,0x35,0xFD,0x97,0x72,0x19,0x59, + 0x7A,0xA7,0xD1,0x5C,0x1A,0x9A,0x42,0x8E, + 0x59,0x19,0x4F,0x75,0xC7,0x21,0xEB,0xCB, + 0xCF,0xAE,0x44,0x69,0x6A,0x49,0x9A,0xFA, + 0x74,0xE0,0x42,0x99,0xF1,0x32,0x02,0x66, + 0x01,0x63,0x8C,0xB8,0x7A,0xB7,0x91,0x90, + 0xD4,0xA0,0x98,0x63,0x15,0xDA,0x8E,0xEC, + 0x65,0x61,0xC9,0x38,0x99,0x6B,0xEA,0xDF]; + // + let p = U2048::from_bytes(&pbytes); + let q = U256::from_bytes(&qbytes); + let g = U2048::from_bytes(&gbytes); + let params = L2048N256::new(p, g, q); + let x = U256::from_bytes(&xbytes); + let y = U2048::from_bytes(&ybytes); + let private = DSAPrivKey::new(params.clone(), x); + let public = DSAPubKey::new(params.clone(), y); + // + let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII + let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII + // With SHA-1, message = "sample": + // k = 888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E + // r = 3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A + // s = D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF + run_rfc6979_test!(Sha1, U256, sample, public, private, + k vec![0x88,0x8F,0xA6,0xF7,0x73,0x8A,0x41,0xBD, + 0xC9,0x84,0x64,0x66,0xAB,0xDB,0x81,0x74, + 0xC0,0x33,0x82,0x50,0xAE,0x50,0xCE,0x95, + 0x5C,0xA1,0x62,0x30,0xF9,0xCB,0xD5,0x3E], + r vec![0x3A,0x1B,0x2D,0xBD,0x74,0x89,0xD6,0xED, + 0x7E,0x60,0x8F,0xD0,0x36,0xC8,0x3A,0xF3, + 0x96,0xE2,0x90,0xDB,0xD6,0x02,0x40,0x8E, + 0x86,0x77,0xDA,0xAB,0xD6,0xE7,0x44,0x5A], + s vec![0xD2,0x6F,0xCB,0xA1,0x9F,0xA3,0xE3,0x05, + 0x8F,0xFC,0x02,0xCA,0x15,0x96,0xCD,0xBB, + 0x6E,0x0D,0x20,0xCB,0x37,0xB0,0x60,0x54, + 0xF7,0xE3,0x6D,0xED,0x0C,0xDB,0xBC,0xCF]); + // With SHA-224, message = "sample": + // k = BC372967702082E1AA4FCE892209F71AE4AD25A6DFD869334E6F153BD0C4D806 + // r = DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C + // s = A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC + run_rfc6979_test!(Sha224, U256, sample, public, private, + k vec![0xBC,0x37,0x29,0x67,0x70,0x20,0x82,0xE1, + 0xAA,0x4F,0xCE,0x89,0x22,0x09,0xF7,0x1A, + 0xE4,0xAD,0x25,0xA6,0xDF,0xD8,0x69,0x33, + 0x4E,0x6F,0x15,0x3B,0xD0,0xC4,0xD8,0x06], + r vec![0xDC,0x9F,0x4D,0xEA,0xDA,0x8D,0x8F,0xF5, + 0x88,0xE9,0x8F,0xED,0x0A,0xB6,0x90,0xFF, + 0xCE,0x85,0x8D,0xC8,0xC7,0x93,0x76,0x45, + 0x0E,0xB6,0xB7,0x6C,0x24,0x53,0x7E,0x2C], + s vec![0xA6,0x5A,0x9C,0x3B,0xC7,0xBA,0xBE,0x28, + 0x6B,0x19,0x5D,0x5D,0xA6,0x86,0x16,0xDA, + 0x8D,0x47,0xFA,0x00,0x97,0xF3,0x6D,0xD1, + 0x9F,0x51,0x73,0x27,0xDC,0x84,0x8C,0xEC]); + // With SHA-256, message = "sample": + // k = 8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52 + // r = EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809 + // s = 7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53 + run_rfc6979_test!(Sha256, U256, sample, public, private, + k vec![0x89,0x26,0xA2,0x7C,0x40,0x48,0x42,0x16, + 0xF0,0x52,0xF4,0x42,0x7C,0xFD,0x56,0x47, + 0x33,0x8B,0x7B,0x39,0x39,0xBC,0x65,0x73, + 0xAF,0x43,0x33,0x56,0x9D,0x59,0x7C,0x52], + r vec![0xEA,0xCE,0x8B,0xDB,0xBE,0x35,0x3C,0x43, + 0x2A,0x79,0x5D,0x9E,0xC5,0x56,0xC6,0xD0, + 0x21,0xF7,0xA0,0x3F,0x42,0xC3,0x6E,0x9B, + 0xC8,0x7E,0x4A,0xC7,0x93,0x2C,0xC8,0x09], + s vec![0x70,0x81,0xE1,0x75,0x45,0x5F,0x92,0x47, + 0xB8,0x12,0xB7,0x45,0x83,0xE9,0xE9,0x4F, + 0x9E,0xA7,0x9B,0xD6,0x40,0xDC,0x96,0x25, + 0x33,0xB0,0x68,0x07,0x93,0xA3,0x8D,0x53]); + // With SHA-384, message = "sample": + // k = C345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920 + // r = B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B + // s = 19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B + run_rfc6979_test!(Sha384, U256, sample, public, private, + k vec![0xC3,0x45,0xD5,0xAB,0x3D,0xA0,0xA5,0xBC, + 0xB7,0xEC,0x8F,0x8F,0xB7,0xA7,0xE9,0x60, + 0x69,0xE0,0x3B,0x20,0x63,0x71,0xEF,0x7D, + 0x83,0xE3,0x90,0x68,0xEC,0x56,0x49,0x20], + r vec![0xB2,0xDA,0x94,0x5E,0x91,0x85,0x88,0x34, + 0xFD,0x9B,0xF6,0x16,0xEB,0xAC,0x15,0x1E, + 0xDB,0xC4,0xB4,0x5D,0x27,0xD0,0xDD,0x4A, + 0x7F,0x6A,0x22,0x73,0x9F,0x45,0xC0,0x0B], + s vec![0x19,0x04,0x8B,0x63,0xD9,0xFD,0x6B,0xCA, + 0x1D,0x9B,0xAE,0x36,0x64,0xE1,0xBC,0xB9, + 0x7F,0x72,0x76,0xC3,0x06,0x13,0x09,0x69, + 0xF6,0x3F,0x38,0xFA,0x83,0x19,0x02,0x1B]); + // With SHA-512, message = "sample": + // k = 5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC + // r = 2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E + // s = D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351 + run_rfc6979_test!(Sha512, U256, sample, public, private, + k vec![0x5A,0x12,0x99,0x44,0x31,0x78,0x54,0x85, + 0xB3,0xF5,0xF0,0x67,0x22,0x15,0x17,0x79, + 0x1B,0x85,0xA5,0x97,0xB7,0xA9,0x43,0x69, + 0x95,0xC8,0x9E,0xD0,0x37,0x46,0x68,0xFC], + r vec![0x20,0x16,0xED,0x09,0x2D,0xC5,0xFB,0x66, + 0x9B,0x8E,0xFB,0x3D,0x1F,0x31,0xA9,0x1E, + 0xEC,0xB1,0x99,0x87,0x9B,0xE0,0xCF,0x78, + 0xF0,0x2B,0xA0,0x62,0xCB,0x4C,0x94,0x2E], + s vec![0xD0,0xC7,0x6F,0x84,0xB5,0xF0,0x91,0xE1, + 0x41,0x57,0x2A,0x63,0x9A,0x4F,0xB8,0xC2, + 0x30,0x80,0x7E,0xEA,0x7D,0x55,0xC8,0xA1, + 0x54,0xA2,0x24,0x40,0x0A,0xFF,0x23,0x51]); + // With SHA-1, message = "test": + // k = 6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F + // r = C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0 + // s = 414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA + run_rfc6979_test!(Sha1, U256, test, public, private, + k vec![0x6E,0xEA,0x48,0x6F,0x9D,0x41,0xA0,0x37, + 0xB2,0xC6,0x40,0xBC,0x56,0x45,0x69,0x4F, + 0xF8,0xFF,0x4B,0x98,0xD0,0x66,0xA2,0x5F, + 0x76,0xBE,0x64,0x1C,0xCB,0x24,0xBA,0x4F], + r vec![0xC1,0x82,0x70,0xA9,0x3C,0xFC,0x60,0x63, + 0xF5,0x7A,0x4D,0xFA,0x86,0x02,0x4F,0x70, + 0x0D,0x98,0x0E,0x4C,0xF4,0xE2,0xCB,0x65, + 0xA5,0x04,0x39,0x72,0x73,0xD9,0x8E,0xA0], + s vec![0x41,0x4F,0x22,0xE5,0xF3,0x1A,0x8B,0x6D, + 0x33,0x29,0x5C,0x75,0x39,0xC1,0xC1,0xBA, + 0x3A,0x61,0x60,0xD7,0xD6,0x8D,0x50,0xAC, + 0x0D,0x3A,0x5B,0xEA,0xC2,0x88,0x4F,0xAA]); + // With SHA-224, message = "test": + // k = 06BD4C05ED74719106223BE33F2D95DA6B3B541DAD7BFBD7AC508213B6DA6670 + // r = 272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3 + // s = E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806 + run_rfc6979_test!(Sha224, U256, test, public, private, + k vec![0x06,0xBD,0x4C,0x05,0xED,0x74,0x71,0x91, + 0x06,0x22,0x3B,0xE3,0x3F,0x2D,0x95,0xDA, + 0x6B,0x3B,0x54,0x1D,0xAD,0x7B,0xFB,0xD7, + 0xAC,0x50,0x82,0x13,0xB6,0xDA,0x66,0x70], + r vec![0x27,0x2A,0xBA,0x31,0x57,0x2F,0x6C,0xC5, + 0x5E,0x30,0xBF,0x61,0x6B,0x7A,0x26,0x53, + 0x12,0x01,0x8D,0xD3,0x25,0xBE,0x03,0x1B, + 0xE0,0xCC,0x82,0xAA,0x17,0x87,0x0E,0xA3], + s vec![0xE9,0xCC,0x28,0x6A,0x52,0xCC,0xE2,0x01, + 0x58,0x67,0x22,0xD3,0x6D,0x1E,0x91,0x7E, + 0xB9,0x6A,0x4E,0xBD,0xB4,0x79,0x32,0xF9, + 0x57,0x6A,0xC6,0x45,0xB3,0xA6,0x08,0x06]); + // With SHA-256, message = "test": + // k = 1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7 + // r = 8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0 + // s = 7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E + run_rfc6979_test!(Sha256, U256, test, public, private, + k vec![0x1D,0x6C,0xE6,0xDD,0xA1,0xC5,0xD3,0x73, + 0x07,0x83,0x9C,0xD0,0x3A,0xB0,0xA5,0xCB, + 0xB1,0x8E,0x60,0xD8,0x00,0x93,0x7D,0x67, + 0xDF,0xB4,0x47,0x9A,0xAC,0x8D,0xEA,0xD7], + r vec![0x81,0x90,0x01,0x2A,0x19,0x69,0xF9,0x95, + 0x7D,0x56,0xFC,0xCA,0xAD,0x22,0x31,0x86, + 0xF4,0x23,0x39,0x8D,0x58,0xEF,0x5B,0x3C, + 0xEF,0xD5,0xA4,0x14,0x6A,0x44,0x76,0xF0], + s vec![0x74,0x52,0xA5,0x3F,0x70,0x75,0xD4,0x17, + 0xB4,0xB0,0x13,0xB2,0x78,0xD1,0xBB,0x8B, + 0xBD,0x21,0x86,0x3F,0x5E,0x7B,0x1C,0xEE, + 0x67,0x9C,0xF2,0x18,0x8E,0x1A,0xB1,0x9E]); + // With SHA-384, message = "test": + // k = 206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C + // r = 239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE + // s = 6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961 + run_rfc6979_test!(Sha384, U256, test, public, private, + k vec![0x20,0x6E,0x61,0xF7,0x3D,0xBE,0x1B,0x2D, + 0xC8,0xBE,0x73,0x6B,0x22,0xB0,0x79,0xE9, + 0xDA,0xCD,0x97,0x4D,0xB0,0x0E,0xEB,0xBC, + 0x5B,0x64,0xCA,0xD3,0x9C,0xF9,0xF9,0x1C], + r vec![0x23,0x9E,0x66,0xDD,0xBE,0x8F,0x8C,0x23, + 0x0A,0x3D,0x07,0x1D,0x60,0x1B,0x6F,0xFB, + 0xDF,0xB5,0x90,0x1F,0x94,0xD4,0x44,0xC6, + 0xAF,0x56,0xF7,0x32,0xBE,0xB9,0x54,0xBE], + s vec![0x6B,0xD7,0x37,0x51,0x3D,0x5E,0x72,0xFE, + 0x85,0xD1,0xC7,0x50,0xE0,0xF7,0x39,0x21, + 0xFE,0x29,0x9B,0x94,0x5A,0xAD,0x1C,0x80, + 0x2F,0x15,0xC2,0x6A,0x43,0xD3,0x49,0x61]); + // With SHA-512, message = "test": + // k = AFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA + // r = 89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307 + // s = C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1 + run_rfc6979_test!(Sha512, U256, test, public, private, + k vec![0xAF,0xF1,0x65,0x1E,0x4C,0xD6,0x03,0x6D, + 0x57,0xAA,0x8B,0x2A,0x05,0xCC,0xF1,0xA9, + 0xD5,0xA4,0x01,0x66,0x34,0x0E,0xCB,0xBD, + 0xC5,0x5B,0xE1,0x0B,0x56,0x8A,0xA0,0xAA], + r vec![0x89,0xEC,0x4B,0xB1,0x40,0x0E,0xCC,0xFF, + 0x8E,0x7D,0x9A,0xA5,0x15,0xCD,0x1D,0xE7, + 0x80,0x3F,0x2D,0xAF,0xF0,0x96,0x93,0xEE, + 0x7F,0xD1,0x35,0x3E,0x90,0xA6,0x83,0x07], + s vec![0xC9,0xF0,0xBD,0xAB,0xCC,0x0D,0x88,0x0B, + 0xB1,0x37,0xA9,0x94,0xCC,0x7F,0x39,0x80, + 0xCE,0x91,0xCC,0x10,0xFA,0xF5,0x29,0xFC, + 0x46,0x56,0x5B,0x15,0xCE,0xA8,0x54,0xE1]); +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 761a728..0fa1526 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,10 +12,11 @@ extern crate byteorder; extern crate cryptonum; extern crate digest; +extern crate hmac; +extern crate num; #[cfg(test)] #[macro_use] extern crate quickcheck; -extern crate num; extern crate rand; extern crate sha1; extern crate sha2; @@ -24,6 +25,11 @@ extern crate simple_asn1; /// The `rsa` module provides bare-bones support for RSA signing, verification, /// encryption, decryption, and key generation. pub mod rsa; +/// The `dsa` module provides bare-bones support for DSA signing, verification, +/// and key generation. You shouldn't need to use these if you're building a +/// new system, but might need to use them to interact with legacy systems or +/// protocols. +pub mod dsa; #[cfg(test)] mod testing; diff --git a/src/rsa/public.rs b/src/rsa/public.rs index dd9458d..1ff693b 100644 --- a/src/rsa/public.rs +++ b/src/rsa/public.rs @@ -95,44 +95,44 @@ impl FromASN1 for RSAPublic { } match rsa_size { 512 => { - let n2 = U512::from_num(n); - let e2 = U512::from_num(e); + let n2 = U512::from_num(n).ok_or(RSAError::InvalidKey)?; + let e2 = U512::from_num(e).ok_or(RSAError::InvalidKey)?; let res = RSA512Public::new(n2, e2); Ok((RSAPublic::Key512(res), rest)) } 1024 => { - let n2 = U1024::from_num(n); - let e2 = U1024::from_num(e); + let n2 = U1024::from_num(n).ok_or(RSAError::InvalidKey)?; + let e2 = U1024::from_num(e).ok_or(RSAError::InvalidKey)?; let res = RSA1024Public::new(n2, e2); Ok((RSAPublic::Key1024(res), rest)) } 2048 => { - let n2 = U2048::from_num(n); - let e2 = U2048::from_num(e); + let n2 = U2048::from_num(n).ok_or(RSAError::InvalidKey)?; + let e2 = U2048::from_num(e).ok_or(RSAError::InvalidKey)?; let res = RSA2048Public::new(n2, e2); Ok((RSAPublic::Key2048(res), rest)) } 3072 => { - let n2 = U3072::from_num(n); - let e2 = U3072::from_num(e); + let n2 = U3072::from_num(n).ok_or(RSAError::InvalidKey)?; + let e2 = U3072::from_num(e).ok_or(RSAError::InvalidKey)?; let res = RSA3072Public::new(n2, e2); Ok((RSAPublic::Key3072(res), rest)) } 4096 => { - let n2 = U4096::from_num(n); - let e2 = U4096::from_num(e); + let n2 = U4096::from_num(n).ok_or(RSAError::InvalidKey)?; + let e2 = U4096::from_num(e).ok_or(RSAError::InvalidKey)?; let res = RSA4096Public::new(n2, e2); Ok((RSAPublic::Key4096(res), rest)) } 8192 => { - let n2 = U8192::from_num(n); - let e2 = U8192::from_num(e); + let n2 = U8192::from_num(n).ok_or(RSAError::InvalidKey)?; + let e2 = U8192::from_num(e).ok_or(RSAError::InvalidKey)?; let res = RSA8192Public::new(n2, e2); Ok((RSAPublic::Key8192(res), rest)) } 15360 => { - let n2 = U15360::from_num(n); - let e2 = U15360::from_num(e); + let n2 = U15360::from_num(n).ok_or(RSAError::InvalidKey)?; + let e2 = U15360::from_num(e).ok_or(RSAError::InvalidKey)?; let res = RSA15360Public::new(n2, e2); Ok((RSAPublic::Key15360(res), rest)) } diff --git a/src/utils.rs b/src/utils.rs index e9d6e65..257263b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,27 +1,27 @@ use cryptonum::unsigned::*; use num::BigUint; -pub trait TranslateNums { - fn from_num(x: BigUint) -> Self; +pub trait TranslateNums: Sized { + fn from_num(x: BigUint) -> Option; fn to_num(&self) -> BigUint; } macro_rules! from_biguint { ($uname: ident, $size: expr) => { impl TranslateNums for $uname { - fn from_num(x: BigUint) -> $uname { + fn from_num(x: BigUint) -> Option<$uname> { let mut base_vec = x.to_bytes_be(); let target_bytes = $size / 8; + if target_bytes < base_vec.len() { + return None; + + } while target_bytes > base_vec.len() { base_vec.insert(0,0); } - while base_vec.len() > target_bytes { - base_vec.remove(0); - } - - $uname::from_bytes(&base_vec) + Some($uname::from_bytes(&base_vec)) } fn to_num(&self) -> BigUint { @@ -32,6 +32,8 @@ macro_rules! from_biguint { }; } +from_biguint!(U192, 192); +from_biguint!(U256, 256); from_biguint!(U512, 512); from_biguint!(U1024, 1024); from_biguint!(U2048, 2048);