Initial DSA support.

Should be upgraded with faster modulo operations and a
more full test suite.
This commit is contained in:
2018-05-05 21:06:11 -07:00
parent 213c75ad51
commit a2b4baa087
13 changed files with 6573 additions and 2 deletions

5
.gitignore vendored
View File

@@ -15,9 +15,14 @@ Cargo.lock
# And some Haskell stuff, because I can't shake it! # And some Haskell stuff, because I can't shake it!
**/cabal.sandbox.config **/cabal.sandbox.config
**/.cabal-sandbox **/.cabal-sandbox
# Test generation leavings
tests/rsa/GenerateRSATests.hi tests/rsa/GenerateRSATests.hi
tests/rsa/GenerateRSATests.o tests/rsa/GenerateRSATests.o
tests/rsa/gen tests/rsa/gen
tests/dsa/GenerateDSATests.hi
tests/dsa/GenerateDSATests.o
tests/dsa/gen
# And I started playing with IDEs, so ... # And I started playing with IDEs, so ...
.vscode .vscode

View File

@@ -10,6 +10,7 @@ repository = "https://github.com/acw/simple_crypto"
[dependencies] [dependencies]
digest = "^0.7.1" digest = "^0.7.1"
hmac = "^0.5.0"
num = "^0.1.42" num = "^0.1.42"
rand = "^0.3" rand = "^0.3"
sha-1 = "^0.7.0" sha-1 = "^0.7.0"

28
src/dsa/errors.rs Normal file
View File

@@ -0,0 +1,28 @@
use simple_asn1::ASN1DecodeErr;
use std::io;
#[derive(Debug)]
pub enum DSAError {
ASN1DecodeErr(ASN1DecodeErr),
InvalidParamSize
}
impl From<ASN1DecodeErr> for DSAError {
fn from(e: ASN1DecodeErr) -> DSAError {
DSAError::ASN1DecodeErr(e)
}
}
#[derive(Debug)]
pub enum DSAGenError {
RngFailure(io::Error),
InvalidSeedLength, InvalidPrimeLength, TooManyGenAttempts
}
impl From<io::Error> for DSAGenError {
fn from(e: io::Error) -> DSAGenError {
DSAGenError::RngFailure(e)
}
}

585
src/dsa/generation.rs Normal file
View File

