ECC Private key support.

This commit is contained in:
2019-02-04 19:27:23 -08:00
parent 8a771c05a4
commit 322701ad6c

View File

@@ -2,7 +2,7 @@ use cryptonum::signed::*;
use cryptonum::unsigned::*; use cryptonum::unsigned::*;
use digest::{BlockInput,Digest,Input,FixedOutput,Reset}; use digest::{BlockInput,Digest,Input,FixedOutput,Reset};
use dsa::rfc6979::{DSASignature,KIterator,bits2int}; use dsa::rfc6979::{DSASignature,KIterator,bits2int};
use ecdsa::curve::{EllipticCurve,P192}; use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
use ecdsa::point::{ECCPoint,Point}; use ecdsa::point::{ECCPoint,Point};
use hmac::{Hmac,Mac}; use hmac::{Hmac,Mac};
@@ -10,14 +10,30 @@ pub struct ECCPrivate<Curve: EllipticCurve> {
d: Curve::Unsigned d: Curve::Unsigned
} }
impl ECCPrivate<P192> pub trait ECCPrivateKey {
type Unsigned;
fn new(d: Self::Unsigned) -> Self;
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<Self::Unsigned>
where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac;
}
macro_rules! generate_privates
{ {
pub fn new(d: U192) -> ECCPrivate<P192> ($curve: ident, $base: ident, $sig: ident, $dbl: ident, $quad: ident) => {
impl ECCPrivateKey for ECCPrivate<$curve>
{
type Unsigned = $base;
fn new(d: $base) -> ECCPrivate<$curve>
{ {
ECCPrivate{ d } ECCPrivate{ d }
} }
pub fn sign<Hash>(&self, m: &[u8]) -> DSASignature<U192> fn sign<Hash>(&self, m: &[u8]) -> DSASignature<$base>
where where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset, Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac Hmac<Hash>: Mac
@@ -34,12 +50,10 @@ impl ECCPrivate<P192>
// modular reduction is no more than a conditional subtraction. // modular reduction is no more than a conditional subtraction.
// //
let h1 = <Hash>::digest(m); let h1 = <Hash>::digest(m);
let size = <P192>::size(); let size = <$curve>::size();
println!("h1: {:?}", h1); let h0: $base = bits2int(&h1, size);
let h0: U192 = bits2int(&h1, size); let n = <$curve>::n();
println!("h0: {:X}", h0); let h = h0 % &n;
let h = h0 % <P192>::n();
println!("h: {:X}", h);
// 2. A random value modulo q, dubbed k, is generated. That value // 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 // shall not be 0; hence, it lies in the [1, q-1] range. Most
@@ -47,7 +61,7 @@ impl ECCPrivate<P192>
// process used to generate k. In plain DSA or ECDSA, k should // process used to generate k. In plain DSA or ECDSA, k should
// be selected through a random selection that chooses a value // be selected through a random selection that chooses a value
// among the q-1 possible values with uniform probability. // among the q-1 possible values with uniform probability.
for k in KIterator::<Hash,U192>::new(&h1, size, &<P192>::n(), &self.d) { for k in KIterator::<Hash,$base>::new(&h1, size, &n, &self.d) {
// 3. A value r (modulo q) is computed from k and the key // 3. A value r (modulo q) is computed from k and the key
// parameters: // parameters:
// * For DSA ... // * For DSA ...
@@ -55,12 +69,10 @@ impl ECCPrivate<P192>
// //
// If r turns out to be zero, a new k should be selected and r // If r turns out to be zero, a new k should be selected and r
// computed again (this is an utterly improbable occurrence). // computed again (this is an utterly improbable occurrence).
println!("k: {:X}", k); let g = Point::<$curve>::default();
let g = Point::<P192>::default(); let ki = $sig::new(false, k.clone());
let ki = I192::new(false, k.clone());
let kg = g.scale(&ki); let kg = g.scale(&ki);
let n = P192::n(); let ni = $sig::from(&n);
let ni = I192::from(&n);
let ri = &kg.x % &ni; let ri = &kg.x % &ni;
if ri.is_zero() { if ri.is_zero() {
continue; continue;
@@ -68,78 +80,80 @@ impl ECCPrivate<P192>
if ri.is_negative() { if ri.is_negative() {
continue; continue;
} }
let r = U192::from(ri); let r = $base::from(ri);
// 4. The value s (modulo q) is computed: // 4. The value s (modulo q) is computed:
// //
// s = (h+x*r)/k mod q // s = (h+x*r)/k mod q
// //
// The pair (r, s) is the signature. // The pair (r, s) is the signature.
if let Some(kinv) = k.modinv(&n) { if let Some(kinv) = k.modinv(&n) {
let xr = &self.d * &r; let mut hxr = &self.d * &r;
let hxr = U384::from(&h) + xr; hxr += $dbl::from(&h);
let base = hxr * U448::from(kinv); let base = hxr * $dbl::from(kinv);
let s = U192::from(base % U896::from(n)); let s = $base::from(base % $quad::from(n));
return DSASignature{ r, s }; return DSASignature{ r, s };
} }
} }
panic!("The world is broken; couldn't find a k in sign()."); panic!("The world is broken; couldn't find a k in sign().");
} }
} }
#[cfg(test)]
mod tests {
use sha2::{Sha224,Sha256,Sha384,Sha512};
use super::*;
use testing::*;
#[test]
fn p192_sign() {
let fname = build_test_path("ecc/sign","P192");
run_test(fname.to_string(), 9, |case| {
let (negd, dbytes) = case.get("d").unwrap();
let (negk, kbytes) = case.get("k").unwrap();
let (negx, xbytes) = case.get("x").unwrap();
let (negy, ybytes) = case.get("y").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negh, hbytes) = case.get("h").unwrap();
let (negr, rbytes) = case.get("r").unwrap();
let (negs, sbytes) = case.get("s").unwrap();
assert!(!negd && !negk && !negx && !negy &&
!negm && !negh && !negr && !negs);
let d = U192::from_bytes(dbytes);
let _ = U192::from_bytes(xbytes);
let _ = U192::from_bytes(ybytes);
let h = U192::from_bytes(hbytes);
let r = U192::from_bytes(rbytes);
let s = U192::from_bytes(sbytes);
{
let (negn, nbytes) = case.get("n").unwrap();
println!("nbytes<{}>: {:?}", usize::from(h.clone()), nbytes);
println!("hash<224>: {:?}", Sha224::digest(mbytes));
println!("hash<256>: {:?}", Sha256::digest(mbytes));
println!("hash<384>: {:?}", Sha384::digest(mbytes));
println!("hash<512>: {:?}", Sha512::digest(mbytes));
println!("kbytes: {:?}", kbytes);
let k = U192::from_bytes(kbytes);
println!("k: {:X}", k);
println!("target r: {:X}", r);
println!("target s: {:X}", s);
}
let private = ECCPrivate::new(d);
let sig = match usize::from(h) {
224 => private.sign::<Sha224>(mbytes),
256 => private.sign::<Sha256>(mbytes),
384 => private.sign::<Sha384>(mbytes),
512 => private.sign::<Sha512>(mbytes),
x => panic!("Unknown hash algorithm {}", x)
};
println!("my r: {:X}", sig.r);
println!("my s: {:X}", sig.s);
assert_eq!(r, sig.r, "r signature check");
assert_eq!(s, sig.s, "s signature check");
});
} }
} }
generate_privates!(P192, U192, I192, U384, U768);
generate_privates!(P224, U256, I256, U512, U1024);
generate_privates!(P256, U256, I256, U512, U1024);
generate_privates!(P384, U384, I384, U768, U1536);
generate_privates!(P521, U576, I576, U1152, U2304);
/************* TESTING ********************************************************/
#[cfg(test)]
use sha2::{Sha224,Sha256,Sha384,Sha512};
#[cfg(test)]
use testing::*;
macro_rules! generate_tests {
($name: ident, $curve: ident, $base: ident) => {
#[test]
fn $name() {
let fname = build_test_path("ecc/sign",stringify!($curve));
run_test(fname.to_string(), 9, |case| {
let (negd, dbytes) = case.get("d").unwrap();
let (negk, _bytes) = case.get("k").unwrap();
let (negx, xbytes) = case.get("x").unwrap();
let (negy, ybytes) = case.get("y").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negh, hbytes) = case.get("h").unwrap();
let (negr, rbytes) = case.get("r").unwrap();
let (negs, sbytes) = case.get("s").unwrap();
assert!(!negd && !negk && !negx && !negy &&
!negm && !negh && !negr && !negs);
let d = $base::from_bytes(dbytes);
let _ = $base::from_bytes(xbytes);
let _ = $base::from_bytes(ybytes);
let h = $base::from_bytes(hbytes);
let r = $base::from_bytes(rbytes);
let s = $base::from_bytes(sbytes);
let private = ECCPrivate::<$curve>::new(d);
let sig = match usize::from(h) {
224 => private.sign::<Sha224>(mbytes),
256 => private.sign::<Sha256>(mbytes),
384 => private.sign::<Sha384>(mbytes),
512 => private.sign::<Sha512>(mbytes),
x => panic!("Unknown hash algorithm {}", x)
};
assert_eq!(r, sig.r, "r signature check");
assert_eq!(s, sig.s, "s signature check");
});
}
};
}
generate_tests!(p192_sign, P192, U192);
generate_tests!(p224_sign, P224, U256);
generate_tests!(p256_sign, P256, U256);
generate_tests!(p384_sign, P384, U384);
generate_tests!(p521_sign, P521, U576);