Initial DSA support.
Should be upgraded with faster modulo operations and a more full test suite.
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -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
|
||||||
@@ -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
28
src/dsa/errors.rs
Normal 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
585
src/dsa/generation.rs
Normal 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
644
src/dsa/gold_tests.rs
Normal 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(¶ms, 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(¶ms, y);
|
||||||
|
let x = UCN::from_bytes(xbytes);
|
||||||
|
let private = DSAPrivate::new(¶ms, 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(¶ms, x);
|
||||||
|
let public = DSAPublic::new(¶ms, 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(¶ms, x);
|
||||||
|
let public = DSAPublic::new(¶ms, 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
77
src/dsa/mod.rs
Normal 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, ¶ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 % (¶ms.q - &one)) + &one;
|
||||||
|
// 7. y = g^x mod p
|
||||||
|
let y = params.g.modexp(&x, ¶ms.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
113
src/dsa/parameters.rs
Normal 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
88
src/dsa/private.rs
Normal 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
72
src/dsa/public.rs
Normal 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
324
src/dsa/rfc6979.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/lib.rs
10
src/lib.rs
@@ -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;
|
||||||
|
|||||||
128
tests/dsa/GenerateDSATests.hs
Normal file
128
tests/dsa/GenerateDSATests.hs
Normal 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
4500
tests/dsa/signature.test
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user