@@ -0,0 +1,585 @@
use cryptonum::UCN;
use digest::{FixedOutput,Input};
use dsa::errors::DSAGenError;
use dsa::parameters::{DSAParameterSize,n_bits,l_bits};
use rand::Rng;
use sha2::Sha256;
use std::ops::{Add,Div,Rem,Sub};
#[derive(Debug,PartialEq)]
pub struct DSAGenEvidence {
pub first_seed: UCN,
pub p_seed: UCN,
pub q_seed: UCN,
pub pgen_counter: usize,
pub qgen_counter: usize
}
fn get_domain_parameter_seed(ev: &DSAGenEvidence) -> Vec<u8> {
let mut output = Vec::new();
let fssize = (ev.first_seed.bits() + 7) / 8;
output.append(&mut ev.first_seed.to_bytes(fssize));
let psize = (ev.p_seed.bits() + 7) / 8;
output.append(&mut ev.p_seed.to_bytes(psize));
let qsize = (ev.q_seed.bits() + 7) / 8;
output.append(&mut ev.q_seed.to_bytes(qsize));
output
}
pub fn generate_provable_primes<G: Rng>(rng: &mut G,
firstseed: &UCN,
ps: DSAParameterSize)
-> Result<(UCN, UCN, DSAGenEvidence),DSAGenError>
{
let one: UCN = UCN::from(1u64);
let two: UCN = UCN::from(2u64);
let three: UCN = UCN::from(3u64);
// See Page 38 of FIPS 186-4!
let n = n_bits(ps);
let l = l_bits(ps);
// 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, return FAILURE.
//
// Done because sum types are cool.
//
// 2. Using N as the length and firstseed as the input_seed, use the random
// prime generation routine in Appendix C.6 to obtain q, qseed and
// qgen_counter. If FAILURE is returned, then return FAILURE.
let (q, qseed, qgen_counter) = shawe_taylor(rng, n, &firstseed)?;
// 3. Using ceiling(L / 2 + 1) as the length and qseed as the input_seed,
// use the random prime generation routine in Appendix C.6 to obtain
// p0, pseed, and pgen_counter. If FAILURE is returned, then return
// FAILURE.
//
// NOTE: The ceiling isn't required. All of the values of L divide
// evenly by 2, so it's just l / 2 + 1. I'm not sure why the
// spec mentions it, frankly.
let (p0, mut pseed, mut pgen_counter) = shawe_taylor(rng, l/2 + 1, &qseed)?;
// 4. iterations = ceiling(L / outlen) - 1.
let iterations = ceildiv(&l, &256) - 1;
// 5. old_counter = pgen_counter.
let old_counter = pgen_counter;
// 6. x = 0.
let mut x_bytes = Vec::new();
// 7. For i = 0 to iterations fo
// x + x + (Hash(pseed + i) * 2^(i * outlen).
// NOTE: WE run this backwards, much like we do in shawe_taylor()
let mut i: i64 = iterations as i64;
while i >= 0 {
let bigi = UCN::from(i as u64);
let prime_i = &pseed + &bigi;
let mut hash_i = hash(&prime_i, l);
x_bytes.append(&mut hash_i);
i -= 1;
}
let x = UCN::from_bytes(&x_bytes);
// 8. pseed = pseed + iterations + 1.
pseed = &pseed + UCN::from(iterations) + &one;
// 9. x = 2^(L-1) + (x mod 2^(L-1));
let twol1: UCN = &one << (l - 1);
// 10. t = ceiling(x / (2 * q * p_0))
let twoqp0 = &two * &q * &p0;
let mut t = ceildiv(&x, &twoqp0);
loop {
// 11. If (2tqp_0 + 1) > 2^L, then t = ceiling(2^(L-1)/2qp0).
let twotqp0p1 = (&t * &twoqp0) + &one;
let twol = &one << l;
if &twotqp0p1 > &twol {
t = ceildiv(&twol1, &twoqp0);
}
// 12. p = 2tqp_0 + 1
let p = twotqp0p1;
// 13. pgen_counter = pgen_counter + 1
pgen_counter = &pgen_counter + 1;
// 14. a = 0
let mut a_bytes = Vec::new();
// 15. For i = 0 to iterations do
// a = a + (Hash(pseed + i) * 2^(i*outlen).
i = iterations as i64;
while i >= 0 {
let bigi = UCN::from(i as u64);
let prime_i = &pseed + &bigi;
let mut hash_i = hash(&prime_i, l);
a_bytes.append(&mut hash_i);
i -= 1;
}
let mut a = UCN::from_bytes(&a_bytes);
// 16. pseed = pseed + iterations + 1.
pseed = &pseed + UCN::from(iterations) + &one;
// 17. a = 2 + (a mod (p - 3))
let pm3 = &p - &three;
let amodpm3 = &a % &pm3;
a = &two + &amodpm3;
// 18. z = a^(2tq) mod p.
let twotq = &two * &t * &q;
let z = a.modexp(&twotq, &p);
// 19. If ((1 = GCD(z-1,p)) and (1 = z^p0 mod p)), then return SUCCESS
// and the values of p, q, and (optionally) pseed, qseed, pgen_counter,
// and qgen_counter.
let zm1 = &z - &one;
if (&one == &zm1.gcd(&p)) && (&one == &z.modexp(&p0, &p)) {
let evidence = DSAGenEvidence {
first_seed: firstseed.clone(),
p_seed: pseed,
q_seed: qseed,
pgen_counter: pgen_counter,
qgen_counter: qgen_counter
};
return Ok((p, q, evidence));
}
// 20. If (pgen_counter > (4L + old_counter)), then return FAILURE.
if pgen_counter > ((4 * l) + old_counter) {
return Err(DSAGenError::TooManyGenAttempts);
}
// 21. t = t + 1
t = &t + &one;
// 22. Go to step 11.
}
}
pub fn validate_provable_primes<G: Rng>(rng: &mut G,
p: &UCN, q: &UCN,
ev: &DSAGenEvidence)
-> bool
{
let one = UCN::from(1u64);
// This is from Page 40 of 186-4, section A.1.2.2.
// 1. L = len(p);
let l = ((p.bits() + 255) / 256) * 256;
// 2. N = len(q);
let n = ((q.bits() + 15) / 16) * 16;
// 3. Check that the (L, N) pair is in the list of acceptable (L, N) pairs.
// If the pair is not in the list, then return failure.
let params = match (l, n) {
(1024, 160) => DSAParameterSize::L1024N160,
(2048, 224) => DSAParameterSize::L2048N224,
(2048, 256) => DSAParameterSize::L2048N256,
(3072, 256) => DSAParameterSize::L3072N256,
_ => return false
};
// 4. If (firstseed < 2^(n-1), then return FAILURE.
let twon1 = &one << (n - 1);
if &ev.first_seed < &twon1 {
return false;
}
// 5. If (2^n <= q), then return FAILURE.
let twon = &one << n;
if &twon <= q {
return false;
}
// 6. If (2^l <= p), then return FAILURE.
let twol = &one << l;
if &twol <= p {
return false;
}
// 7. If ((p - 1) mod q /= 0), then return FAILURE.
let pm1 = p - &one;
if !pm1.rem(q).is_zero() {
return false;
}
// 8. Using L, N and firstseed, perform the constructive prime generation
// procedure in Appendix A.1.2.1.2 to obtain p_val, q_val, pseed_val,
// qseed_val, pgen_counter_val, and qgen_counter_val. If FAILURE is
// returned, or if (q_val ≠ q) or (qseed_val ≠ qseed) or
// (qgen_counter_val ≠ qgen_counter) or (p_val ≠ p) or (pseed_val ≠
// pseed) or (pgen_counter_val ≠ pgen_counter), then return FAILURE.
match generate_provable_primes(rng, &ev.first_seed, params) {
Err(_) => false,
Ok((p_val, q_val, ev2)) => {
// 9. Return SUCCESS
(&q_val == q) && (&p_val == p) && (ev == &ev2)
}
}
}
pub fn generate_verifiable_generator(p: &UCN,
q: &UCN,
ev: &DSAGenEvidence,
index: u8)
-> Result<UCN,DSAGenError>
{
// See FIPS 186-4, Section A.2.3: Verifiable Canonical Generatio of the
// Generator g
let one = UCN::from(1u64);
let two = UCN::from(2u64);
// 1. If (index is incorrect), then return INVALID.
// NOTE: Can't happen, because types.
// 2. N = len(q)
let _n = q.bits();
// 3. e = (p - 1)/q.
let e = (p - &one) / q;
// 4. count = 0.
let mut count: u16 = 0;
loop {
// 5. count = count + 1;
count = count + 1;
// 6. if (count = 0), then return INVALID.
if count == 0 {
return Err(DSAGenError::TooManyGenAttempts);
}
// 7. U = domain_parameter_seed || "ggen" || index || count
// Comment: "ggen" is the bit string 0x6767656E.
let mut u = get_domain_parameter_seed(&ev);
u.push(0x67); u.push(0x67); u.push(0x65); u.push(0x6E);
u.push(index);
u.push((count >> 8) as u8); u.push((count & 0xFF) as u8);
// 8. W = hash(U)
let mut dgst = Sha256::default();
dgst.process(&u);
let w = UCN::from_bytes(dgst.fixed_result().as_slice());
// 9. g = W^e mod p
let g = w.modexp(&e, &p);
// 10. if (g < 2), then go to step 5.
if &g >= &two {
// 11. Return VALID and the value of g.
return Ok(g);
}
}
}
pub fn verify_generator(p: &UCN, q: &UCN, ev: &DSAGenEvidence,
index: u8, g: &UCN)
-> bool
{
// FIPS 186.4, Section A.2.4!
let one = UCN::from(1u64);
let two = UCN::from(2u64);
// 1. If (index is incorrect), then return INVALID.
// NOTE: Not sure how this can be invalid.
// 2. Verify that 2 <= g <= (p - 1). If not true, return INVALID.
if g < &two {
return false;
}
if g >= p {
return false;
}
// 3. If (g^q /= 1 mod p), then return INVALID.
if g.modexp(q, p) != one {
return false;
}
// 4. N = len(q)
// let n = ((q.bits() + 15) / 15) * 15;
// 5. e = (p - 1) / q
let e = (p - &one) / q;
// 6. count = 0
let mut count: u16 = 0;
loop {
// 7. count = count + 1
count = count + 1;
// 8. if (count == 0), then return INVALID
if count == 0 {
return false;
}
// 9. U = domain_parameter_seed || "ggen" || index || count.
let mut u = get_domain_parameter_seed(&ev);
u.push(0x67); u.push(0x67); u.push(0x65); u.push(0x6E);
u.push(index);
u.push((count >> 8) as u8); u.push((count & 0xFF) as u8);
// 10. W = Hash(U)
let mut dgst = Sha256::default();
dgst.process(&u);
let w = UCN::from_bytes(dgst.fixed_result().as_slice());
// 11. computed_g = W^e mod p
let computed_g = w.modexp(&e, &p);
// 12. if (computed_g < 2), then go to step 7.
if &computed_g < &two {
continue;
}
// 13. if (computed_g == g), then return VALID, else return INVALID
return &computed_g == g;
}
}
pub fn get_input_seed<G: Rng>(rng: &mut G,
size: DSAParameterSize,
seedlen: usize)
-> Result<UCN,DSAGenError>
{
let mut firstseed = UCN::from(0u64);
let one = UCN::from(1u64);
let n = n_bits(size);
// 3. If (seedlen < N), then return FAILURE
if seedlen < n {
return Err(DSAGenError::InvalidSeedLength)
}
// 4. While firstseed < 2^(n-1) ...
let twonm1 = one << (n - 1);
while &firstseed < &twonm1 {
// Get an arbitrary sequence of seedlen bits as firstseed.
let bytes: Vec<u8> = rng.gen_iter().take(seedlen / 8).collect();
firstseed = UCN::from_bytes(&bytes);
}
// 5. Return SUCCESS and the value of firstseed
Ok(firstseed)
}
// Appendix C.6: Shawe-Taylor Random_Prime Routine. Also referenced in 186-4
// as ST_Random_Prime, so when you see that in a bit, understand that it's a
// recursive call.
fn shawe_taylor<G: Rng>(rng: &mut G, length: usize, input_seed: &UCN)
-> Result<(UCN,UCN,usize),DSAGenError>
{
// 1. If (length < 2), then return (FAILURE, 0, 0 {, 0}).
if length < 2 {
return Err(DSAGenError::InvalidPrimeLength);
}
// 2. If (length ≥ 33), then go to step 14.
if length >= 33 {
shawe_taylor_large(rng, length, input_seed)
} else {
shawe_taylor_small(length, input_seed)
}
}
fn shawe_taylor_small(length: usize, input_seed: &UCN)
-> Result<(UCN,UCN,usize),DSAGenError>
{
let one = UCN::from(1u64);
let two = UCN::from(2u64);
// 3. prime_seed = input_seed.
let mut prime_seed: UCN = input_seed.clone();
// 4. prime_gen_counter = 0
let mut prime_gen_counter = 0;
loop {
// 5. c = Hash(prime_seed) ⊕ Hash(prime_seed + 1).
let cbs = xorvecs(hash(&prime_seed, length),
hash(&(&prime_seed + &one), length));
let mut c = UCN::from_bytes(&cbs);
// 6. c = 2^(length 1) + (c mod 2^(length 1))
let twolm1: UCN = &one << (length - 1);
c = &twolm1 + (c % &twolm1);
// 7. c = (2 floor(c / 2)) + 1.
c = ((c >> 1) << 1) + &one;
// 8. prime_gen_counter = prime_gen_counter + 1.
prime_gen_counter = prime_gen_counter + 1;
// 9. prime_seed = prime_seed + 2.
prime_seed = prime_seed + &two;
// 10. Perform a deterministic primality test on c. For example, since
// c is small, its primality can be tested by trial division. See
// Appendix C.7.
let c_is_prime = prime_test(&c);
// 11. If (c is a prime number), then
if c_is_prime {
// 11.1 prime = c.
let prime = c;
// 11.2 Return (SUCCESS, prime, prime_seed {, prime_gen_counter}).
return Ok((prime, prime_seed.clone(), prime_gen_counter))
}
// 12. If (prime_gen_counter > (4 length)), then
// return (FAILURE, 0, 0 {, 0}).
if prime_gen_counter > (4 * length) {
return Err(DSAGenError::TooManyGenAttempts);
}
// 13. Go to step 5.
}
}
fn shawe_taylor_large<G: Rng>(rng: &mut G, length: usize, input_seed: &UCN)
-> Result<(UCN,UCN,usize),DSAGenError>
{
let one = UCN::from(1u64);
let two = UCN::from(2u64);
let three = UCN::from(3u64);
// 14. (status, c0, prime_seed, prime_gen_counter) =
// (ST_Random_Prime ((ceiling(length / 2) + 1), input_seed).
let len2: usize = ceildiv(&length, &2);
let (c0, mut prime_seed, mut prime_gen_counter) =
shawe_taylor( rng, len2 + 1, input_seed )?;
// 15. If FAILURE is returned, return (FAILURE, 0, 0 {, 0}).
// 16. iterations = ceiling(length / outlen) 1.
let outlen = 256; // the size of the hash function output in bits
let iterations = ceildiv(&length, &outlen) - 1;
// 17. old_counter = prime_gen_counter.
let old_counter = prime_gen_counter;
// 18. x = 0.
let mut x_bytes = Vec::new();
// 19. For i = 0 to iterations do
// x = x + (Hash(prime_seed + i) 2^(i * outlen)).
//
// We're going to actually run this backwards. What this computation
// does is essentially built up a large vector of hashes, one per
// iteration, shifting them bast each other via the 2^(i * outlen)
// term. So we'll just do this directly.
let mut i: i64 = iterations as i64;
while i >= 0 {
let bigi = UCN::from(i as u64);
let prime_i = &prime_seed + &bigi;
let mut hash_i = hash(&prime_i, length);
x_bytes.append(&mut hash_i);
i -= 1;
}
let mut x = UCN::from_bytes(&x_bytes);
// 20. prime_seed = prime_seed + iterations + 1.
prime_seed = &prime_seed + UCN::from(iterations) + &one;
// 21. x = 2^(length 1) + (x mod 2^(length 1)).
let twolm1 = &one << (length - 1);
x = &twolm1 + (&x % &twolm1);
// 22. t = ceiling(x / (2c0)).
let twoc0 = &two * &c0;
let mut t: UCN = ceildiv(&x, &twoc0);
loop {
// 23. If (2tc0 + 1 > 2^length), then
// t = ceiling(2^(length 1) / (2c0)).
let twotc0 = &t * &twoc0;
if (&twotc0 + &one) > (&one << length) {
t = ceildiv(&twolm1, &twoc0);
}
// 24. c = 2tc0 + 1.
let c = &twotc0 + &one;
// 25. prime_gen_counter = prime_gen_counter + 1.
prime_gen_counter = prime_gen_counter + 1;
// 26. a = 0.
let mut a_bytes = Vec::new();
// 27. For i = 0 to iterations do
// a = a + (Hash(prime_seed + i) 2 i * outlen).
//
// As with the last time we did this, we're going to do this more
// constructively
i = iterations as i64;
while i >= 0 {
let bigi = UCN::from(i as u64);
let prime_i = &prime_seed + &bigi;
let mut hash_i = hash(&prime_i, length);
a_bytes.append(&mut hash_i);
i -= 1;
}
let mut a = UCN::from_bytes(&a_bytes);
// 28. prime_seed = prime_seed + iterations + 1.
prime_seed = &prime_seed + UCN::from(iterations) + &one;
// 29. a = 2 + (a mod (c 3)).
a = &two + (a % (&c - &three));
// 30. z = a^2t mod c.
let z: UCN = a.modexp(&(&two * &t), &c);
// 31. If ((1 = GCD(z 1, c)) and (1 = z^c_0 mod c)), then
let gcd_ok = &one == &c.gcd(&(&z - &one));
let modexp_ok = &one == &z.modexp(&c0, &c);
if gcd_ok && modexp_ok {
// 31.1 prime = c.
let prime = c;
// 31.2 Return (SUCCESS, prime, prime_seed {, prime_gen_counter}).
return Ok((prime, prime_seed, prime_gen_counter));
}
// 32. If (prime_gen_counter ≥ ((4 length) + old_counter)), then
// return (FAILURE, 0, 0 {, 0}).
let limit = (4 * length) + old_counter;
if prime_gen_counter >= limit {
return Err(DSAGenError::TooManyGenAttempts)
}
// 33. t = t + 1.
t = t + &one;
// 34. Go to step 23.
}
}
fn ceildiv<T>(a: &T, b: &T) -> T
where T: Add<Output=T>,
T: Sub<Output=T>,
T: Div<Output=T>,
T: From<usize>,
T: Clone
{
let aclone: T = a.clone();
let bclone: T = b.clone();
let one: T = T::from(1 as usize);
let x: T = (aclone + bclone.clone()) - one;
let res = x / bclone;
res
}
fn prime_test(x: &UCN) -> bool {
let two = UCN::from(2 as u64);
let three = UCN::from(3 as u64);
let five = UCN::from(5 as u64);
if x.is_even() {
if x == &two {
return true;
}
return false;
}
if x.is_multiple_of(&three) {
return false;
}
if x.is_multiple_of(&five) {
return false;
}
let mut divisor = UCN::from(7 as u32);
let sqrtx = isqrt(&x);
while &divisor < &sqrtx {
if x.is_multiple_of(&divisor) {
return false;
}
divisor = next_divisor(divisor);
}
true
}
fn isqrt(x: &UCN) -> UCN {
let mut num = x.clone();
let mut res = UCN::from(0u64);
let one = UCN::from(1u64);
let mut bit = one << num.bits();
while &bit > &num {
bit >>= 2;
}
while !bit.is_zero() {
if num >= (&res + &bit) {
num = &num - (&res + &bit);
res = (&res >> 1) + &bit;
} else {
res >>= 1;
}
bit >>= 2;
}
res
}
fn next_divisor(input: UCN) -> UCN {
let two = UCN::from(2 as u64);
let three = UCN::from(3 as u64);
let five = UCN::from(5 as u64);
let mut x = input;
loop {
x = &x + &two;
if x.is_multiple_of(&three) {
continue;
}
if x.is_multiple_of(&five) {
continue;
}
return x;
}
}
fn hash(x: &UCN, len: usize) -> Vec<u8> {
let bytelen = len / 8;
let base = x.to_bytes(bytelen);
let mut dgst = Sha256::default();
dgst.process(&base);
dgst.fixed_result().as_slice().to_vec()
}
fn xorvecs(a: Vec<u8>, b: Vec<u8>) -> Vec<u8> {
assert!(a.len() == b.len());
let mut c = Vec::with_capacity(a.len());
for (a,b) in a.iter().zip(b.iter()) {
c.push(a ^ b);
}
c
}

644
src/dsa/gold_tests.rs Normal file
View File

@@ -0,0 +1,644 @@
use cryptonum::UCN;
use digest::{FixedOutput,Input};
use dsa::generation::*;
use dsa::rfc6979::*;
use dsa::parameters::*;
use dsa::private::DSAPrivate;
use dsa::public::DSAPublic;
use rand::{OsRng,Rng};
use sha1::Sha1;
use sha2::{Sha224,Sha256,Sha384,Sha512};
use simple_asn1::{der_decode,der_encode};
use testing::run_test;
const NUM_TESTS: u32 = 2;
#[test]
#[ignore]
fn pqg_generation_checks() {
let mut rng = OsRng::new().unwrap();
let params = DSAParameterSize::L1024N160;
for _ in 0..NUM_TESTS {
let seed = get_input_seed(&mut rng,params,n_bits(params)).unwrap();
let (p, q, ev) =
generate_provable_primes(&mut rng, &seed, params).unwrap();
assert!(validate_provable_primes(&mut rng, &p, &q, &ev));
let index = rng.gen::<u8>();
let g = generate_verifiable_generator(&p, &q, &ev, index).unwrap();
assert!(verify_generator(&p, &q, &ev, index, &g));
}
}
#[test]
fn dsa_verification_tests()
{
run_test("tests/dsa/signature.test", 9, |case| {
let (neg0, pbytes) = case.get("p").unwrap();
let (neg1, gbytes) = case.get("g").unwrap();
let (neg2, qbytes) = case.get("q").unwrap();
let (neg4, ybytes) = case.get("y").unwrap();
let (neg5, hbytes) = case.get("h").unwrap();
let (neg6, msg) = case.get("m").unwrap();
let (neg7, rbytes) = case.get("r").unwrap();
let (neg8, sbytes) = case.get("s").unwrap();
assert!(!neg0 & !neg1 & !neg2 & !neg4 &
!neg5 & !neg6 & !neg7 & !neg8);
let p = UCN::from_bytes(pbytes);
let g = UCN::from_bytes(gbytes);
let q = UCN::from_bytes(qbytes);
let params = DSAParameters::new(p, g, q).unwrap();
let y = UCN::from_bytes(ybytes);
let public = DSAPublic::new(&params, y);
let r = UCN::from_bytes(rbytes);
let s = UCN::from_bytes(sbytes);
let sig = DSASignature{ r: r, s: s };
match usize::from(UCN::from_bytes(hbytes)) {
0x1 => assert!(public.verify::<Sha1>(msg, &sig)),
0x224 => assert!(public.verify::<Sha224>(msg, &sig)),
0x256 => assert!(public.verify::<Sha256>(msg, &sig)),
0x384 => assert!(public.verify::<Sha384>(msg, &sig)),
0x512 => assert!(public.verify::<Sha512>(msg, &sig)),
v => panic!("Bad hash size {}!", v)
}
});
}
#[test]
fn dsa_signing_tests()
{
run_test("tests/dsa/signature.test", 9, |case| {
let (neg0, pbytes) = case.get("p").unwrap();
let (neg1, gbytes) = case.get("g").unwrap();
let (neg2, qbytes) = case.get("q").unwrap();
let (neg3, xbytes) = case.get("x").unwrap();
let (neg4, ybytes) = case.get("y").unwrap();
let (neg5, hbytes) = case.get("h").unwrap();
let (neg6, msg) = case.get("m").unwrap();
assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4 & !neg5 & !neg6);
let p = UCN::from_bytes(pbytes);
let g = UCN::from_bytes(gbytes);
let q = UCN::from_bytes(qbytes);
let params = DSAParameters::new(p, g, q).unwrap();
let y = UCN::from_bytes(ybytes);
let public = DSAPublic::new(&params, y);
let x = UCN::from_bytes(xbytes);
let private = DSAPrivate::new(&params, x);
let hash_size = usize::from(UCN::from_bytes(hbytes));
let sig = match hash_size {
0x1 => private.sign::<Sha1>(msg),
0x224 => private.sign::<Sha224>(msg),
0x256 => private.sign::<Sha256>(msg),
0x384 => private.sign::<Sha384>(msg),
0x512 => private.sign::<Sha512>(msg),
v => panic!("Bad hash size {}!", v)
};
match usize::from(UCN::from_bytes(hbytes)) {
0x1 => assert!(public.verify::<Sha1>(msg, &sig)),
0x224 => assert!(public.verify::<Sha224>(msg, &sig)),
0x256 => assert!(public.verify::<Sha256>(msg, &sig)),
0x384 => assert!(public.verify::<Sha384>(msg, &sig)),
0x512 => assert!(public.verify::<Sha512>(msg, &sig)),
v => panic!("Bad hash size {}!", v)
}
});
}
macro_rules! run_rfc6979_test {
($hash: ty, $val: ident, $public: ident, $private: ident,
k $k: expr,
r $r: expr,
s $s: expr) => ({
let mut digest = <$hash>::default();
digest.process(&$val);
let h1 = digest.fixed_result().as_slice().to_vec();
let rbytes = $r;
let sbytes = $s;
let r = UCN::from_bytes(&rbytes);
let s = UCN::from_bytes(&sbytes);
let mut iter = KIterator::<$hash>::new(&h1,
n_bits($public.params.size),
&$public.params.q,
&$private.x);
let next = iter.next().unwrap();
let size = (next.bits() + 7) / 8;
let k1 = next.to_bytes(size);
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 = UCN::from_bytes(&pbytes);
let q = UCN::from_bytes(&qbytes);
let g = UCN::from_bytes(&gbytes);
let params = DSAParameters::new(p, g, q).unwrap();
let x = UCN::from_bytes(&xbytes);
let y = UCN::from_bytes(&ybytes);
let private = DSAPrivate::new(&params, x);
let public = DSAPublic::new(&params, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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 = UCN::from_bytes(&pbytes);
let q = UCN::from_bytes(&qbytes);
let g = UCN::from_bytes(&gbytes);
let params = DSAParameters::new(p, g, q).unwrap();
let x = UCN::from_bytes(&xbytes);
let y = UCN::from_bytes(&ybytes);
let private = DSAPrivate::new(&params, x);
let public = DSAPublic::new(&params, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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]);
}

77
src/dsa/mod.rs Normal file
View File

@@ -0,0 +1,77 @@
mod errors;
mod generation;
#[cfg(test)]
mod gold_tests;
mod parameters;
mod public;
mod private;
mod rfc6979;
pub use self::public::DSAPublic;
pub use self::private::DSAPrivate;
pub use self::rfc6979::DSASignature;
use cryptonum::UCN;
use rand::{OsRng,Rng};
use self::errors::*;
use self::parameters::*;
/// A DSA key pair
#[derive(Clone,Debug,PartialEq)]
pub struct DSAKeyPair {
pub private: DSAPrivate,
pub public: DSAPublic
}
impl DSAKeyPair {
pub fn generate(size: DSAParameterSize)
-> Result<DSAKeyPair,DSAGenError>
{
let mut rng = OsRng::new()?;
DSAKeyPair::generate_rng(&mut rng, size)
}
pub fn generate_rng<G: Rng>(rng: &mut G, size: DSAParameterSize)
-> Result<DSAKeyPair,DSAGenError>
{
let params = DSAParameters::generate_w_rng(rng, size)?;
DSAKeyPair::generate_w_params_rng(rng, &params)
}
pub fn generate_w_params(params: &DSAParameters)
-> Result<DSAKeyPair,DSAGenError>
{
let mut rng = OsRng::new()?;
DSAKeyPair::generate_w_params_rng(&mut rng, params)
}
pub fn generate_w_params_rng<G: Rng>(rng: &mut G, params: &DSAParameters)
-> Result<DSAKeyPair,DSAGenError>
{
// 1. N = len(q); L = len(p);
let n = n_bits(params.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<u8> = rng.gen_iter().take(n + 8).collect();
// 5. Convert returned_bits to the (non-negative) integer c.
let c = UCN::from_bytes(&returned_bits);
// 6. x = (c mod (q-1)) + 1.
let one = UCN::from(1 as u64);
let x = (&c % (&params.q - &one)) + &one;
// 7. y = g^x mod p
let y = params.g.modexp(&x, &params.p);
// 8. Return SUCCESS, x, and y.
let private = DSAPrivate { params: params.clone(), x: x };
let public = DSAPublic { params: params.clone(), y: y };
Ok(DSAKeyPair {
private: private,
public: public
})
}
}

113
src/dsa/parameters.rs Normal file
View File

@@ -0,0 +1,113 @@
use cryptonum::UCN;
use dsa::errors::*;
use dsa::generation::{DSAGenEvidence,verify_generator,
get_input_seed,generate_provable_primes,
generate_verifiable_generator,
validate_provable_primes};
use rand::{OsRng,Rng};
/// These are the legal lengths for L and N when using DSA; essentially,
/// the bit sizes available for the algorithms.
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum DSAParameterSize { L1024N160, L2048N224, L2048N256, L3072N256 }
pub fn n_bits(ps: DSAParameterSize) -> usize {
match ps {
DSAParameterSize::L1024N160 => 160,
DSAParameterSize::L2048N224 => 224,
DSAParameterSize::L2048N256 => 256,
DSAParameterSize::L3072N256 => 256,
}
}
pub fn l_bits(ps: DSAParameterSize) -> usize {
match ps {
DSAParameterSize::L1024N160 => 1024,
DSAParameterSize::L2048N224 => 2048,
DSAParameterSize::L2048N256 => 2048,
DSAParameterSize::L3072N256 => 3072,
}
}
/// A set of DSA parameters, which are shared across both the public and private
/// keys.
#[derive(Clone,Debug,PartialEq)]
pub struct DSAParameters {
pub size: DSAParameterSize,
pub p: UCN,
pub g: UCN,
pub q: UCN,
}
impl DSAParameters {
/// Generate a new set of DSA parameters, from a certificate file or some
/// other source. This will try to find an appropriate size based on the
/// size of the values provided, but will fail (returning
/// `DSAError::InvalidParamSize`) if it can't find a reasonable one.
pub fn new(p: UCN, g: UCN, q: UCN)
-> Result<DSAParameters,DSAError>
{
let l = ((p.bits() + 255) / 256) * 256;
let n = ((q.bits() + 15) / 16) * 16;
let size = match (l, n) {
(1024, 160) => DSAParameterSize::L1024N160,
(2048, 224) => DSAParameterSize::L2048N224,
(2048, 256) => DSAParameterSize::L2048N256,
(3072, 256) => DSAParameterSize::L3072N256,
_ => return Err(DSAError::InvalidParamSize)
};
Ok(DSAParameters{ size: size, p: p, g: g, q: q })
}
/// Generate a new set of DSA parameters for use. You probably shouldn't be
/// doing this. This is equivalent to calling `generate_w_rng` with
/// `OsRng`, which is supposed to be cryptographically sound.
pub fn generate(ps: DSAParameterSize)
-> Result<DSAParameters,DSAGenError>
{
let mut rng = OsRng::new()?;
DSAParameters::generate_w_rng(&mut rng, ps)
}
/// Generate a new set of DSA parameters for use, using the given entropy
/// source. I would normally include a note here about making sure to use
/// a good one, but if you're using DSA you've already given up a little
/// bit of the high ground, there.
pub fn generate_w_rng<G: Rng>(rng: &mut G, ps: DSAParameterSize)
-> Result<DSAParameters,DSAGenError>
{
let firstseed = get_input_seed(rng, ps, n_bits(ps))?;
let (p, q, ev) = generate_provable_primes(rng, &firstseed, ps)?;
DSAParameters::generate_g(ps, p, q, ev, 0)
}
/// Using the given p and q values and an index, create a new DSAParameters
/// by creating a new generator g that works with p and q.
fn generate_g(ps: DSAParameterSize,
p: UCN, q: UCN,
ev: DSAGenEvidence,
idx: u8)
-> Result<DSAParameters, DSAGenError>
{
let g = generate_verifiable_generator(&p, &q, &ev, idx)?;
Ok(DSAParameters{ size: ps, p: p, q: q, g: g })
}
/// Given the provided evidence, validate that the domain parameters
/// were appropriately constructed.
pub fn verify(&self, ev: &DSAGenEvidence, idx: u8) -> bool {
let mut rng = OsRng::new().unwrap();
self.verify_w_rng(&mut rng, ev, idx)
}
/// Given the set of inputs you used to generate your system, verify that
/// everything makes sense.
pub fn verify_w_rng<G: Rng>(&self, r: &mut G, ev: &DSAGenEvidence, idx: u8)
-> bool
{
validate_provable_primes(r, &self.p, &self.q, ev) &&
verify_generator(&self.p, &self.q, ev, idx, &self.g)
}
}

88
src/dsa/private.rs Normal file
View File

@@ -0,0 +1,88 @@
use cryptonum::UCN;
use digest::{BlockInput,FixedOutput,Input};
use digest::generic_array::ArrayLength;
use dsa::parameters::{DSAParameters,n_bits};
use dsa::rfc6979::{DSASignature,KIterator,bits2int};
use hmac::Hmac;
use std::ops::Rem;
/// A DSA private key.
#[derive(Clone,Debug,PartialEq)]
pub struct DSAPrivate {
pub params: DSAParameters,
pub(crate) x: UCN
}
impl DSAPrivate {
pub fn new(params: &DSAParameters, x: UCN) -> DSAPrivate {
DSAPrivate {
params: params.clone(),
x: x
}
}
pub fn sign<Hash>(&self, m: &[u8]) -> DSASignature
where
Hash: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<Hash>: Clone,
Hash::BlockSize: ArrayLength<u8>
{
// 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 mut digest = <Hash>::default();
digest.process(m);
let n = n_bits(self.params.size);
let h1: Vec<u8> = digest.fixed_result()
.as_slice()
.iter()
.map(|x| *x)
.collect();
let h0 = bits2int(&h1, n);
let h = h0.rem(&self.params.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>::new(&h1, n, &self.params.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 r = self.params.g.modexp(&k, &self.params.p) % &self.params.q;
if r.is_zero() {
continue;
}
// 4. The value s (modulo q) is computed:
//
// s = (h+x*r)/k mod q
//
// The pair (r, s) is the signature.
let kinv = k.modinv(&self.params.q);
let s = ((&h + (&self.x * &r)) * &kinv) % &self.params.q;
return DSASignature{ r: r, s: s };
}
panic!("The world is broken; couldn't find a k in sign().");
}
}

72
src/dsa/public.rs Normal file
View File

@@ -0,0 +1,72 @@
use cryptonum::{SCN,UCN};
use digest::{FixedOutput,Input};
use dsa::parameters::{DSAParameters,n_bits};
use dsa::rfc6979::DSASignature;
use num::BigInt;
use simple_asn1::{ASN1Block,ToASN1,ASN1EncodeErr,ASN1Class};
use std::cmp::min;
use std::ops::Rem;
/// A DSA key pair
#[derive(Clone,Debug,PartialEq)]
pub struct DSAPublic {
pub params: DSAParameters,
pub y: UCN
}
impl DSAPublic {
pub fn new(params: &DSAParameters, y: UCN) -> DSAPublic {
DSAPublic {
params: params.clone(),
y: y
}
}
pub fn verify<Hash>(&self, m: &[u8], sig: &DSASignature) -> bool
where Hash: Clone + Default + Input + FixedOutput
{
if sig.r >= self.params.q {
return false;
}
if sig.s >= self.params.q {
return false;
}
// w = (s')^-1 mod q;
let w = sig.s.modinv(&self.params.q);
// z = the leftmost min(N, outlen) bits of Hash(M').
let mut digest = <Hash>::default();
digest.process(m);
let z = { let mut bytes: Vec<u8> = digest.fixed_result()
.as_slice()
.iter()
.map(|x| *x)
.collect();
let n = n_bits(self.params.size) / 8;
let len = min(n, bytes.len());
bytes.truncate(len);
UCN::from_bytes(&bytes) };
// u1 = (zw) mod q
let u1 = (&z * &w).rem(&self.params.q);
// u2 = (rw) mod q
let u2 = (&sig.r * &w).rem(&self.params.q);
// 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 v = (&v_1 * &v_2).rem(&self.params.p)
.rem(&self.params.q);
// if v = r, then the signature is verified
v == sig.r
}
}
impl ToASN1 for DSAPublic {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let inty = SCN::from(self.y.clone());
let yblock = ASN1Block::Integer(c, 0, BigInt::from(inty));
Ok(vec![yblock])
}
}

324
src/dsa/rfc6979.rs Normal file
View File

@@ -0,0 +1,324 @@
use cryptonum::UCN;
use digest::{BlockInput,FixedOutput,Input};
use digest::generic_array::ArrayLength;
use hmac::{Hmac,Mac};
use num::{BigInt,Signed};
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,
FromASN1, ToASN1};
use std::clone::Clone;
#[allow(non_snake_case)]
pub struct KIterator<H>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
H::BlockSize : ArrayLength<u8>
{
hmac_k: Hmac<H>,
V: Vec<u8>,
q: UCN,
qlen: usize
}
impl<H> KIterator<H>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H::BlockSize : ArrayLength<u8>
{
pub fn new(h1: &[u8], qlen: usize, q: &UCN, x: &UCN) -> KIterator<H>
{
// 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::<H>::new(&K).unwrap(),
V: V,
q: q.clone(),
qlen: qlen
}
}
}
impl<H> Iterator for KIterator<H>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H::BlockSize : ArrayLength<u8>
{
type Item = UCN;
fn next(&mut self) -> Option<UCN> {
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 = 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::<H>::new(&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) -> UCN {
let mut value = UCN::from_bytes(x);
let vlen = x.len() * 8;
if vlen > qlen {
value >>= vlen - qlen;
}
value
}
fn bits2octets(x: &[u8], q: &UCN, qlen: usize) -> Vec<u8> {
let z1 = bits2int(x, qlen);
let res = if &z1 > q { z1 - q } else { z1 };
int2octets(&res, qlen)
}
fn int2octets(x: &UCN, qlen_bits: usize) -> Vec<u8> {
let qlen_bytes = (qlen_bits + 7) / 8;
x.to_bytes(qlen_bytes)
}
fn runhmac<H>(base: &Hmac<H>, m: &[u8]) -> Vec<u8>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H::BlockSize : ArrayLength<u8>
{
let mut runner = base.clone();
runner.input(&m);
runner.result().code().as_slice().to_vec()
}
fn hmac<H>(k: &[u8], m: &[u8]) -> Vec<u8>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H::BlockSize : ArrayLength<u8>
{
let mut runner = Hmac::<H>::new(&k).unwrap();
runner.input(&m);
runner.result().code().as_slice().to_vec()
}
/// A DSA Signature
#[derive(Clone,Debug,PartialEq)]
pub struct DSASignature {
pub r: UCN,
pub s: UCN
}
#[derive(Clone,Debug,PartialEq)]
pub enum DSADecodeError {
ASN1Error(ASN1DecodeErr),
NoSignatureFound,
NegativeSigValues
}
impl From<ASN1DecodeErr> for DSADecodeError {
fn from(a: ASN1DecodeErr) -> DSADecodeError {
DSADecodeError::ASN1Error(a)
}
}
impl FromASN1 for DSASignature {
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)) => {
if rint.is_negative() || sint.is_negative() {
return Err(DSADecodeError::NegativeSigValues)
}
let r = UCN::from(rint);
let s = UCN::from(sint);
Ok((DSASignature{ r: r, s: s }, rest))
}
_ => Err(DSADecodeError::NoSignatureFound)
}
}
_ => Err(DSADecodeError::NoSignatureFound)
}
}
}
impl ToASN1 for DSASignature {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let rb = ASN1Block::Integer(c, 0, BigInt::from(self.r.clone()));
let sb = ASN1Block::Integer(c, 0, BigInt::from(self.s.clone()));
Ok(vec![ASN1Block::Sequence(c, 0, vec![rb,sb])])
}
}
#[cfg(test)]
mod tests {
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 = UCN::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 = UCN::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 = UCN::from_bytes(&QBYTES);
let x = UCN::from_bytes(&XBYTES);
let mut iter = KIterator::<Sha256>::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 = UCN::from_bytes(&target);
assert_eq!(x, x2);
}
}
}
}

View File

@@ -11,6 +11,7 @@
//! off to more detailed modules. Help requested! //! off to more detailed modules. Help requested!
extern crate digest; extern crate digest;
extern crate hmac;
extern crate num; extern crate num;
#[cfg(test)] #[cfg(test)]
#[macro_use] #[macro_use]
@@ -20,13 +21,18 @@ extern crate sha1;
extern crate sha2; extern crate sha2;
extern crate simple_asn1; extern crate simple_asn1;
/// The cryptonum module provides support for large numbers for use in various /// The `cryptonum` module provides support for large numbers for use in various
/// cryptographically-relevant algorithms. /// cryptographically-relevant algorithms.
pub mod cryptonum; pub mod cryptonum;
/// The rsa module provides support for RSA-related core algorithms, including /// The `rsa` module provides support for RSA-related core algorithms, including
/// signing / verification and encryption / decryption. You can also generate /// signing / verification and encryption / decryption. You can also generate
/// key material there. /// key material there.
pub mod rsa; pub mod rsa;
/// The `dsa` module provides support for DSA-related signing and verification
/// algorithms, as well as key generation. That being said: don't use this,
/// unless you've got a legacy application or system that you're trying to
/// interact with. DSA is almost always the wrong choice.
pub mod dsa;
#[cfg(test)] #[cfg(test)]
mod testing; mod testing;

View File

@@ -0,0 +1,128 @@
{-# LANGUAGE ScopedTypeVariables #-}
import Control.Monad
import Codec.Crypto.DSA.Pure
import Control.Concurrent
import Crypto.Random.DRBG
import Data.Bits
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BSC
import qualified Data.ByteString.Lazy as BSL
import Data.Char
import Data.List
import qualified Data.Map.Strict as Map
import GHC.Integer.GMP.Internals
import Numeric
import System.IO
import System.ProgressBar
import System.Random
import Debug.Trace
numThreads :: Int
numThreads = 4
keyIterations :: [ParameterSizes]
keyIterations = replicate 500 L1024_N160 ++
replicate 500 L2048_N224 ++
replicate 200 L2048_N256 ++
replicate 100 L3072_N256
randomByteString :: CryptoRandomGen g => g -> (BS.ByteString, g)
randomByteString g =
let Right (bs, g') = genBytes 2 g
[h,l] = BS.unpack bs
x = (fromIntegral h `shiftL` 8) + (fromIntegral l)
Right (res, g'') = genBytes (x `mod` 1024) g'
in (res, g'')
randomHash :: CryptoRandomGen g => g -> ((HashFunction, String), g)
randomHash g =
randomElement g [(SHA1, "1"),
(SHA224, "224"),
(SHA256, "256"),
(SHA384, "384"),
(SHA512, "512")]
showBinary :: BS.ByteString -> String
showBinary v = go v
where
go bstr =
case BS.uncons bstr of
Nothing ->
""
Just (x, rest) ->
let high = showHex (x `shiftR` 4) ""
low = showHex (x .&. 0xF) ""
in high ++ low ++ go rest
dump :: Handle -> [(String,String)] -> IO ()
dump hndl = mapM_ writeItem
where
writeItem (name, value) =
do hPutStr hndl name
hPutStr hndl ": "
hPutStrLn hndl value
mkProgress x y = Progress (fromIntegral x) (fromIntegral y)
runSignatureGenerator :: Chan ParameterSizes ->
Chan [(String,String)] ->
IO ()
runSignatureGenerator inputs outputs =
do rng0 :: GenBuffered SystemRandom <- newGenIO
go Nothing rng0
where
go Nothing rng0 =
do keySize <- readChan inputs
go (Just keySize) rng0
go (Just keySize) g0 =
do let Right (public, private, _, g1) = generateKeyPair g0 keySize
let (msg, g2) = randomByteString g1
let msg' = BSL.fromStrict msg
let ((hash, hashname), g3) = randomHash g2
case signMessage' hash kViaRFC6979 g3 private msg' of
Left _ ->
go (Just keySize) g3
Right (sig, g4) ->
do unless (verifyMessage' hash public msg' sig) $
fail "DSA verification failed internally."
let params = private_params private
writeChan outputs [("p", showHex (params_p params) ""),
("g", showHex (params_g params) ""),
("q", showHex (params_q params) ""),
("x", showHex (private_x private) ""),
("y", showHex (public_y public) ""),
("h", hashname),
("m", showBinary msg),
("r", showHex (sign_r sig) ""),
("s", showHex (sign_s sig) "")]
go Nothing g4
writeData :: Chan [(String,String)] -> (Progress -> IO ()) -> Handle -> IO ()
writeData outputChan progressBar hndl = go 0
where
count = fromIntegral (length keyIterations)
go x | x == count = return ()
| otherwise = do output <- readChan outputChan
dump hndl output
hFlush hndl
progressBar (Progress (x + 1) count)
go (x + 1)
main :: IO ()
main =
do sizeChan <- newChan
outputChan <- newChan
--
sigthrs <- replicateM numThreads $
forkIO $ runSignatureGenerator sizeChan outputChan
let bar = autoProgressBar (msg "Generating signature tests") percentage 60
writeList2Chan sizeChan keyIterations
g1 <- withFile "signature.test" WriteMode (writeData outputChan bar)
return ()
randomElement :: CryptoRandomGen g => g -> [a] -> (a, g)
randomElement g xs =
let Right (bs, g') = genBytes 1 g
x = BS.head bs
idx = fromIntegral x `mod` length xs
in (xs !! idx, g')

4500
tests/dsa/signature.test Normal file

File diff suppressed because it is too large Load Diff