48 Commits

Author SHA1 Message Date
8d8351e833 Preliminary x.509 support. This is some of the ugliest code I've ever written, but it works. Ish. 2019-02-18 10:54:34 -08:00
4559b80d2f Start tracking a bunch of debt I'm accumulating. 2019-02-11 13:20:36 -08:00
293a93c6d4 Support ECDSA key generation. 2019-02-11 13:19:51 -08:00
a3b0ef8d98 Generalize ECC public key support; still very slow. 2019-02-11 12:36:35 -08:00
9ce976bb6e [FIXED] Fairly ridiculous implementation of ECDSA verification 2019-02-11 12:10:59 -08:00
94defc4e77 [BROKEN] Start adding support for ECDSA public keys. 2019-02-10 17:47:36 -08:00
a426ca3901 Make ecdsa/private.rs a bit more pretty. 2019-02-10 17:47:11 -08:00
3716dba87c Add test cases for scaling and adding two points. 2019-02-10 17:46:19 -08:00
a390a7bb53 Start moving from from_bytes to from in the curve constants. 2019-02-04 19:28:17 -08:00
71cb38ca30 Comment out some very slow test cases. Probably need a better way to do this. 2019-02-04 19:27:58 -08:00
322701ad6c ECC Private key support. 2019-02-04 19:27:23 -08:00
8a771c05a4 Tweak some build flags. 2019-02-04 19:27:01 -08:00
a8174ac47e Fix a typo in the P521 base point. 2019-02-04 19:26:35 -08:00
00b944e30a Remove From<U512> requirement on the k-generator. 2019-02-04 19:25:57 -08:00
63bfda9073 Remove extraneous file. 2019-02-04 19:25:28 -08:00
4529562cb8 This appears to work ... maybe. slowly. 2019-01-27 19:02:52 -08:00
4af5446e80 Start work on ECDSA signing. 2019-01-18 21:55:52 -08:00
04b4c79f7a Add size querying for ECDSA curves. 2019-01-18 21:55:42 -08:00
89deea0337 Cleanups for the RFC 6979 code, plus support for running the test cases. 2019-01-18 21:55:08 -08:00
f60a492a0b Updated cabal file and generated test cases. 2019-01-18 21:54:18 -08:00
c5e9d4be25 Add test generation for RFC 6979 k value generation. 2019-01-18 21:53:52 -08:00
f4e47154c2 Add ECDSA scaling and signing tests. 2019-01-18 21:53:15 -08:00
cdcfd9a3a3 Basic point math, with tests. Distressingly slow. 2019-01-08 09:45:02 -08:00
f3494d8524 Handle negative scaling factors. 2018-12-30 21:16:16 -08:00
eb82edea7e Start with Elliptic Curve point math. Slow, but it works. 2018-12-30 21:00:10 -08:00
62cb276888 DSA support! 2018-12-08 10:59:14 -06:00
160618cdd7 Update some libraries, and now RSA works again! 2018-11-21 22:27:59 -08:00
9d87916cc5 Rewrite against a newer cryptonum. 2018-11-14 20:51:14 -05:00
ef54ed4cda Remove the cryptonum stuff; it's been moved to a different crate. 2018-10-27 15:15:23 -07:00
43b73139cd Checkpoint; not sure where this code is, but I'm rethinking. 2018-10-27 15:11:45 -07:00
b30fe6a75f Modular exponentiation with Barrett reduction. Seems slow. :( 2018-06-18 12:04:11 -07:00
011ebc0c99 Extend modular addition to Barrett constants. 2018-06-18 08:42:01 -07:00
a6def22bd1 Barrett reduction! 2018-06-17 11:01:22 -07:00
c49cd29c43 Barrett reduction 2018-06-10 21:09:53 -07:00
65d7b7e93f Modular exponentiation! 2018-06-10 21:09:35 -07:00
b93286fe60 Make modular addition take a trait argument like the others. 2018-06-10 10:36:49 -07:00
5a5b48569b Switch to the same test naming scheme across modules. 2018-06-10 10:36:34 -07:00
b5afa8fdf9 Modular squaring support (slow, initially) 2018-06-09 17:32:46 -07:00
26eb05ceeb Don't use Vecs in modmul, use fixed-size buffers 2018-06-09 17:32:15 -07:00
fee68cca18 Create a modular multiplication trait, and build a slow implementation using mod. 2018-06-09 17:12:01 -07:00
11c951d29b Fix division; we were computing n wrong. 2018-06-09 17:08:13 -07:00
72a5c4568e Division! (With tests) 2018-06-04 21:36:03 -07:00
eae2ea49a9 My multiplication loops were not, in fact, off by one. 2018-06-04 21:35:13 -07:00
69596c83ec Remove a debugging println!() that I missed in a previous commit. 2018-06-04 21:34:09 -07:00
bebb5b2861 Support for fast squaring. 2018-06-02 20:29:44 -07:00
a5f0179d77 Publish a decoder, to make testing a bit easier. 2018-06-02 20:28:53 -07:00
041f824caf Give credit where credit is due. 2018-06-02 20:28:33 -07:00
f088f0f9a5 A second crack at fixed-sized numbers. 2018-06-02 09:26:34 -07:00
154 changed files with 253430 additions and 376993 deletions

24
.gitignore vendored
View File

@@ -11,17 +11,15 @@ Cargo.lock
# And these are just annoying
.DS_Store
# And some Haskell stuff, because I can't shake it!
**/cabal.sandbox.config
**/.cabal-sandbox
# Test generation leavings
**/*.hi
**/*.o
**/gen
**/*.class
**/*.jar
# And I started playing with IDEs, so ...
.vscode
# Ignore testing files
**/*.o
**/*.hi
**/gen
**/.cabal-sandbox
**/cabal.sandbox.config
FlameGraph
*.user_stacks
**/.ghc.environment.*
tests/rsa/dist*

View File

@@ -1,8 +0,0 @@
language: rust
rust:
- stable
- beta
- nightly
script:
- cargo build --verbose
- travis_wait 25 cargo test --verbose

View File

@@ -9,20 +9,26 @@ license-file = "LICENSE"
repository = "https://github.com/acw/simple_crypto"
[dependencies]
base64 = "^0.9.1"
digest = "^0.7.1"
hmac = "^0.5.0"
num = "^0.1.42"
rand = "^0.3"
sha-1 = "^0.7.0"
sha2 = "^0.7.0"
simple_asn1 = "^0.1.0"
byteorder = "^1.2.7"
chrono = "^0.4.6"
cryptonum = { path = "../cryptonum" }
digest = "^0.8.0"
hmac = "^0.7.0"
num = "^0.2.0"
rand = "^0.6.0"
sha-1 = "^0.8.1"
sha2 = "^0.8.0"
simple_asn1 = "^0.2.0"
[dev-dependencies]
quickcheck = "^0.4.1"
quickcheck = "^0.7.2"
[profile.dev]
opt-level = 1
overflow-checks = false
[profile.test]
opt-level = 2
debug = true
debug-assertions = true
overflow-checks = false

10
TECHNICAL_DEBT Normal file
View File

@@ -0,0 +1,10 @@
- Build RSA test cases from Haskell examples
- Build DSA test cases from Haskell examples
- Add negative test cases (RSA, DSA, ECDSA)
- Make Point::double_scalar_mult() not truly awful
- Use std::Default instead of the bespoke default() in Point?
- Run rustfmt on this stuff
- Run clippy on this stuff
- De-macro. Surely some of this stuff could be turned into trait invocations?
- Test cases for key generation
- Better, timing-resistant ECC point math

View File

@@ -1,126 +0,0 @@
macro_rules! derive_arithmetic_operators
{
($type: ident, $cl: ident, $fn: ident, $asncl: ident, $asnfn: ident) => {
impl $asncl for $type {
fn $asnfn(&mut self, other: $type) {
self.$asnfn(&other)
}
}
impl $cl for $type {
type Output = $type;
fn $fn(self, other: $type) -> $type {
let mut res = self.clone();
res.$asnfn(&other);
res
}
}
impl<'a> $cl<&'a $type> for $type {
type Output = $type;
fn $fn(self, other: &$type) -> $type {
let mut res = self.clone();
res.$asnfn(other);
res
}
}
impl<'a> $cl<$type> for &'a $type {
type Output = $type;
fn $fn(self, other: $type) -> $type {
let mut res = self.clone();
res.$asnfn(&other);
res
}
}
impl<'a,'b> $cl<&'a $type> for &'b $type {
type Output = $type;
fn $fn(self, other: &$type) -> $type {
let mut res = self.clone();
res.$asnfn(other);
res
}
}
}
}
macro_rules! derive_shift_operators
{
($type: ident, $asncl: ident, $cl: ident,
$asnfn: ident, $fn: ident,
$base: ident) =>
{
impl $asncl<$base> for $type {
fn $asnfn(&mut self, rhs: $base) {
self.$asnfn(rhs as u64);
}
}
derive_shifts_from_shift_assign!($type, $asncl, $cl,
$asnfn, $fn,
$base);
}
}
macro_rules! derive_shifts_from_shift_assign
{
($type: ident, $asncl: ident, $cl: ident,
$asnfn: ident, $fn: ident,
$base: ident) =>
{
impl $cl<$base> for $type {
type Output = $type;
fn $fn(self, rhs: $base) -> $type {
let mut copy = self.clone();
copy.$asnfn(rhs as u64);
copy
}
}
impl<'a> $cl<$base> for &'a $type {
type Output = $type;
fn $fn(self, rhs: $base) -> $type {
let mut copy = self.clone();
copy.$asnfn(rhs as u64);
copy
}
}
}
}
macro_rules! derive_signed_shift_operators
{
($type: ident, $base: ident, $signed_base: ident) => {
impl ShlAssign<$signed_base> for $type {
fn shl_assign(&mut self, rhs: $signed_base) {
if rhs < 0 {
self.shr_assign(-rhs);
} else {
self.shl_assign(rhs as $base);
}
}
}
impl ShrAssign<$signed_base> for $type {
fn shr_assign(&mut self, rhs: $signed_base) {
if rhs < 0 {
self.shl_assign(-rhs);
} else {
self.shr_assign(rhs as $base);
}
}
}
derive_shifts_from_shift_assign!($type, ShlAssign, Shl,
shl_assign, shl, $signed_base);
derive_shifts_from_shift_assign!($type, ShrAssign, Shr,
shr_assign, shr, $signed_base);
}
}

View File

@@ -1,85 +0,0 @@
macro_rules! define_from
{
($type: ident, $base: ident) => {
impl From<$base> for $type {
fn from(x: $base) -> $type {
if x == 0 {
UCN{ contents: Vec::new() }
} else {
UCN{ contents: vec![x as u64] }
}
}
}
}
}
macro_rules! define_signed_from
{
($type: ident, $base: ident, $uns: ident) => {
impl From<$uns> for $type {
fn from(x: $uns) -> $type {
SCN{ negative: false, value: UCN::from(x) }
}
}
impl From<$base> for $type {
fn from(x: $base) -> $type {
let neg = x < 0;
let absx = x.abs();
SCN{ negative: neg, value: UCN::from(absx as $uns) }
}
}
}
}
macro_rules! define_into
{
($type: ident, $base: ident) => {
impl<'a> From<&'a $type> for $base {
fn from(x: &$type) -> $base {
if x.contents.is_empty() {
0
} else {
x.contents[0] as $base
}
}
}
impl From<$type> for $base {
fn from(x: $type) -> $base {
$base::from(&x)
}
}
}
}
macro_rules! define_signed_into
{
($type: ident, $base: ident, $uns: ident) => {
impl<'a> From<&'a $type> for $uns {
fn from(x: &$type) -> $uns {
let res: $uns = $uns::from(&x.value);
if x.negative { 0-res } else { res }
}
}
impl<'a> From<&'a $type> for $base {
fn from(x: &$type) -> $base {
let res: $uns = $uns::from(&x.value);
if x.negative { (0-res) as $base } else { res as $base }
}
}
impl From<$type> for $uns {
fn from(x: $type) -> $uns {
$uns::from(&x)
}
}
impl From<$type> for $base {
fn from(x: $type) -> $base {
$base::from(&x)
}
}
}
}

View File

@@ -1,187 +0,0 @@
use cryptonum::unsigned::BarrettUCN;
use testing::{make_signed,make_unsigned,run_test};
#[test]
fn unsigned_sum_test()
{
run_test("tests/math/unsigned_add.tests", 3, |scase| {
let case = make_unsigned(scase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
let res = x + y;
assert_eq!(res, *z);
});
}
#[test]
fn signed_sum_test()
{
run_test("tests/math/signed_add.tests", 3, |bcase| {
let case = make_signed(bcase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x + y, *z);
});
}
#[test]
fn unsigned_sub_test()
{
run_test("tests/math/unsigned_sub.tests", 3, |scase| {
let case = make_unsigned(scase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x - y, *z);
});
}
#[test]
fn signed_sub_test()
{
run_test("tests/math/signed_sub.tests", 3, |bcase| {
let case = make_signed(bcase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x - y, *z);
});
}
#[test]
fn unsigned_mul_test()
{
run_test("tests/math/unsigned_mul.tests", 3, |scase| {
let case = make_unsigned(scase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x * y, *z);
});
}
#[test]
fn signed_mul_test()
{
run_test("tests/math/signed_mul.tests", 3, |bcase| {
let case = make_signed(bcase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x * y, *z);
});
}
#[test]
fn unsigned_div_test()
{
run_test("tests/math/unsigned_div.tests", 3, |scase| {
let case = make_unsigned(scase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x / y, *z);
});
}
#[test]
fn signed_div_test()
{
run_test("tests/math/signed_div.tests", 3, |bcase| {
let case = make_signed(bcase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x / y, *z);
});
}
#[test]
fn unsigned_mod_test()
{
run_test("tests/math/unsigned_mod.tests", 3, |scase| {
let case = make_unsigned(scase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x % y, *z);
});
}
#[test]
fn signed_mod_test()
{
run_test("tests/math/signed_mod.tests", 3, |bcase| {
let case = make_signed(bcase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x % y, *z);
});
}
#[test]
#[ignore]
fn modular_exponentiation_test()
{
run_test("tests/math/modexp.tests", 4, |scase| {
let case = make_unsigned(scase);
let a = case.get("a").unwrap();
let b = case.get("b").unwrap();
let m = case.get("m").unwrap();
let z = case.get("z").unwrap();
assert_eq!(a.modexp(&b, &m), *z);
});
}
#[test]
fn fast_modular_exponentiation_test()
{
run_test("tests/math/fastmodexp.tests", 6, |scase| {
let case = make_unsigned(scase);
let a = case.get("a").unwrap();
let b = case.get("b").unwrap();
let kbig = case.get("k").unwrap();
let k = usize::from(kbig);
let m = case.get("m").unwrap();
let u = case.get("u").unwrap();
let z = case.get("z").unwrap();
let mu = BarrettUCN{ k: k, u: u.clone(), m: m.clone() };
assert_eq!(a.fastmodexp(&b, &mu), *z);
});
}
#[test]
fn barrett_reduction_test()
{
run_test("tests/math/barrett.tests", 5, |scase| {
let case = make_unsigned(scase);
let kbig = case.get("k").unwrap();
let m = case.get("m").unwrap();
let r = case.get("r").unwrap();
let u = case.get("u").unwrap();
let v = case.get("v").unwrap();
let k = usize::from(kbig);
let barrett = m.barrett_u();
let result = v.reduce(&barrett);
assert_eq!(barrett.k, k);
assert_eq!(&barrett.u, u);
assert_eq!(&barrett.m, m);
assert_eq!(&result, r);
});
}
#[test]
fn modular_inverse_test()
{
run_test("tests/math/modinv.tests", 3, |scase| {
let case = make_unsigned(scase);
let a = case.get("x").unwrap();
let m = case.get("y").unwrap();
let r = case.get("z").unwrap();
let result = a.modinv(m);
assert_eq!(r, &result);
});
}

View File

@@ -1,13 +0,0 @@
#[macro_use]
mod conversions;
#[macro_use]
mod complete_arith;
mod primes;
mod signed;
mod unsigned;
#[cfg(test)]
mod gold_tests;
pub use self::signed::SCN;
pub use self::unsigned::{BarrettUCN,UCN};
pub use self::primes::*;

View File

@@ -1,139 +0,0 @@
use cryptonum::unsigned::UCN;
use rand::Rng;
static SMALL_PRIMES: [u32; 310] = [
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013,
1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069,
1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223,
1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373,
1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451,
1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511,
1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583,
1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657,
1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811,
1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889,
1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987,
1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053];
impl UCN {
pub fn generate_prime<F,G>(rng: &mut G,
bitlen: usize,
iterations: usize,
check_value: F)
-> UCN
where
G: Rng,
F: Fn(UCN) -> Option<UCN>
{
let one = UCN::from(1 as u8);
assert!((bitlen % 64) == 0);
loop {
let base = random_number(rng, bitlen);
let candidate = base | &one;
if let Some(proposed) = check_value(candidate) {
if proposed.probably_prime(rng, bitlen, iterations) {
return proposed;
}
}
}
}
fn probably_prime<G: Rng>(&self, g: &mut G, size: usize, iters: usize)
-> bool
{
for tester in SMALL_PRIMES.iter() {
if (self % UCN::from(*tester)).is_zero() {
return false;
}
}
miller_rabin(g, &self, size, iters)
}
}
fn miller_rabin<G: Rng>(g: &mut G, n: &UCN, size: usize, iters: usize) -> bool {
let one = UCN::from(1 as u8);
let two = UCN::from(2 as u8);
let nm1 = n - &one;
// Quoth Wikipedia:
// write n - 1 as 2^r*d with d odd by factoring powers of 2 from n - 1
let mut d = nm1.clone();
let mut r = 0;
while d.is_even() {
d >>= 1;
r += 1;
assert!(r < n.bits());
}
// WitnessLoop: repeat k times
'WitnessLoop: for _k in 0..iters {
// pick a random integer a in the range [2, n - 2]
let a = random_in_range(g, size, &two, &nm1);
// x <- a^d mod n
let mut x = a.modexp(&d, &n);
// if x = 1 or x = n - 1 then
if (&x == &one) || (&x == &nm1) {
// continue WitnessLoop
continue 'WitnessLoop;
}
// repeat r - 1 times:
for _i in 0..r {
// x <- x^2 mod n
x = x.modexp(&two, &n);
// if x = 1 then
if &x == &one {
// return composite
return false;
}
// if x = n - 1 then
if &x == &nm1 {
// continue WitnessLoop
continue 'WitnessLoop;
}
}
// return composite
return false;
}
// return probably prime
true
}
fn random_in_range<G: Rng>(rng: &mut G, bitlen: usize, min: &UCN, max: &UCN)
-> UCN
{
loop {
let candidate = random_number(rng, bitlen);
if (&candidate >= min) && (&candidate < max) {
return candidate;
}
}
}
fn random_number<G: Rng>(rng: &mut G, bitlen: usize) -> UCN {
assert!(bitlen % 64 == 0);
let wordlen = bitlen / 64;
let components = rng.gen_iter().take(wordlen).collect();
UCN{ contents: components }
}

View File

@@ -1,406 +0,0 @@
use cryptonum::unsigned::{BarrettUCN,UCN,divmod};
use num::BigInt;
use num::bigint::Sign;
use std::fmt;
use std::cmp::Ordering;
use std::fmt::Write;
use std::ops::*;
/// In case you were wondering, it stands for "Signed Crypto Num".
#[derive(Clone,Debug,PartialEq,Eq)]
pub struct SCN {
pub(crate) negative: bool,
pub(crate) value: UCN
}
impl SCN {
pub fn zero() -> SCN {
SCN{ negative: false, value: UCN::zero() }
}
pub fn is_zero(&self) -> bool {
self.value.is_zero()
}
pub fn is_negative(&self) -> bool {
self.negative
}
pub fn from_str(x: &str) -> SCN {
if x.get(0..1) == Some("-") {
SCN{ negative: true, value: UCN::from_str(&x[1..]) }
} else {
SCN{ negative: false, value: UCN::from_str(x) }
}
}
fn cleanup(&mut self) {
if self.value.is_zero() {
self.negative = false;
}
}
pub fn egcd(self, b: SCN) -> (SCN, SCN, SCN) {
let mut s = SCN::zero();
let mut old_s = SCN::from(1 as u8);
let mut t = SCN::from(1 as u8);
let mut old_t = SCN::zero();
let mut r = b;
let mut old_r = self;
while !r.is_zero() {
let quotient = old_r.clone() / r.clone();
let prov_r = r.clone();
let prov_s = s.clone();
let prov_t = t.clone();
r = old_r - (r * &quotient);
s = old_s - (s * &quotient);
t = old_t - (t * &quotient);
old_r = prov_r;
old_s = prov_s;
old_t = prov_t;
}
(old_r, old_s, old_t)
}
pub fn reduce(&self, m: &BarrettUCN) -> SCN {
println!("signed reduce");
SCN{ negative: false, value: self.value.reduce(m) }
}
pub fn divmod(&self, x: &SCN, m: &BarrettUCN) -> SCN {
println!("STEP1");
let xmod = x.reduce(m);
println!("STEP2");
assert!(!xmod.negative);
println!("STEP3");
let i = xmod.value.modinv(&m.m);
println!("STEP4");
let si = SCN::from(i);
println!("STEP5");
let yi = self * si;
println!("STEP6: {:X}", yi);
println!(" mod {:X}", m.m);
let res = yi.reduce(m);
println!("STEP7");
res
}
}
impl fmt::UpperHex for SCN {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(),fmt::Error> {
if self.negative {
fmt.write_char('-')?;
}
self.value.fmt(fmt)
}
}
//------------------------------------------------------------------------------
//
// Conversions to/from crypto nums.
//
//------------------------------------------------------------------------------
define_signed_from!(SCN, i8, u8);
define_signed_from!(SCN, i16, u16);
define_signed_from!(SCN, i32, u32);
define_signed_from!(SCN, i64, u64);
define_signed_into!(SCN, i8, u8);
define_signed_into!(SCN, i16, u16);
define_signed_into!(SCN, i32, u32);
define_signed_into!(SCN, i64, u64);
impl From<UCN> for SCN {
fn from(x: UCN) -> SCN {
SCN{ negative: false, value: x }
}
}
impl Into<UCN> for SCN {
fn into(self) -> UCN {
self.value
}
}
impl From<SCN> for BigInt {
fn from(x: SCN) -> BigInt {
let sign = if x.is_negative() { Sign::Minus } else { Sign::Plus };
let numbytes = x.value.contents.len() * 8;
let bytes = x.value.to_bytes(numbytes);
BigInt::from_bytes_be(sign, &bytes)
}
}
//------------------------------------------------------------------------------
//
// Comparisons
//
//------------------------------------------------------------------------------
impl PartialOrd for SCN {
fn partial_cmp(&self, other: &SCN) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for SCN {
fn cmp(&self, other: &SCN) -> Ordering {
match (self.negative, other.negative) {
(false, false) => self.value.cmp(&other.value),
(false, true) => Ordering::Greater,
(true, false) => Ordering::Less,
(true, true) => self.value.cmp(&other.value).reverse()
}
}
}
//------------------------------------------------------------------------------
//
// Shifts
//
//------------------------------------------------------------------------------
impl ShlAssign<u64> for SCN {
fn shl_assign(&mut self, rhs: u64) {
self.value <<= rhs;
}
}
impl Shl<u64> for SCN {
type Output = SCN;
fn shl(self, rhs: u64) -> SCN {
let mut copy = self.clone();
copy.shl_assign(rhs);
copy
}
}
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, usize);
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u32);
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u16);
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u8);
impl ShrAssign<u64> for SCN {
fn shr_assign(&mut self, rhs: u64) {
self.value >>= rhs;
}
}
impl Shr<u64> for SCN {
type Output = SCN;
fn shr(self, rhs: u64) -> SCN {
let mut copy = self.clone();
copy.shr_assign(rhs);
copy
}
}
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, usize);
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u32);
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u16);
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u8);
derive_signed_shift_operators!(SCN, usize, isize);
derive_signed_shift_operators!(SCN, u64, i64);
derive_signed_shift_operators!(SCN, u32, i32);
derive_signed_shift_operators!(SCN, u16, i16);
derive_signed_shift_operators!(SCN, u8, i8);
//------------------------------------------------------------------------------
//
// Arithmetic
//
//------------------------------------------------------------------------------
impl Neg for SCN {
type Output = SCN;
fn neg(self) -> SCN {
if self.is_zero() {
self
} else {
SCN{ negative: !self.negative, value: self.value }
}
}
}
impl<'a> Neg for &'a SCN {
type Output = SCN;
fn neg(self) -> SCN {
if self.is_zero() {
self.clone()
} else {
SCN{ negative: !self.negative, value: self.value.clone() }
}
}
}
impl<'a> AddAssign<&'a SCN> for SCN {
fn add_assign(&mut self, rhs: &SCN) {
if self.negative == rhs.negative {
self.value.add_assign(&rhs.value);
} else {
if self.value >= rhs.value {
self.value.sub_assign(&rhs.value);
} else {
self.negative = !self.negative;
self.value = &rhs.value - &self.value;
}
}
self.cleanup();
}
}
impl<'a> SubAssign<&'a SCN> for SCN {
fn sub_assign(&mut self, rhs: &SCN) {
let flipped = SCN{ negative: !rhs.negative, value: rhs.value.clone() };
self.add_assign(&flipped);
self.cleanup();
}
}
impl<'a> MulAssign<&'a SCN> for SCN {
fn mul_assign(&mut self, rhs: &SCN) {
self.negative ^= rhs.negative;
self.value.mul_assign(&rhs.value);
self.cleanup();
}
}
impl<'a> DivAssign<&'a SCN> for SCN {
fn div_assign(&mut self, rhs: &SCN) {
self.negative ^= rhs.negative;
// rounding makes me grumpy
let mut remainder = Vec::new();
let copy = self.value.contents.clone();
divmod(&mut self.value.contents, &mut remainder,
&copy, &rhs.value.contents);
if self.negative && !remainder.is_empty() {
let one = UCN{ contents: vec![1] };
self.sub_assign(SCN{ negative: false, value: one});
}
self.cleanup();
}
}
impl<'a> RemAssign<&'a SCN> for SCN {
fn rem_assign(&mut self, rhs: &SCN) {
let base = &self.value % &rhs.value;
if self.negative == rhs.negative {
self.value = base;
} else {
self.negative = rhs.negative;
self.value = &rhs.value - &base;
}
self.cleanup();
}
}
derive_arithmetic_operators!(SCN, Add, add, AddAssign, add_assign);
derive_arithmetic_operators!(SCN, Sub, sub, SubAssign, sub_assign);
derive_arithmetic_operators!(SCN, Mul, mul, MulAssign, mul_assign);
derive_arithmetic_operators!(SCN, Div, div, DivAssign, div_assign);
derive_arithmetic_operators!(SCN, Rem, rem, RemAssign, rem_assign);
//------------------------------------------------------------------------------
//
// Tests!
//
//------------------------------------------------------------------------------
#[cfg(test)]
mod test {
use quickcheck::{Arbitrary,Gen};
use super::*;
impl Arbitrary for SCN {
fn arbitrary<G: Gen>(g: &mut G) -> SCN {
let neg = (g.next_u32() & 1) == 1;
SCN{ negative: neg, value: UCN::arbitrary(g) }
}
}
fn one() -> SCN {
SCN{ negative: false, value: UCN::from(1 as u8) }
}
quickcheck! {
fn additive_identity(x: SCN) -> bool {
(&x + &SCN::zero()) == x
}
fn subtractive_identity(x: SCN) -> bool {
(&x - &SCN::zero()) == x
}
fn multiplicative_identity(x: SCN) -> bool {
(&x * &one()) == x
}
fn division_identity(x: SCN) -> bool {
let result = &x / &one();
result == x
}
fn additive_destructor(x: SCN) -> bool {
(&x + (- &x)) == SCN::zero()
}
fn subtractive_destructor(x: SCN) -> bool {
(&x - &x) == SCN::zero()
}
fn multiplicative_destructor(x: SCN) -> bool {
(x * SCN::zero()) == SCN::zero()
}
fn division_deastructor(x: SCN) -> bool {
(&x / &x) == one()
}
fn remainder_destructor(x: SCN) -> bool {
(&x % &x) == SCN::zero()
}
fn addition_commutes(a: SCN, b: SCN) -> bool {
(&a + &b) == (&b + &a)
}
fn multiplication_commutes(a: SCN, b: SCN) -> bool {
(&a * &b) == (&b * &a)
}
fn addition_associates(a: SCN, b: SCN, c: SCN) -> bool {
((&a + &b) + &c) == (&a + (&b + &c))
}
fn multiplication_associates(a: SCN, b: SCN, c: SCN) -> bool {
((&a * &b) * &c) == (&a * (&b * &c))
}
fn distribution_works(a: SCN, b: SCN, c: SCN) -> bool {
(&a * (&b + &c)) == ((&a * &b) + (&a * &c))
}
fn negation_works(a: SCN) -> bool {
(- &a) == (&a * &SCN{ negative: true, value: UCN::from(1 as u8) })
}
fn double_negation_works(a: SCN) -> bool {
(- (- &a)) == a
}
fn negation_commutes(a: SCN, b: SCN) -> bool {
((- &a) * &b) == (&a * (- &b))
}
fn negation_cancels(a: SCN, b: SCN) -> bool {
((- &a) * (- &b)) == (&a * &b)
}
fn negation_distributes(a: SCN, b: SCN) -> bool {
(- (&a + &b)) == ((- &a) + (- &b))
}
}
quickcheck! {
fn egcd_works(a: SCN, b: SCN) -> bool {
let (d, x, y) = a.clone().egcd(b.clone());
((a * x) + (b * y)) == d
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,16 @@
use simple_asn1::ASN1DecodeErr;
use std::io;
use rand;
#[derive(Debug)]
pub enum DSAError {
ASN1DecodeErr(ASN1DecodeErr),
InvalidParamSize
RandomGenError(rand::Error),
ASN1DecodeErr(ASN1DecodeErr)
}
impl From<rand::Error> for DSAError {
fn from(e: rand::Error) -> DSAError {
DSAError::RandomGenError(e)
}
}
impl From<ASN1DecodeErr> for DSAError {
@@ -12,17 +18,3 @@ impl From<ASN1DecodeErr> for 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)
}
}

View File

@@ -1,585 +0,0 @@
use cryptonum::{BarrettUCN,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, pu: &BarrettUCN,
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.fastmodexp(&e, &pu);
// 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
}

View File

@@ -1,77 +1,69 @@
mod errors;
mod generation;
#[cfg(test)]
mod gold_tests;
mod parameters;
mod public;
mod params;
mod private;
pub(crate) mod rfc6979;
mod public;
pub mod rfc6979;
#[cfg(test)]
mod tests;
pub use self::public::DSAPublic;
pub use self::private::DSAPrivate;
pub use self::rfc6979::DSASignature;
pub use self::params::*;
pub use self::private::*;
pub use self::public::*;
use cryptonum::UCN;
use rand::{OsRng,Rng};
use self::errors::*;
use self::parameters::*;
use cryptonum::unsigned::*;
use rand::Rng;
use rand::distributions::Standard;
/// A DSA key pair
#[derive(Clone,Debug,PartialEq)]
pub struct DSAKeyPair {
pub private: DSAPrivate,
pub public: DSAPublic
pub struct DSAKeyPair<P,L,N>
{
pub private: DSAPrivKey<P,N>,
pub public: DSAPubKey<P,L>
}
impl DSAKeyPair {
pub fn generate(size: DSAParameterSize)
-> Result<DSAKeyPair,DSAGenError>
{
let mut rng = OsRng::new()?;
DSAKeyPair::generate_rng(&mut rng, size)
}
pub trait DSAKeyGeneration
{
type Params;
pub fn generate_rng<G: Rng>(rng: &mut G, size: DSAParameterSize)
-> Result<DSAKeyPair,DSAGenError>
{
let params = DSAParameters::generate_w_rng(rng, size)?;
DSAKeyPair::generate_w_params_rng(rng, &params)
}
pub fn generate_w_params(params: &DSAParameters)
-> Result<DSAKeyPair,DSAGenError>
{
let mut rng = OsRng::new()?;
DSAKeyPair::generate_w_params_rng(&mut rng, params)
}
pub fn generate_w_params_rng<G: Rng>(rng: &mut G, params: &DSAParameters)
-> Result<DSAKeyPair,DSAGenError>
{
// 1. N = len(q); L = len(p);
let n = n_bits(params.size);
// 2. If the (L,N) pair is invalid, then return an ERROR indicator,
// Invalid_x, and Invalid_y.
// 3. requested_security_strength = the security strength associated
// with the (L, N) pair; see SP 800-57.
// 4. Obtain a string of N+64 returned_bits from an RBG with a security
// strength of requested_security_strength or more. If an ERROR
// indication is returned, then return an ERROR indication,
// Invalid_x, and Invalid_y.
let returned_bits: Vec<u8> = rng.gen_iter().take(n + 8).collect();
// 5. Convert returned_bits to the (non-negative) integer c.
let c = UCN::from_bytes(&returned_bits);
// 6. x = (c mod (q-1)) + 1.
let one = UCN::from(1 as u64);
let x = (&c % (&params.q - &one)) + &one;
// 7. y = g^x mod p
let y = params.g.fastmodexp(&x, &params.pu);
// 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
})
}
fn generate<G: Rng>(params: &Self::Params, rng: &mut G) -> Self;
}
macro_rules! generate_dsa_pair {
($ptype: ident, $ltype: ident, $ntype: ident, $nbig: ident) => {
impl DSAKeyGeneration for DSAKeyPair<$ptype,$ltype,$ntype>
{
type Params = $ptype;
fn generate<G: Rng>(params: &$ptype, rng: &mut G) -> Self
{
// 1. N = len(q); L = len(p);
let n = $ptype::n_size();
// 2. If the (L,N) pair is invalid, then return an ERROR indicator,
// Invalid_x, and Invalid_y.
// 3. requested_security_strength = the security strength associated
// with the (L, N) pair; see SP 800-57.
// 4. Obtain a string of N+64 returned_bits from an RBG with a security
// strength of requested_security_strength or more. If an ERROR
// indication is returned, then return an ERROR indication,
// Invalid_x, and Invalid_y.
let returned_bits: Vec<u8> = rng.sample_iter(&Standard).take(n + 8).collect();
// 5. Convert returned_bits to the (non-negative) integer c.
let c = $nbig::from_bytes(&returned_bits);
// 6. x = (c mod (q-1)) + 1.
let one = $nbig::from(1 as u64);
let qbig = $nbig::from(&params.q);
let x = $ntype::from( (&c % (&qbig - &one)) + &one );
// 7. y = g^x mod p
let y = params.g.modexp(&$ltype::from(&x), &params.p);
// 8. Return SUCCESS, x, and y.
let private = DSAPrivKey::new(params.clone(), x);
let public = DSAPubKey::new(params.clone(), y);
DSAKeyPair { private, public }
}
}
};
}
generate_dsa_pair!(L1024N160, U1024, U192, U256);
generate_dsa_pair!(L2048N224, U2048, U256, U384);
generate_dsa_pair!(L2048N256, U2048, U256, U384);
generate_dsa_pair!(L3072N256, U3072, U256, U384);

View File

@@ -1,119 +0,0 @@
use cryptonum::{BarrettUCN,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,
pub pu: BarrettUCN,
pub qu: BarrettUCN
}
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)
};
let pu = p.barrett_u();
let qu = q.barrett_u();
Ok(DSAParameters{ size: size, p: p, g: g, q: q, pu: pu, qu: qu })
}
/// 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 pu = p.barrett_u();
let qu = q.barrett_u();
let g = generate_verifiable_generator(&p, &pu, &q, &ev, idx)?;
Ok(DSAParameters{ size: ps, p: p, q: q, g: g, pu: pu, qu: qu })
}
/// 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)
}
}

212
src/dsa/params.rs Normal file
View File

@@ -0,0 +1,212 @@
use cryptonum::unsigned::{CryptoNum,Decoder,Encoder,ModExp,PrimeGen};
use cryptonum::unsigned::{U192,U256,U1024,U2048,U3072};
use digest::Digest;
use sha2::Sha256;
use simple_asn1::{ToASN1,ASN1Block,ASN1Class,ASN1EncodeErr};
use rand::Rng;
use utils::TranslateNums;
pub trait DSAParameters : ToASN1
{
type L;
type N;
fn new(p: Self::L, g: Self::L, q: Self::N) -> Self;
fn generate<G: Rng>(rng: &mut G) -> Self;
fn n_size() -> usize;
fn l_size() -> usize;
fn n_bits(&self) -> usize {
Self::n_size()
}
}
macro_rules! generate_parameters {
($name: ident, $ltype: ident, $ntype: ident, $l: expr, $n: expr) => {
#[derive(Clone)]
pub struct $name {
pub p: $ltype,
pub g: $ltype,
pub q: $ntype
}
impl ToASN1 for $name {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let p = ASN1Block::Integer(c, 0, self.p.to_num());
let q = ASN1Block::Integer(c, 0, self.q.to_num());
let g = ASN1Block::Integer(c, 0, self.g.to_num());
Ok(vec![ASN1Block::Sequence(c, 0, vec![p, q, g])])
}
}
impl DSAParameters for $name
{
type L = $ltype;
type N = $ntype;
fn new(p: $ltype, g: $ltype, q: $ntype) -> $name
{
$name{ p: p, g: g, q: q }
}
fn generate<G: Rng>(rng: &mut G) -> $name
{
let (p, q, _, _) = $name::generate_primes(rng);
let g = $name::generate_g(rng, &p, &q);
$name{ p: p, g: g, q: q }
}
fn l_size() -> usize {
$l
}
fn n_size() -> usize {
$n
}
}
impl $name
{
fn generate_primes<G: Rng>(rng: &mut G) -> ($ltype,$ntype,U256,usize)
{
// This is A.1.1.2 from FIPS 186-4, with seedlen hardcoded to 256
// (since that's guaranteed to be >= N), and with the hash
// hardcoded as SHA-256.
#[allow(non_snake_case)]
let L = $ltype::bit_length();
#[allow(non_snake_case)]
let N = $ntype::bit_length();
let seedlen = 256;
let outlen = 256;
//
// 1. Check that the (L,N) pair is in the list of acceptable
// (L,N) pairs (see Section 4.2). If the pair is not in the
// list, then return INVALID.
// [This is always true.]
//
// 2. If (seedlen < N), then return INVALID.
// [This is always true.]
//
// 3. n = L/outlen 1.
let n = ((L + 255) / 256) - 1;
// 4. b = L 1 (n outlen).
let b = L - 1 - (n * outlen);
loop {
// 5. Get an arbitrary sequence of seedlen bits as the
// domain_parameter_seed.
let domain_parameter_seed: U256 = rng.gen();
// 6. U = Hash (domain_parameter_seed) mod 2^(N1).
let mut ubytes = hash(&domain_parameter_seed, 32);
while ubytes.len() > (N / 8) { ubytes.remove(0); }
#[allow(non_snake_case)]
let U = $ntype::from_bytes(&ubytes);
// 7. q = 2^(N1) + U + 1 (U mod 2).
let ulow = if U.is_even() { 0 } else { 1 };
let mut q = $ntype::from(1u64) << (N - 1);
q += U;
q += $ntype::from(1u64 + ulow);
// 8. Test whether or not q is prime as specified in Appendix C.3.
let q_is_prime = q.probably_prime(rng, 40);
// 9. If q is not a prime, then go to step 5.
if !q_is_prime {
continue;
}
// 10. offset = 1.
let mut offset = 1;
// 11. For counter = 0 to (4L 1) do
for counter in 0..(4*L)-1 {
// 11.1 For j = 0 to n do
// Vj = Hash ((domain_parameter_seed + offset + j) mod 2^seedlen).
#[allow(non_snake_case)]
let mut V = Vec::new();
for j in 0..n {
let val = &domain_parameter_seed + U256::from(offset + j);
let bytes = hash(&val, 32);
assert_eq!(seedlen, bytes.len());
V.push(bytes);
}
// 11.2 W = V_0 + ( V_1 2^outlen) + ... + ( V_(n1) 2^(n 1) outlen) + ((V_n mod 2^b) 2^(n outlen).
#[allow(non_snake_case)]
let mut W = $ltype::zero();
for (idx, val) in V.iter().enumerate() {
if idx < n {
let mut base = val.clone();
let baselen = base.len();
base.resize(baselen + (idx * (outlen / 8)), 0);
W += $ltype::from_bytes(&base);
} else {
let base = $ltype::from_bytes(val);
let twob = $ltype::from(1u64) << b;
let val = base % twob;
W += val << (n * outlen);
}
}
// 11.3 X = W + 2^(L 1).
// Comment: 0 ≤ W < 2 L 1 ; hence, 2 L 1 ≤ X < 2 L .
#[allow(non_snake_case)]
let mut X = $ltype::from(1u64) << (L - 1);
X += W;
// 11.4 c = X mod 2q.
let c = &X % ($ltype::from(&q) << 1);
// 11.5 p = X ( c 1).
// Comment: p ≡ 1 ( mod 2 q) .
let p = &X - (c - $ltype::from(1u64));
// 11.6 If ( p < 2L 1), then go to step 11.9.
if p >= $ltype::from((2*L) - 1) {
// 11.7 Test whether or not p is prime as specified in Appendix C .3.
if p.probably_prime(rng, 40) {
// 11.8 If p is determined to be prime, then return VALID and the values of p , q and (optionally) the values of domain_parameter_seed and counter .
return (p, q, domain_parameter_seed, counter);
}
}
// 11.9 offset = offset + n + 1.
offset = offset + n + 1;
}
}
}
fn generate_g<G: Rng>(rng: &mut G, p: &$ltype, q: &$ntype) -> $ltype
{
let bigq = $ltype::from(q);
let p_minus_1 = p - $ltype::from(1u64);
// This is A.2.1 (Unverifiable Generation of g) from FIPS 186-4.
// 1. e = (p 1) / q.
let e = (p - $ltype::from(1u64)) / bigq;
loop {
// 2. Set h = any integer satisfying 1 < h < ( p 1), such that
// h differs from any value previously tried. Note that h could
// be obtained from a random number generator or from a counter
// that changes after each use.
let h = rng.gen_range($ltype::from(2u64), &p_minus_1);
// 3. g = h^e mod p.
let g = h.modexp(&e, p);
// 4. If ( g = 1), then go to step 2.
if g != $ltype::from(1u64) {
// 5. Return g
return g;
}
}
}
}
};
}
generate_parameters!(L1024N160, U1024, U192, 1024, 160);
generate_parameters!(L2048N224, U2048, U256, 2048, 224);
generate_parameters!(L2048N256, U2048, U256, 2048, 256);
generate_parameters!(L3072N256, U3072, U256, 3072, 256);
fn hash<T>(x: &T, len: usize) -> Vec<u8>
where T: Encoder
{
let mut base = x.to_bytes();
let bytelen = len / 8;
while base.len() < bytelen {
base.insert(0,0);
}
Sha256::digest(&base).as_slice().to_vec()
}

View File

@@ -1,89 +1,119 @@
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;
use cryptonum::unsigned::*;
use cryptonum::signed::ModInv;
use digest::{BlockInput,Digest,Input,FixedOutput,Reset};
use dsa::params::*;
use dsa::rfc6979::*;
use hmac::{Hmac,Mac};
/// A DSA private key.
#[derive(Clone,Debug,PartialEq)]
pub struct DSAPrivate {
pub params: DSAParameters,
pub(crate) x: UCN
pub trait DSAPrivateKey {
type Params;
type L;
type N;
/// Generate a new private key using the given DSA parameters and private
/// key value.
fn new(params: Self::Params, x: Self::N) -> Self;
/// Generate a DSA signature for the given message, using the appropriate
/// hash included in the type invocation.
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<Self::N>
where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac;
}
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.reduce(&self.params.qu);
// 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.fastmodexp(&k, &self.params.pu)
.rem(&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).rem(&self.params.q);
return DSASignature{ r: r, s: s };
}
panic!("The world is broken; couldn't find a k in sign().");
}
pub struct DSAPrivKey<Params,N>
{
pub(crate) params: Params,
pub(crate) x: N
}
pub enum DSAPrivate {
DSA1024Private(DSAPrivKey<L1024N160,U192>),
DSA2048SmallPrivate(DSAPrivKey<L2048N224,U256>),
DSA2048Private(DSAPrivKey<L2048N256,U256>),
DSA3072Private(DSAPrivKey<L3072N256,U256>)
}
macro_rules! privkey_impls {
($ptype: ident, $ltype: ident, $ntype: ident, $big: ident, $bigger: ident, $biggest: ident) => {
impl DSAPrivateKey for DSAPrivKey<$ptype,$ntype>
{
type Params = $ptype;
type L = $ltype;
type N = $ntype;
fn new(params: $ptype, x: $ntype) -> DSAPrivKey<$ptype,$ntype>
{
DSAPrivKey{ params, x }
}
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<$ntype>
where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac
{
// This algorithm is per RFC 6979, which has a nice, relatively
// straightforward description of how to do DSA signing.
//
// 1. H(m) is transformed into an integer modulo q using the bits2int
// transform and an extra modular reduction:
//
// h = bits2int(H(m)) mod q
//
// As was noted in the description of bits2octets, the extra
// modular reduction is no more than a conditional subtraction.
//
let h1 = <Hash>::digest(m);
let n = $ptype::n_size();
let h0: $ntype = bits2int(&h1, $ptype::n_size());
let q = &self.params.q;
let h = h0 % q;
// 2. A random value modulo q, dubbed k, is generated. That value
// shall not be 0; hence, it lies in the [1, q-1] range. Most
// of the remainder of this document will revolve around the
// process used to generate k. In plain DSA or ECDSA, k should
// be selected through a random selection that chooses a value
// among the q-1 possible values with uniform probability.
for k in KIterator::<Hash,$ntype>::new(&h1, n, q, &self.x) {
// 3. A value r (modulo q) is computed from k and the key
// parameters:
// * For DSA:
// r = g^k mod p mod q
//
// (The exponentiation is performed modulo p, yielding a
// number between 0 and p-1, which is then further reduced
// modulo q.)
// * For ECDSA ...
//
// If r turns out to be zero, a new k should be selected and r
// computed again (this is an utterly improbable occurrence).
let bigk = $ltype::from(&k);
let bigr = self.params.g.modexp(&bigk, &self.params.p) % $ltype::from(q);
if bigr.is_zero() {
continue;
}
let r = $ntype::from(bigr);
// 4. The value s (modulo q) is computed:
//
// s = (h+x*r)/k mod q
//
// The pair (r, s) is the signature.
if let Some(kinv) = k.modinv(&q) {
let xr = &self.x * &r;
let top = xr + $big::from(&h);
let left = top * $bigger::from(kinv);
let bigs = left % $biggest::from(q);
return DSASignature::new(r, $ntype::from(bigs));
}
}
panic!("The world is broken; couldn't find a k in sign().");
}
}
};
}
privkey_impls!(L1024N160, U1024, U192, U384, U448, U896);
privkey_impls!(L2048N224, U2048, U256, U512, U576, U1152);
privkey_impls!(L2048N256, U2048, U256, U512, U576, U1152);
privkey_impls!(L3072N256, U3072, U256, U512, U576, U1152);

View File

@@ -1,72 +1,100 @@
use cryptonum::{SCN,UCN};
use digest::{FixedOutput,Input};
use dsa::parameters::{DSAParameters,n_bits};
use cryptonum::unsigned::*;
use cryptonum::signed::ModInv;
use digest::Digest;
use dsa::params::*;
use dsa::rfc6979::DSASignature;
use num::BigInt;
use simple_asn1::{ASN1Block,ToASN1,ASN1EncodeErr,ASN1Class};
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,ToASN1};
use std::cmp::min;
use std::ops::Rem;
use utils::TranslateNums;
/// A DSA key pair
#[derive(Clone,Debug,PartialEq)]
pub struct DSAPublic {
pub params: DSAParameters,
pub y: UCN
pub trait DSAPublicKey {
type Params : DSAParameters;
type L;
type N;
/// Generate a new public key given the parameters and public value.
fn new(params: Self::Params, y: Self::L) -> Self;
/// Verify the given signature against the given message, using the
/// appropriate hash function.
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<Self::N>) -> bool
where Hash: Digest;
}
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).reduce(&self.params.qu);
// u2 = (rw) mod q
let u2 = (&sig.r * &w).reduce(&self.params.qu);
// v = (((g)^u1(y)^u2) mod p) mod q
let v_1 = self.params.g.fastmodexp(&u1, &self.params.pu);
let v_2 = self.y.fastmodexp(&u2, &self.params.pu);
let v = (&v_1 * &v_2).reduce(&self.params.pu)
.rem(&self.params.q);
// if v = r, then the signature is verified
v == sig.r
}
pub struct DSAPubKey<Params,L> {
pub(crate) params: Params,
pub(crate) y: L
}
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])
}
pub enum DSAPublic {
DSAPublicL1024N160(DSAPubKey<L1024N160,U1024>),
DSAPublicL2048N224(DSAPubKey<L2048N224,U2048>),
DSAPublicL2048N256(DSAPubKey<L2048N256,U2048>),
DSAPublicL3072N256(DSAPubKey<L3072N256,U3072>)
}
macro_rules! pubkey_impls {
($ptype: ident, $ltype: ident, $ntype: ident, $dbl: ident, $bdbl: ident) => {
impl DSAPublicKey for DSAPubKey<$ptype,$ltype>
{
type Params = $ptype;
type L = $ltype;
type N = $ntype;
fn new(params: $ptype, y: $ltype) -> DSAPubKey<$ptype,$ltype>
{
DSAPubKey{ params, y }
}
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<$ntype>) -> bool
where Hash: Digest
{
if sig.r >= self.params.q {
return false;
}
if sig.s >= self.params.q {
return false;
}
// w = (s')^-1 mod q;
if let Some(w) = sig.s.modinv(&self.params.q) {
// z = the leftmost min(N, outlen) bits of Hash(M').
let mut digest_bytes = <Hash>::digest(m).to_vec();
let len = min(digest_bytes.len(), $ptype::n_size() / 8);
digest_bytes.truncate(len);
let z = $ntype::from_bytes(&digest_bytes);
// u1 = (zw) mod q
let qdbl = $dbl::from(&self.params.q);
let u1 = $ltype::from( (&z * &w) % &qdbl );
// u2 = (rw) mod q
let u2 = $ltype::from( (&sig.r * &w) % &qdbl );
// v = (((g)^u1(y)^u2) mod p) mod q
let v_1 = self.params.g.modexp(&u1, &self.params.p);
let v_2 = self.y.modexp(&u2, &self.params.p);
let bigp = $bdbl::from(&self.params.p);
let v_first_mod = (v_1 * v_2) % bigp;
let v = $ltype::from(v_first_mod) % $ltype::from(&self.params.q);
// if v = r, then the signature is verified
return $ntype::from(v) == sig.r
}
false
}
}
impl ToASN1 for DSAPubKey<$ptype,$ltype> {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let inty = self.y.to_num();
let yblock = ASN1Block::Integer(c, 0, inty);
Ok(vec![yblock])
}
}
};
}
pubkey_impls!(L1024N160, U1024, U192, U384, U2048);
pubkey_impls!(L2048N224, U2048, U256, U512, U4096);
pubkey_impls!(L2048N256, U2048, U256, U512, U4096);
pubkey_impls!(L3072N256, U3072, U256, U512, U6144);

View File

@@ -1,31 +1,48 @@
use cryptonum::UCN;
use digest::{BlockInput,FixedOutput,Input};
use cryptonum::unsigned::{CryptoNum,Decoder,Encoder};
use digest::{BlockInput,Digest,FixedOutput,Input,Reset};
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;
use num::BigInt;
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr};
use simple_asn1::{FromASN1,ToASN1};
use utils::TranslateNums;
use std::ops::{Shr,Sub};
#[derive(Debug,PartialEq)]
pub struct DSASignature<N>
{
pub r: N,
pub s: N
}
impl<N> DSASignature<N>
{
pub fn new(r: N, s: N) -> DSASignature<N>
{
DSASignature{ r, s }
}
}
#[allow(non_snake_case)]
pub struct KIterator<H>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
H::BlockSize : ArrayLength<u8>
pub struct KIterator<H,N>
where
H: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
N: Clone + Decoder + Encoder + PartialOrd + Shr<usize,Output=N>,
Hmac<H>: Mac
{
hmac_k: Hmac<H>,
V: Vec<u8>,
q: UCN,
q: N,
qlen: usize
}
impl<H> KIterator<H>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H::BlockSize : ArrayLength<u8>
impl<H,N> KIterator<H,N>
where
H: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
N: Clone + Decoder + Encoder + PartialOrd + Shr<usize,Output=N> + Sub<Output=N>,
Hmac<H>: Mac
{
pub fn new(h1: &[u8], qlen: usize, q: &UCN, x: &UCN) -> KIterator<H>
pub fn new(h1: &[u8], qlen: usize, q: &N, x: &N) -> KIterator<H,N>
{
// Given the input message m, the following process is applied:
//
@@ -100,7 +117,7 @@ impl<H> KIterator<H>
V = hmac(&K, &V);
// h is for later ...
KIterator {
hmac_k: Hmac::<H>::new(&K).unwrap(),
hmac_k: Hmac::<H>::new_varkey(&K).unwrap(),
V: V,
q: q.clone(),
qlen: qlen
@@ -108,15 +125,16 @@ impl<H> KIterator<H>
}
}
impl<H> Iterator for KIterator<H>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H::BlockSize : ArrayLength<u8>
impl<H,N> Iterator for KIterator<H,N>
where
H: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
N: Clone + CryptoNum + Decoder + Encoder + PartialOrd + Shr<usize,Output=N>,
Hmac<H>: Mac
{
type Item = UCN;
type Item = N;
fn next(&mut self) -> Option<UCN> {
fn next(&mut self) -> Option<N>
{
loop {
// h. Apply the following algorithm until a proper value is found
// for k:
@@ -138,7 +156,7 @@ impl<H> Iterator for KIterator<H>
// 3. Compute:
//
// k = bits2int(T)
let resk = bits2int(&t, self.qlen);
let resk: N = bits2int(&t, self.qlen);
//
// If that value of k is within the [1,q-1] range, and is
// suitable for DSA or ECDSA (i.e., it results in an r value
@@ -152,44 +170,64 @@ impl<H> Iterator for KIterator<H>
#[allow(non_snake_case)]
let K = runhmac(&self.hmac_k, &input);
// V = HMAC_K(V)
self.hmac_k = Hmac::<H>::new(&K).unwrap();
self.hmac_k = Hmac::<H>::new_varkey(&K).unwrap();
self.V = runhmac(&self.hmac_k, &self.V);
//
// and loop (try to generate a new T, and so on).
//
if !resk.is_zero() && (&resk < &self.q) {
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;
pub fn bits2int<X>(x: &[u8], qlen: usize) -> X
where
X: Decoder + Shr<usize,Output=X>
{
if vlen > qlen {
value >>= vlen - qlen;
if qlen < (x.len() * 8) {
let mut fixed_x = Vec::from(x);
let qlen_bytes = (qlen + 7) / 8;
let rounded_qlen = qlen_bytes * 8;
fixed_x.resize(qlen_bytes, 0);
X::from_bytes(&fixed_x) >> (rounded_qlen - qlen)
} else {
X::from_bytes(x)
}
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 };
fn bits2octets<X>(x: &[u8], q: &X, qlen: usize) -> Vec<u8>
where
X: Clone + Decoder + Encoder + PartialOrd + Sub<Output=X> + Shr<usize,Output=X>
{
let z1: X = bits2int(x, qlen);
let res = if &z1 > q { z1 - q.clone() } else { z1 };
int2octets(&res, qlen)
}
fn int2octets(x: &UCN, qlen_bits: usize) -> Vec<u8> {
fn int2octets<X>(x: &X, qlen_bits: usize) -> Vec<u8>
where X: Encoder
{
let qlen_bytes = (qlen_bits + 7) / 8;
x.to_bytes(qlen_bytes)
let mut base = x.to_bytes();
while base.len() < qlen_bytes {
base.insert(0,0);
}
while base.len() > qlen_bytes {
base.remove(0);
}
base
}
fn runhmac<H>(base: &Hmac<H>, m: &[u8]) -> Vec<u8>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H: Clone + BlockInput + Default + Input + FixedOutput + Reset,
Hmac<H>: Clone + Mac,
H::BlockSize : ArrayLength<u8>
{
let mut runner = base.clone();
@@ -199,27 +237,21 @@ fn runhmac<H>(base: &Hmac<H>, m: &[u8]) -> Vec<u8>
fn hmac<H>(k: &[u8], m: &[u8]) -> Vec<u8>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H: BlockInput + Clone + Default + Input + FixedOutput + Reset,
Hmac<H>: Clone + Mac,
H::BlockSize : ArrayLength<u8>
{
let mut runner = Hmac::<H>::new(&k).unwrap();
let mut runner = Hmac::<H>::new_varkey(&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
InvalidRValue,
InvalidSValue
}
impl From<ASN1DecodeErr> for DSADecodeError {
@@ -228,11 +260,13 @@ impl From<ASN1DecodeErr> for DSADecodeError {
}
}
impl FromASN1 for DSASignature {
impl<N> FromASN1 for DSASignature<N>
where N: TranslateNums<BigInt>
{
type Error = DSADecodeError;
fn from_asn1(v: &[ASN1Block])
-> Result<(DSASignature,&[ASN1Block]),DSADecodeError>
-> Result<(DSASignature<N>,&[ASN1Block]),DSADecodeError>
{
match v.split_first() {
Some((&ASN1Block::Sequence(_,_,ref info), rest))
@@ -241,12 +275,9 @@ impl FromASN1 for DSASignature {
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))
let r = N::from_num(rint).ok_or(DSADecodeError::InvalidRValue)?;
let s = N::from_num(sint).ok_or(DSADecodeError::InvalidSValue)?;
Ok((DSASignature{ r, s }, rest))
}
_ => Err(DSADecodeError::NoSignatureFound)
}
@@ -256,22 +287,26 @@ impl FromASN1 for DSASignature {
}
}
impl ToASN1 for DSASignature {
impl<N> ToASN1 for DSASignature<N>
where N: TranslateNums<BigInt>
{
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()));
let rb = ASN1Block::Integer(c, 0, self.r.to_num());
let sb = ASN1Block::Integer(c, 0, self.s.to_num());
Ok(vec![ASN1Block::Sequence(c, 0, vec![rb,sb])])
}
}
#[cfg(test)]
mod tests {
use sha2::Sha256;
use cryptonum::unsigned::U192;
use sha2::{Sha224,Sha256,Sha384,Sha512};
use super::*;
use testing::*;
const QBYTES: [u8; 21] = [0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x01, 0x08, 0xA2, 0xE0, 0xCC,
@@ -286,7 +321,7 @@ mod tests {
#[test]
fn int2octets_example() {
let x = UCN::from_bytes(&XBYTES);
let x = U192::from_bytes(&XBYTES);
let octets = int2octets(&x, 163);
let target = vec![0x00, 0x9A, 0x4D, 0x67, 0x92, 0x29, 0x5A, 0x7F,
0x73, 0x0F, 0xC3, 0xF2, 0xB4, 0x9C, 0xBC, 0x0F,
@@ -296,7 +331,7 @@ mod tests {
#[test]
fn bits2octets_example() {
let q = UCN::from_bytes(&QBYTES);
let q = U192::from_bytes(&QBYTES);
let octets = bits2octets(&H1, &q, 163);
let target = vec![0x01, 0x79, 0x5E, 0xDF, 0x0D, 0x54, 0xDB, 0x76,
0x0F, 0x15, 0x6D, 0x0D, 0xAC, 0x04, 0xC0, 0x32,
@@ -306,9 +341,9 @@ mod tests {
#[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);
let q = U192::from_bytes(&QBYTES);
let x = U192::from_bytes(&XBYTES);
let mut iter = KIterator::<Sha256,U192>::new(&H1, 163, &q, &x);
match iter.next() {
None =>
assert!(false),
@@ -316,9 +351,86 @@ mod tests {
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);
let x2 = U192::from_bytes(&target);
assert_eq!(x, x2);
}
}
}
use cryptonum::unsigned::*;
macro_rules! k_generator_tests {
($testname: ident, $hash: ident, $fname: expr) => {
#[test]
fn $testname() {
let fname = build_test_path("rfc6979", $fname);
run_test(fname.to_string(), 7, |case| {
let (negq, qbytes) = case.get("q").unwrap();
let (negl, lbytes) = case.get("l").unwrap();
let (negx, xbytes) = case.get("x").unwrap();
let (negh, h1) = case.get("h").unwrap();
let (negk, kbytes) = case.get("k").unwrap();
let (negy, ybytes) = case.get("y").unwrap();
let (negz, zbytes) = case.get("z").unwrap();
assert!(!negq && !negl && !negx && !negh &&
!negk && !negy && !negz);
let qlen = usize::from(U192::from_bytes(lbytes));
assert!(qlen >= 160); assert!(qlen <= 521);
if qlen < 192 {
let q = U192::from_bytes(qbytes);
let x = U192::from_bytes(xbytes);
let k = U192::from_bytes(kbytes);
let y = U192::from_bytes(ybytes);
let z = U192::from_bytes(zbytes);
let mut kiter = KIterator::<$hash,U192>::new(h1,qlen,&q,&x);
assert_eq!(Some(k), kiter.next(), "first value test");
assert_eq!(Some(y), kiter.next(), "second value test");
assert_eq!(Some(z), kiter.next(), "third value test");
} else if qlen < 256 {
let q = U256::from_bytes(qbytes);
let x = U256::from_bytes(xbytes);
let k = U256::from_bytes(kbytes);
let y = U256::from_bytes(ybytes);
let z = U256::from_bytes(zbytes);
let mut kiter = KIterator::<$hash,U256>::new(h1,qlen,&q,&x);
assert_eq!(Some(k), kiter.next(), "first value test");
assert_eq!(Some(y), kiter.next(), "second value test");
assert_eq!(Some(z), kiter.next(), "third value test");
} else if qlen < 512 {
let q = U512::from_bytes(qbytes);
let x = U512::from_bytes(xbytes);
let k = U512::from_bytes(kbytes);
let y = U512::from_bytes(ybytes);
let z = U512::from_bytes(zbytes);
let mut kiter = KIterator::<$hash,U512>::new(h1,qlen,&q,&x);
assert_eq!(Some(k), kiter.next(), "first value test");
assert_eq!(Some(y), kiter.next(), "second value test");
assert_eq!(Some(z), kiter.next(), "third value test");
} else {
let q = U576::from_bytes(qbytes);
let x = U576::from_bytes(xbytes);
let k = U576::from_bytes(kbytes);
let y = U576::from_bytes(ybytes);
let z = U576::from_bytes(zbytes);
let mut kiter = KIterator::<$hash,U576>::new(h1,qlen,&q,&x);
assert_eq!(Some(k), kiter.next(), "first value test");
assert_eq!(Some(y), kiter.next(), "second value test");
assert_eq!(Some(z), kiter.next(), "third value test");
}
});
}
};
}
k_generator_tests!(kgen_sha224, Sha224, "SHA224");
k_generator_tests!(kgen_sha256, Sha256, "SHA256");
k_generator_tests!(kgen_sha384, Sha384, "SHA384");
k_generator_tests!(kgen_sha512, Sha512, "SHA512");
}

View File

@@ -1,138 +1,29 @@
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 cryptonum::unsigned::*;
use digest::Digest;
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 pu = p.barrett_u();
let g = generate_verifiable_generator(&p, &pu, &q, &ev, index).unwrap();
assert!(verify_generator(&p, &q, &ev, index, &g));
}
}
#[test]
fn dsa_verification_tests()
{
run_test("tests/dsa/signature.test", 9, |case| {
let (neg0, pbytes) = case.get("p").unwrap();
let (neg1, gbytes) = case.get("g").unwrap();
let (neg2, qbytes) = case.get("q").unwrap();
let (neg4, ybytes) = case.get("y").unwrap();
let (neg5, hbytes) = case.get("h").unwrap();
let (neg6, msg) = case.get("m").unwrap();
let (neg7, rbytes) = case.get("r").unwrap();
let (neg8, sbytes) = case.get("s").unwrap();
assert!(!neg0 & !neg1 & !neg2 & !neg4 &
!neg5 & !neg6 & !neg7 & !neg8);
let p = UCN::from_bytes(pbytes);
let g = UCN::from_bytes(gbytes);
let q = UCN::from_bytes(qbytes);
let params = DSAParameters::new(p, g, q).unwrap();
let y = UCN::from_bytes(ybytes);
let public = DSAPublic::new(&params, y);
let r = UCN::from_bytes(rbytes);
let s = UCN::from_bytes(sbytes);
let sig = DSASignature{ r: r, s: s };
match usize::from(UCN::from_bytes(hbytes)) {
0x1 => assert!(public.verify::<Sha1>(msg, &sig)),
0x224 => assert!(public.verify::<Sha224>(msg, &sig)),
0x256 => assert!(public.verify::<Sha256>(msg, &sig)),
0x384 => assert!(public.verify::<Sha384>(msg, &sig)),
0x512 => assert!(public.verify::<Sha512>(msg, &sig)),
v => panic!("Bad hash size {}!", v)
}
});
}
#[test]
#[ignore]
fn dsa_signing_tests()
{
run_test("tests/dsa/signature.test", 9, |case| {
let (neg0, pbytes) = case.get("p").unwrap();
let (neg1, gbytes) = case.get("g").unwrap();
let (neg2, qbytes) = case.get("q").unwrap();
let (neg3, xbytes) = case.get("x").unwrap();
let (neg4, ybytes) = case.get("y").unwrap();
let (neg5, hbytes) = case.get("h").unwrap();
let (neg6, msg) = case.get("m").unwrap();
assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4 & !neg5 & !neg6);
let p = UCN::from_bytes(pbytes);
let g = UCN::from_bytes(gbytes);
let q = UCN::from_bytes(qbytes);
let params = DSAParameters::new(p, g, q).unwrap();
let y = UCN::from_bytes(ybytes);
let public = DSAPublic::new(&params, y);
let x = UCN::from_bytes(xbytes);
let private = DSAPrivate::new(&params, x);
let hash_size = usize::from(UCN::from_bytes(hbytes));
let sig = match hash_size {
0x1 => private.sign::<Sha1>(msg),
0x224 => private.sign::<Sha224>(msg),
0x256 => private.sign::<Sha256>(msg),
0x384 => private.sign::<Sha384>(msg),
0x512 => private.sign::<Sha512>(msg),
v => panic!("Bad hash size {}!", v)
};
match usize::from(UCN::from_bytes(hbytes)) {
0x1 => assert!(public.verify::<Sha1>(msg, &sig)),
0x224 => assert!(public.verify::<Sha224>(msg, &sig)),
0x256 => assert!(public.verify::<Sha256>(msg, &sig)),
0x384 => assert!(public.verify::<Sha384>(msg, &sig)),
0x512 => assert!(public.verify::<Sha512>(msg, &sig)),
v => panic!("Bad hash size {}!", v)
}
});
}
use dsa::params::{DSAParameters,L1024N160,L2048N256};
use dsa::private::{DSAPrivateKey,DSAPrivKey};
use dsa::public::{DSAPublicKey,DSAPubKey};
use dsa::rfc6979::KIterator;
macro_rules! run_rfc6979_test {
($hash: ty, $val: ident, $public: ident, $private: ident,
($hash: ty, $ntype: ident, $val: ident, $params: 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 h1 = <$hash>::digest(&$val);
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);
let r = $ntype::from_bytes(&rbytes);
let s = $ntype::from_bytes(&sbytes);
let mut iter = KIterator::<$hash,$ntype>::new(&h1, $params.n_bits(), &$params.q, &$private.x);
let mut k1 = iter.next().unwrap().to_bytes().to_vec();
while k1.len() > $k.len() {
assert_eq!(k1[0], 0);
k1.remove(0);
}
assert_eq!($k, k1);
let sig = $private.sign::<$hash>(&$val);
assert_eq!(sig.r, r);
@@ -202,14 +93,14 @@ fn appendix_a21() {
0x86, 0xE2, 0x22, 0x31, 0x70, 0xB4, 0x4E, 0xAA,
0x7D, 0xA5, 0xDD, 0x9F, 0xFC, 0xFB, 0x7F, 0x3B];
//
let p = UCN::from_bytes(&pbytes);
let q = UCN::from_bytes(&qbytes);
let g = UCN::from_bytes(&gbytes);
let params = DSAParameters::new(p, g, q).unwrap();
let x = UCN::from_bytes(&xbytes);
let y = UCN::from_bytes(&ybytes);
let private = DSAPrivate::new(&params, x);
let public = DSAPublic::new(&params, y);
let p = U1024::from_bytes(&pbytes);
let q = U192::from_bytes(&qbytes);
let g = U1024::from_bytes(&gbytes);
let params = L1024N160::new(p, g, q);
let x = U192::from_bytes(&xbytes);
let y = U1024::from_bytes(&ybytes);
let private = DSAPrivKey::new(params.clone(), x);
let public = DSAPubKey::<L1024N160,U1024>::new(params.clone(), y);
//
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
@@ -217,7 +108,7 @@ fn appendix_a21() {
// k = 7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B
// r = 2E1A0C2562B2912CAAF89186FB0F42001585DA55
// s = 29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5
run_rfc6979_test!(Sha1, sample, public, private,
run_rfc6979_test!(Sha1, U192, sample, params, public, private,
k vec![0x7B, 0xDB, 0x6B, 0x0F, 0xF7, 0x56, 0xE1, 0xBB,
0x5D, 0x53, 0x58, 0x3E, 0xF9, 0x79, 0x08, 0x2F,
0x9A, 0xD5, 0xBD, 0x5B],
@@ -231,7 +122,7 @@ fn appendix_a21() {
// k = 562097C06782D60C3037BA7BE104774344687649
// r = 4BC3B686AEA70145856814A6F1BB53346F02101E
// s = 410697B92295D994D21EDD2F4ADA85566F6F94C1
run_rfc6979_test!(Sha224, sample, public, private,
run_rfc6979_test!(Sha224, U192, sample, params, public, private,
k vec![0x56, 0x20, 0x97, 0xC0, 0x67, 0x82, 0xD6, 0x0C,
0x30, 0x37, 0xBA, 0x7B, 0xE1, 0x04, 0x77, 0x43,
0x44, 0x68, 0x76, 0x49],
@@ -245,7 +136,7 @@ fn appendix_a21() {
// k = 519BA0546D0C39202A7D34D7DFA5E760B318BCFB
// r = 81F2F5850BE5BC123C43F71A3033E9384611C545
// s = 4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89
run_rfc6979_test!(Sha256, sample, public, private,
run_rfc6979_test!(Sha256, U192, sample, params, public, private,
k vec![0x51, 0x9B, 0xA0, 0x54, 0x6D, 0x0C, 0x39, 0x20,
0x2A, 0x7D, 0x34, 0xD7, 0xDF, 0xA5, 0xE7, 0x60,
0xB3, 0x18, 0xBC, 0xFB],
@@ -259,7 +150,7 @@ fn appendix_a21() {
// k = 95897CD7BBB944AA932DBC579C1C09EB6FCFC595
// r = 07F2108557EE0E3921BC1774F1CA9B410B4CE65A
// s = 54DF70456C86FAC10FAB47C1949AB83F2C6F7595
run_rfc6979_test!(Sha384, sample, public, private,
run_rfc6979_test!(Sha384, U192, sample, params, public, private,
k vec![0x95, 0x89, 0x7C, 0xD7, 0xBB, 0xB9, 0x44, 0xAA,
0x93, 0x2D, 0xBC, 0x57, 0x9C, 0x1C, 0x09, 0xEB,
0x6F, 0xCF, 0xC5, 0x95],
@@ -273,7 +164,7 @@ fn appendix_a21() {
// k = 09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B
// r = 16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B
// s = 02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C
run_rfc6979_test!(Sha512, sample, public, private,
run_rfc6979_test!(Sha512, U192, sample, params, public, private,
k vec![0x09, 0xEC, 0xE7, 0xCA, 0x27, 0xD0, 0xF5, 0xA4,
0xDD, 0x4E, 0x55, 0x6C, 0x9D, 0xF1, 0xD2, 0x1D,
0x28, 0x10, 0x4F, 0x8B],
@@ -287,7 +178,7 @@ fn appendix_a21() {
// k = 5C842DF4F9E344EE09F056838B42C7A17F4A6433
// r = 42AB2052FD43E123F0607F115052A67DCD9C5C77
// s = 183916B0230D45B9931491D4C6B0BD2FB4AAF088
run_rfc6979_test!(Sha1, test, public, private,
run_rfc6979_test!(Sha1, U192, test, params, public, private,
k vec![0x5C, 0x84, 0x2D, 0xF4, 0xF9, 0xE3, 0x44, 0xEE,
0x09, 0xF0, 0x56, 0x83, 0x8B, 0x42, 0xC7, 0xA1,
0x7F, 0x4A, 0x64, 0x33],
@@ -301,7 +192,7 @@ fn appendix_a21() {
// k = 4598B8EFC1A53BC8AECD58D1ABBB0C0C71E67297
// r = 6868E9964E36C1689F6037F91F28D5F2C30610F2
// s = 49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F
run_rfc6979_test!(Sha224, test, public, private,
run_rfc6979_test!(Sha224, U192, test, params, public, private,
k vec![0x45, 0x98, 0xB8, 0xEF, 0xC1, 0xA5, 0x3B, 0xC8,
0xAE, 0xCD, 0x58, 0xD1, 0xAB, 0xBB, 0x0C, 0x0C,
0x71, 0xE6, 0x72, 0x97],
@@ -315,7 +206,7 @@ fn appendix_a21() {
// k = 5A67592E8128E03A417B0484410FB72C0B630E1A
// r = 22518C127299B0F6FDC9872B282B9E70D0790812
// s = 6837EC18F150D55DE95B5E29BE7AF5D01E4FE160
run_rfc6979_test!(Sha256, test, public, private,
run_rfc6979_test!(Sha256, U192, test, params, public, private,
k vec![0x5A, 0x67, 0x59, 0x2E, 0x81, 0x28, 0xE0, 0x3A,
0x41, 0x7B, 0x04, 0x84, 0x41, 0x0F, 0xB7, 0x2C,
0x0B, 0x63, 0x0E, 0x1A],
@@ -329,7 +220,7 @@ fn appendix_a21() {
// k = 220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89
// r = 854CF929B58D73C3CBFDC421E8D5430CD6DB5E66
// s = 91D0E0F53E22F898D158380676A871A157CDA622
run_rfc6979_test!(Sha384, test, public, private,
run_rfc6979_test!(Sha384, U192, test, params, public, private,
k vec![0x22, 0x01, 0x56, 0xB7, 0x61, 0xF6, 0xCA, 0x5E,
0x6C, 0x9F, 0x1B, 0x9C, 0xF9, 0xC2, 0x4B, 0xE2,
0x5F, 0x98, 0xCD, 0x89],
@@ -343,7 +234,7 @@ fn appendix_a21() {
// k = 65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C
// r = 8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0
// s = 7C670C7AD72B6C050C109E1790008097125433E8
run_rfc6979_test!(Sha512, test, public, private,
run_rfc6979_test!(Sha512, U192, test, params, public, private,
k vec![0x65, 0xD2, 0xC2, 0xEE, 0xB1, 0x75, 0xE3, 0x70,
0xF2, 0x8C, 0x75, 0xBF, 0xCD, 0xC0, 0x28, 0xD2,
0x2C, 0x7D, 0xBE, 0x9C],
@@ -462,14 +353,14 @@ fn appendix_a22() {
0xD4,0xA0,0x98,0x63,0x15,0xDA,0x8E,0xEC,
0x65,0x61,0xC9,0x38,0x99,0x6B,0xEA,0xDF];
//
let p = UCN::from_bytes(&pbytes);
let q = UCN::from_bytes(&qbytes);
let g = UCN::from_bytes(&gbytes);
let params = DSAParameters::new(p, g, q).unwrap();
let x = UCN::from_bytes(&xbytes);
let y = UCN::from_bytes(&ybytes);
let private = DSAPrivate::new(&params, x);
let public = DSAPublic::new(&params, y);
let p = U2048::from_bytes(&pbytes);
let q = U256::from_bytes(&qbytes);
let g = U2048::from_bytes(&gbytes);
let params = L2048N256::new(p, g, q);
let x = U256::from_bytes(&xbytes);
let y = U2048::from_bytes(&ybytes);
let private = DSAPrivKey::<L2048N256,U256>::new(params.clone(), x);
let public = DSAPubKey::<L2048N256,U2048>::new(params.clone(), y);
//
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
@@ -477,7 +368,7 @@ fn appendix_a22() {
// k = 888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E
// r = 3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A
// s = D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF
run_rfc6979_test!(Sha1, sample, public, private,
run_rfc6979_test!(Sha1, U256, sample, params, 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,
@@ -494,7 +385,7 @@ fn appendix_a22() {
// k = BC372967702082E1AA4FCE892209F71AE4AD25A6DFD869334E6F153BD0C4D806
// r = DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C
// s = A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC
run_rfc6979_test!(Sha224, sample, public, private,
run_rfc6979_test!(Sha224, U256, sample, params, 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,
@@ -511,7 +402,7 @@ fn appendix_a22() {
// k = 8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52
// r = EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809
// s = 7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53
run_rfc6979_test!(Sha256, sample, public, private,
run_rfc6979_test!(Sha256, U256, sample, params, 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,
@@ -528,7 +419,7 @@ fn appendix_a22() {
// k = C345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920
// r = B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B
// s = 19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B
run_rfc6979_test!(Sha384, sample, public, private,
run_rfc6979_test!(Sha384, U256, sample, params, 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,
@@ -545,7 +436,7 @@ fn appendix_a22() {
// k = 5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC
// r = 2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E
// s = D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351
run_rfc6979_test!(Sha512, sample, public, private,
run_rfc6979_test!(Sha512, U256, sample, params, 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,
@@ -562,7 +453,7 @@ fn appendix_a22() {
// k = 6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F
// r = C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0
// s = 414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA
run_rfc6979_test!(Sha1, test, public, private,
run_rfc6979_test!(Sha1, U256, test, params, 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,
@@ -579,7 +470,7 @@ fn appendix_a22() {
// k = 06BD4C05ED74719106223BE33F2D95DA6B3B541DAD7BFBD7AC508213B6DA6670
// r = 272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3
// s = E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806
run_rfc6979_test!(Sha224, test, public, private,
run_rfc6979_test!(Sha224, U256, test, params, 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,
@@ -596,7 +487,7 @@ fn appendix_a22() {
// k = 1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7
// r = 8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0
// s = 7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E
run_rfc6979_test!(Sha256, test, public, private,
run_rfc6979_test!(Sha256, U256, test, params, 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,
@@ -613,7 +504,7 @@ fn appendix_a22() {
// k = 206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C
// r = 239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE
// s = 6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961
run_rfc6979_test!(Sha384, test, public, private,
run_rfc6979_test!(Sha384, U256, test, params, 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,
@@ -630,7 +521,7 @@ fn appendix_a22() {
// k = AFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA
// r = 89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307
// s = C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1
run_rfc6979_test!(Sha512, test, public, private,
run_rfc6979_test!(Sha512, U256, test, params, 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,

440
src/ecdsa/curve.rs Normal file
View File

@@ -0,0 +1,440 @@
use cryptonum::signed::{I192,I256,I384,I576};
use cryptonum::unsigned::{Decoder};
use cryptonum::unsigned::{U192,U256,U384,U576};
#[allow(non_snake_case)]
pub trait EllipticCurve {
type Unsigned : Clone;
type Signed : Clone;
fn size() -> usize;
fn p() -> Self::Unsigned;
fn n() -> Self::Unsigned;
fn SEED() -> Self::Unsigned;
fn c() -> Self::Unsigned;
fn a() -> Self::Unsigned;
fn b() -> Self::Unsigned;
fn Gx() -> Self::Signed;
fn Gy() -> Self::Signed;
}
pub enum P192 {}
impl EllipticCurve for P192 {
type Unsigned = U192;
type Signed = I192;
fn size() -> usize {
192
}
fn p() -> U192 {
U192::from([0xffffffffffffffff, 0xfffffffffffffffe, 0xffffffffffffffff])
}
fn n() -> U192 {
U192::from([0x146bc9b1b4d22831, 0xffffffff99def836, 0xffffffffffffffff])
}
fn SEED() -> U192 {
U192::from([0xd38020eae12196d5, 0xc8422f64ed579528, 0x3045ae6f])
}
fn c() -> U192 {
U192::from([0x5f3d6fe2c745de65, 0x542dcd5fb078b6ef, 0x3099d2bbbfcb2538])
}
fn a() -> U192 {
U192::from([0xfffffffffffffffc, 0xfffffffffffffffe, 0xffffffffffffffff])
}
fn b() -> U192 {
U192::from([0xfeb8deecc146b9b1, 0x0fa7e9ab72243049, 0x64210519e59c80e7])
}
fn Gx() -> I192 {
I192::from(U192::from([0xf4ff0afd82ff1012, 0x7cbf20eb43a18800, 0x188da80eb03090f6]))
}
fn Gy() -> I192 {
I192::from(U192::from([0x73f977a11e794811, 0x631011ed6b24cdd5, 0x07192b95ffc8da78]))
}
}
pub enum P224 {}
impl EllipticCurve for P224 {
type Unsigned = U256;
type Signed = I256;
fn size() -> usize {
224
}
fn p() -> U256 {
U256::from_bytes(&[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01
])
}
fn n() -> U256 {
U256::from_bytes(&[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
0x5c, 0x5c, 0x2a, 0x3d
])
}
fn SEED() -> U256 {
U256::from_bytes(&[
0xbd, 0x71, 0x34, 0x47, 0x99, 0xd5, 0xc7, 0xfc,
0xdc, 0x45, 0xb5, 0x9f, 0xa3, 0xb9, 0xab, 0x8f,
0x6a, 0x94, 0x8b, 0xc5
])
}
fn c() -> U256 {
U256::from_bytes(&[
0x5b, 0x05, 0x6c, 0x7e, 0x11, 0xdd, 0x68, 0xf4,
0x04, 0x69, 0xee, 0x7f, 0x3c, 0x7a, 0x7d, 0x74,
0xf7, 0xd1, 0x21, 0x11, 0x65, 0x06, 0xd0, 0x31,
0x21, 0x82, 0x91, 0xfb
])
}
fn a() -> U256 {
U256::from_bytes(&[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfe
])
}
fn b() -> U256 {
U256::from_bytes(&[
0xb4, 0x05, 0x0a, 0x85, 0x0c, 0x04, 0xb3, 0xab,
0xf5, 0x41, 0x32, 0x56, 0x50, 0x44, 0xb0, 0xb7,
0xd7, 0xbf, 0xd8, 0xba, 0x27, 0x0b, 0x39, 0x43,
0x23, 0x55, 0xff, 0xb4
])
}
fn Gx() -> I256 {
I256::from(U256::from_bytes(&[
0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f,
0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3,
0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6,
0x11, 0x5c, 0x1d, 0x21
]))
}
fn Gy() -> I256 {
I256::from(U256::from_bytes(&[
0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb,
0x4c, 0x22, 0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0,
0x5a, 0x07, 0x47, 0x64, 0x44, 0xd5, 0x81, 0x99,
0x85, 0x00, 0x7e, 0x34
]))
}
}
pub enum P256 {}
impl EllipticCurve for P256 {
type Signed = I256;
type Unsigned = U256;
fn size() -> usize {
256
}
fn p() -> U256 {
U256::from_bytes(&[
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
])
}
fn n() -> U256 {
U256::from_bytes(&[
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84,
0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51
])
}
fn SEED() -> U256 {
U256::from_bytes(&[
0xc4, 0x9d, 0x36, 0x08, 0x86, 0xe7, 0x04, 0x93,
0x6a, 0x66, 0x78, 0xe1, 0x13, 0x9d, 0x26, 0xb7,
0x81, 0x9f, 0x7e, 0x90
])
}
fn c() -> U256 {
U256::from_bytes(&[
0x7e, 0xfb, 0xa1, 0x66, 0x29, 0x85, 0xbe, 0x94,
0x03, 0xcb, 0x05, 0x5c, 0x75, 0xd4, 0xf7, 0xe0,
0xce, 0x8d, 0x84, 0xa9, 0xc5, 0x11, 0x4a, 0xbc,
0xaf, 0x31, 0x77, 0x68, 0x01, 0x04, 0xfa, 0x0d
])
}
fn a() -> U256 {
U256::from_bytes(&[
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc
])
}
fn b() -> U256 {
U256::from_bytes(&[
0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7,
0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc,
0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53, 0xb0, 0xf6,
0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b
])
}
fn Gx() -> I256 {
I256::from(U256::from_bytes(&[
0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47,
0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2,
0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0,
0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96
]))
}
fn Gy() -> I256 {
I256::from(U256::from_bytes(&[
0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b,
0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16,
0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce,
0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5
]))
}
}
pub enum P384 {}
impl EllipticCurve for P384 {
type Signed = I384;
type Unsigned = U384;
fn size() -> usize {
384
}
fn p() -> U384 {
U384::from_bytes(&[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
])
}
fn n() -> U384 {
U384::from_bytes(&[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf,
0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a,
0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x73
])
}
fn SEED() -> U384 {
U384::from_bytes(&[
0xa3, 0x35, 0x92, 0x6a, 0xa3, 0x19, 0xa2, 0x7a,
0x1d, 0x00, 0x89, 0x6a, 0x67, 0x73, 0xa4, 0x82,
0x7a, 0xcd, 0xac, 0x73
])
}
fn c() -> U384 {
U384::from_bytes(&[
0x79, 0xd1, 0xe6, 0x55, 0xf8, 0x68, 0xf0, 0x2f,
0xff, 0x48, 0xdc, 0xde, 0xe1, 0x41, 0x51, 0xdd,
0xb8, 0x06, 0x43, 0xc1, 0x40, 0x6d, 0x0c, 0xa1,
0x0d, 0xfe, 0x6f, 0xc5, 0x20, 0x09, 0x54, 0x0a,
0x49, 0x5e, 0x80, 0x42, 0xea, 0x5f, 0x74, 0x4f,
0x6e, 0x18, 0x46, 0x67, 0xcc, 0x72, 0x24, 0x83
])
}
fn a() -> U384 {
U384::from_bytes(&[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfc
])
}
fn b() -> U384 {
U384::from_bytes(&[
0xb3, 0x31, 0x2f, 0xa7, 0xe2, 0x3e, 0xe7, 0xe4,
0x98, 0x8e, 0x05, 0x6b, 0xe3, 0xf8, 0x2d, 0x19,
0x18, 0x1d, 0x9c, 0x6e, 0xfe, 0x81, 0x41, 0x12,
0x03, 0x14, 0x08, 0x8f, 0x50, 0x13, 0x87, 0x5a,
0xc6, 0x56, 0x39, 0x8d, 0x8a, 0x2e, 0xd1, 0x9d,
0x2a, 0x85, 0xc8, 0xed, 0xd3, 0xec, 0x2a, 0xef
])
}
fn Gx() -> I384 {
I384::from(U384::from_bytes(&[
0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37,
0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74,
0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98,
0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38,
0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c,
0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7
]))
}
fn Gy() -> I384 {
I384::from(U384::from_bytes(&[
0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f,
0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29,
0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c,
0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0,
0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d,
0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f
]))
}
}
pub enum P521 {}
impl EllipticCurve for P521 {
type Signed = I576;
type Unsigned = U576;
fn size() -> usize {
521
}
fn p() -> U576 {
U576::from_bytes(&[
0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff
])
}
fn n() -> U576 {
U576::from_bytes(&[
0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfa, 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f,
0x96, 0x6b, 0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09,
0xa5, 0xd0, 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c,
0x47, 0xae, 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38,
0x64, 0x09
])
}
fn SEED() -> U576 {
U576::from_bytes(&[
0xd0, 0x9e, 0x88, 0x00, 0x29, 0x1c, 0xb8, 0x53,
0x96, 0xcc, 0x67, 0x17, 0x39, 0x32, 0x84, 0xaa,
0xa0, 0xda, 0x64, 0xba
])
}
fn c() -> U576 {
U576::from_bytes(&[
0xb4, 0x8b, 0xfa, 0x5f, 0x42, 0x0a, 0x34, 0x94,
0x95, 0x39, 0xd2, 0xbd, 0xfc, 0x26, 0x4e, 0xee,
0xeb, 0x07, 0x76, 0x88, 0xe4, 0x4f, 0xbf, 0x0a,
0xd8, 0xf6, 0xd0, 0xed, 0xb3, 0x7b, 0xd6, 0xb5,
0x33, 0x28, 0x10, 0x00, 0x51, 0x8e, 0x19, 0xf1,
0xb9, 0xff, 0xbe, 0x0f, 0xe9, 0xed, 0x8a, 0x3c,
0x22, 0x00, 0xb8, 0xf8, 0x75, 0xe5, 0x23, 0x86,
0x8c, 0x70, 0xc1, 0xe5, 0xbf, 0x55, 0xba, 0xd6,
0x37
])
}
fn a() -> U576 {
U576::from_bytes(&[
0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfc
])
}
fn b() -> U576 {
U576::from_bytes(&[
0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c, 0x9a,
0x1f, 0x92, 0x9a, 0x21, 0xa0, 0xb6, 0x85, 0x40,
0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3, 0x15,
0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1, 0x09,
0xe1, 0x56, 0x19, 0x39, 0x51, 0xec, 0x7e, 0x93,
0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1, 0xbf,
0x07, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c, 0x34,
0xf1, 0xef, 0x45, 0x1f, 0xd4, 0x6b, 0x50, 0x3f,
0x00
])
}
fn Gx() -> I576 {
I576::from(U576::from_bytes(&[
0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04,
0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95,
0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f,
0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d,
0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7,
0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff,
0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a,
0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5,
0xbd, 0x66
]))
}
fn Gy() -> I576 {
I576::from(U576::from_bytes(&[
0x01, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b,
0xc0, 0x04, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d,
0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b,
0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e,
0x66, 0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4,
0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad,
0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72,
0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1,
0x66, 0x50
]))
}
}

View File

@@ -1,443 +0,0 @@
use cryptonum::{BarrettUCN,SCN,UCN};
use ecdsa::point::ECPoint;
use std::fmt;
pub struct EllipticCurve {
pub name: &'static str,
pub p: [u8; 66],
pub n: [u8; 66],
pub seed: [u8; 66],
pub c: [u8; 66],
pub a: [u8; 66],
pub b: [u8; 66],
pub gx: [u8; 66],
pub gy: [u8; 66]
}
impl fmt::Debug for EllipticCurve {
fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)
}
}
impl PartialEq for EllipticCurve {
fn eq(&self, other: &EllipticCurve) -> bool {
self.name == other.name
}
}
impl EllipticCurve {
pub fn get_p(&self) -> UCN {
UCN::from_bytes(&self.p)
}
pub fn get_pu(&self) -> BarrettUCN {
self.get_p().barrett_uk(self.get_p().contents.len() + 4)
}
pub fn get_n(&self) -> UCN {
UCN::from_bytes(&self.n)
}
pub fn get_seed(&self) -> UCN {
UCN::from_bytes(&self.seed)
}
pub fn get_c(&self) -> UCN {
UCN::from_bytes(&self.c)
}
pub fn get_a(&self) -> UCN {
UCN::from_bytes(&self.a)
}
pub fn get_b(&self) -> UCN {
UCN::from_bytes(&self.b)
}
pub fn default(&'static self) -> ECPoint {
let x = SCN::from(UCN::from_bytes(&self.gx));
let y = SCN::from(UCN::from_bytes(&self.gy));
ECPoint::new(self, x, y)
}
}
pub const NIST_P192: EllipticCurve = EllipticCurve {
name: "secp192r1",
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff ],
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99, 0xde,
0xf8, 0x36, 0x14, 0x6b, 0xc9, 0xb1, 0xb4, 0xd2,
0x28, 0x31 ],
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x45,
0xae, 0x6f, 0xc8, 0x42, 0x2f, 0x64, 0xed, 0x57,
0x95, 0x28, 0xd3, 0x81, 0x20, 0xea, 0xe1, 0x21,
0x96, 0xd5 ],
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x99, 0xd2, 0xbb, 0xbf, 0xcb,
0x25, 0x38, 0x54, 0x2d, 0xcd, 0x5f, 0xb0, 0x78,
0xb6, 0xef, 0x5f, 0x3d, 0x6f, 0xe2, 0xc7, 0x45,
0xde, 0x65 ],
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfc ],
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x64, 0x21, 0x05, 0x19, 0xe5, 0x9c,
0x80, 0xe7, 0x0f, 0xa7, 0xe9, 0xab, 0x72, 0x24,
0x30, 0x49, 0xfe, 0xb8, 0xde, 0xec, 0xc1, 0x46,
0xb9, 0xb1 ],
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x8d, 0xa8, 0x0e, 0xb0, 0x30,
0x90, 0xf6, 0x7c, 0xbf, 0x20, 0xeb, 0x43, 0xa1,
0x88, 0x00, 0xf4, 0xff, 0x0a, 0xfd, 0x82, 0xff,
0x10, 0x12 ],
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0x19, 0x2b, 0x95, 0xff, 0xc8,
0xda, 0x78, 0x63, 0x10, 0x11, 0xed, 0x6b, 0x24,
0xcd, 0xd5, 0x73, 0xf9, 0x77, 0xa1, 0x1e, 0x79,
0x48, 0x11 ]
};
pub const NIST_P224: EllipticCurve = EllipticCurve {
name: "secp224r1",
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01],
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, 0xe0, 0xb8,
0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, 0x5c, 0x5c,
0x2a, 0x3d],
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x71,
0x34, 0x47, 0x99, 0xd5, 0xc7, 0xfc, 0xdc, 0x45,
0xb5, 0x9f, 0xa3, 0xb9, 0xab, 0x8f, 0x6a, 0x94,
0x8b, 0xc5],
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x05,
0x6c, 0x7e, 0x11, 0xdd, 0x68, 0xf4, 0x04, 0x69,
0xee, 0x7f, 0x3c, 0x7a, 0x7d, 0x74, 0xf7, 0xd1,
0x21, 0x11, 0x65, 0x06, 0xd0, 0x31, 0x21, 0x82,
0x91, 0xfb],
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfe],
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x05,
0x0a, 0x85, 0x0c, 0x04, 0xb3, 0xab, 0xf5, 0x41,
0x32, 0x56, 0x50, 0x44, 0xb0, 0xb7, 0xd7, 0xbf,
0xd8, 0xba, 0x27, 0x0b, 0x39, 0x43, 0x23, 0x55,
0xff, 0xb4],
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x0e,
0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, 0x32, 0x13,
0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3, 0x56, 0xc2,
0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, 0x11, 0x5c,
0x1d, 0x21],
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x37,
0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22,
0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07,
0x47, 0x64, 0x44, 0xd5, 0x81, 0x99, 0x85, 0x00,
0x7e, 0x34]
};
pub const NIST_P256: EllipticCurve = EllipticCurve {
name: "secp256r1",
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff],
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17,
0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63,
0x25, 0x51],
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x9d,
0x36, 0x08, 0x86, 0xe7, 0x04, 0x93, 0x6a, 0x66,
0x78, 0xe1, 0x13, 0x9d, 0x26, 0xb7, 0x81, 0x9f,
0x7e, 0x90],
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7e, 0xfb, 0xa1, 0x66, 0x29, 0x85,
0xbe, 0x94, 0x03, 0xcb, 0x05, 0x5c, 0x75, 0xd4,
0xf7, 0xe0, 0xce, 0x8d, 0x84, 0xa9, 0xc5, 0x11,
0x4a, 0xbc, 0xaf, 0x31, 0x77, 0x68, 0x01, 0x04,
0xfa, 0x0d],
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfc],
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a,
0x93, 0xe7, 0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98,
0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2,
0x60, 0x4b],
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c,
0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4,
0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb,
0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98,
0xc2, 0x96],
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a,
0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f,
0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31,
0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf,
0x51, 0xf5]
};
pub const NIST_P384: EllipticCurve = EllipticCurve {
name: "secp384r1",
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff],
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37,
0x2d, 0xdf, 0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0,
0xa7, 0x7a, 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5,
0x29, 0x73],
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x35,
0x92, 0x6a, 0xa3, 0x19, 0xa2, 0x7a, 0x1d, 0x00,
0x89, 0x6a, 0x67, 0x73, 0xa4, 0x82, 0x7a, 0xcd,
0xac, 0x73],
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x79, 0xd1, 0xe6, 0x55, 0xf8, 0x68,
0xf0, 0x2f, 0xff, 0x48, 0xdc, 0xde, 0xe1, 0x41,
0x51, 0xdd, 0xb8, 0x06, 0x43, 0xc1, 0x40, 0x6d,
0x0c, 0xa1, 0x0d, 0xfe, 0x6f, 0xc5, 0x20, 0x09,
0x54, 0x0a, 0x49, 0x5e, 0x80, 0x42, 0xea, 0x5f,
0x74, 0x4f, 0x6e, 0x18, 0x46, 0x67, 0xcc, 0x72,
0x24, 0x83],
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xfc],
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xb3, 0x31, 0x2f, 0xa7, 0xe2, 0x3e,
0xe7, 0xe4, 0x98, 0x8e, 0x05, 0x6b, 0xe3, 0xf8,
0x2d, 0x19, 0x18, 0x1d, 0x9c, 0x6e, 0xfe, 0x81,
0x41, 0x12, 0x03, 0x14, 0x08, 0x8f, 0x50, 0x13,
0x87, 0x5a, 0xc6, 0x56, 0x39, 0x8d, 0x8a, 0x2e,
0xd1, 0x9d, 0x2a, 0x85, 0xc8, 0xed, 0xd3, 0xec,
0x2a, 0xef],
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b,
0x05, 0x37, 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20,
0xad, 0x74, 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7,
0x9b, 0x98, 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54,
0x2a, 0x38, 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55,
0x29, 0x6c, 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76,
0x0a, 0xb7],
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26,
0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92,
0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a,
0x14, 0x7c, 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0,
0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e,
0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea,
0x0e, 0x5f]
};
pub const NIST_P521: EllipticCurve = EllipticCurve {
name: "secp521r1",
p: [ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff ],
n: [ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfa, 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f,
0x96, 0x6b, 0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09,
0xa5, 0xd0, 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c,
0x47, 0xae, 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38,
0x64, 0x09 ],
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x9e,
0x88, 0x00, 0x29, 0x1c, 0xb8, 0x53, 0x96, 0xcc,
0x67, 0x17, 0x39, 0x32, 0x84, 0xaa, 0xa0, 0xda,
0x64, 0xba ],
c: [ 0x00, 0xb4, 0x8b, 0xfa, 0x5f, 0x42, 0x0a, 0x34,
0x94, 0x95, 0x39, 0xd2, 0xbd, 0xfc, 0x26, 0x4e,
0xee, 0xeb, 0x07, 0x76, 0x88, 0xe4, 0x4f, 0xbf,
0x0a, 0xd8, 0xf6, 0xd0, 0xed, 0xb3, 0x7b, 0xd6,
0xb5, 0x33, 0x28, 0x10, 0x00, 0x51, 0x8e, 0x19,
0xf1, 0xb9, 0xff, 0xbe, 0x0f, 0xe9, 0xed, 0x8a,
0x3c, 0x22, 0x00, 0xb8, 0xf8, 0x75, 0xe5, 0x23,
0x86, 0x8c, 0x70, 0xc1, 0xe5, 0xbf, 0x55, 0xba,
0xd6, 0x37 ],
a: [ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfc ],
b: [ 0x00, 0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c,
0x9a, 0x1f, 0x92, 0x9a, 0x21, 0xa0, 0xb6, 0x85,
0x40, 0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3,
0x15, 0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1,
0x09, 0xe1, 0x56, 0x19, 0x39, 0x51, 0xec, 0x7e,
0x93, 0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1,
0xbf, 0x07, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c,
0x34, 0xf1, 0xef, 0x45, 0x1f, 0xd4, 0x6b, 0x50,
0x3f, 0x00 ],
gx: [ 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04,
0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95,
0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f,
0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d,
0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7,
0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff,
0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a,
0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5,
0xbd, 0x66 ],
gy: [ 0x00, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b,
0xc0, 0x04, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d,
0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b,
0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e,
0x66, 0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4,
0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad,
0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72,
0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1,
0x66, 0x50 ]
};

View File

@@ -1,187 +0,0 @@
use cryptonum::{SCN,UCN};
//use dsa::rfc6979::*;
use ecdsa::curves::*;
use ecdsa::point::ECPoint;
//use ecdsa::private::ECDSAPrivate;
//use ecdsa::public::ECDSAPublic;
//use sha1::Sha1;
//use sha2::{Sha224,Sha256,Sha384,Sha512};
use testing::run_test;
fn get_curve(cbytes: &[u8]) -> &'static EllipticCurve {
match usize::from(UCN::from_bytes(cbytes)) {
0x192 => &NIST_P192,
0x224 => &NIST_P224,
0x256 => &NIST_P256,
0x384 => &NIST_P384,
0x521 => &NIST_P521,
x => panic!("Unacceptable curve identifier {}", x)
}
}
#[test]
fn point_negate()
{
run_test("tests/ecdsa/ec_negate.test", 5, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, cbytes) = case.get("c").unwrap();
let (neg3, xbytes) = case.get("x").unwrap();
let (neg4, ybytes) = case.get("y").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4);
let curve = get_curve(&cbytes);
let x = SCN::from(UCN::from_bytes(xbytes));
let y = SCN::from(UCN::from_bytes(ybytes));
let orig = ECPoint::new(curve, x, y);
let a = SCN::from(UCN::from_bytes(abytes));
let b = SCN::from(UCN::from_bytes(bbytes));
let inverted = ECPoint::new(curve, a, b);
assert_eq!(inverted, orig.negate());
});
}
#[test]
fn point_double()
{
run_test("tests/ecdsa/ec_dble.test", 5, |case| {
println!("START");
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, cbytes) = case.get("c").unwrap();
let (neg3, xbytes) = case.get("x").unwrap();
let (neg4, ybytes) = case.get("y").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4);
println!("SEC1");
let curve = get_curve(&cbytes);
println!("SEC2");
let x = SCN::from(UCN::from_bytes(xbytes));
let y = SCN::from(UCN::from_bytes(ybytes));
let orig = ECPoint::new(curve, x, y);
println!("SEC3");
let a = SCN::from(UCN::from_bytes(abytes));
let b = SCN::from(UCN::from_bytes(bbytes));
let doubled = ECPoint::new(curve, a, b);
println!("SEC4");
assert_eq!(doubled, orig.double());
});
}
#[test]
fn point_add()
{
run_test("tests/ecdsa/ec_add.test", 7, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, qbytes) = case.get("q").unwrap();
let (neg3, rbytes) = case.get("r").unwrap();
let (neg4, cbytes) = case.get("c").unwrap();
let (neg5, xbytes) = case.get("x").unwrap();
let (neg6, ybytes) = case.get("y").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5 && !neg6);
let curve = get_curve(&cbytes);
let x = SCN::from(UCN::from_bytes(xbytes));
let y = SCN::from(UCN::from_bytes(ybytes));
let p1 = ECPoint::new(curve, x, y);
let q = SCN::from(UCN::from_bytes(qbytes));
let r = SCN::from(UCN::from_bytes(rbytes));
let p2 = ECPoint::new(curve, q, r);
let a = SCN::from(UCN::from_bytes(abytes));
let b = SCN::from(UCN::from_bytes(bbytes));
let result = ECPoint::new(curve, a, b);
assert_eq!(result, p1.add(&p2));
});
}
#[test]
fn point_scale()
{
run_test("tests/ecdsa/ec_mul.test", 6, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, kbytes) = case.get("k").unwrap();
let (neg3, cbytes) = case.get("c").unwrap();
let (neg4, xbytes) = case.get("x").unwrap();
let (neg5, ybytes) = case.get("y").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5);
let curve = get_curve(&cbytes);
let x = SCN::from(UCN::from_bytes(xbytes));
let y = SCN::from(UCN::from_bytes(ybytes));
let base = ECPoint::new(curve, x, y);
let k = UCN::from_bytes(kbytes);
let a = SCN::from(UCN::from_bytes(abytes));
let b = SCN::from(UCN::from_bytes(bbytes));
let result = ECPoint::new(curve, a, b);
assert_eq!(result, base.scale(&k));
});
}
//#[test]
//fn verification_tests()
//{
// run_test("tests/ecdsa/signature.test", 8, |case| {
// let (neg0, cbytes) = case.get("c").unwrap();
// let (negx, xbytes) = case.get("x").unwrap();
// let (negy, ybytes) = case.get("y").unwrap();
// let (neg1, hbytes) = case.get("h").unwrap();
// let (neg2, msg) = case.get("m").unwrap();
// let (neg3, rbytes) = case.get("r").unwrap();
// let (neg4, sbytes) = case.get("s").unwrap();
//
// assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4);
// let curve = get_curve(cbytes);
// let ux = UCN::from_bytes(xbytes);
// let uy = UCN::from_bytes(ybytes);
// let x = SCN{ negative: *negx, value: ux };
// let y = SCN{ negative: *negy, value: uy };
// let point = ECCPoint::new(&curve, x, y);
// let public = ECDSAPublic::new(&curve, &point);
// let r = UCN::from_bytes(rbytes);
// let s = UCN::from_bytes(sbytes);
// println!("r: {:X}", r);
// 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 signing_tests()
//{
// run_test("tests/ecdsa/signature.test", 8, |case| {
// let (neg0, cbytes) = case.get("c").unwrap();
// let (neg1, dbytes) = case.get("d").unwrap();
// let (neg2, hbytes) = case.get("h").unwrap();
// let (neg3, msg) = case.get("m").unwrap();
// let (neg4, rbytes) = case.get("r").unwrap();
// let (neg5, sbytes) = case.get("s").unwrap();
//
// assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4 & !neg5);
// let curve = get_curve(cbytes);
// let d = UCN::from_bytes(dbytes);
// let private = ECDSAPrivate::new(&curve, &d);
// 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_eq!(sig, private.sign::<Sha1>(msg)),
// 0x224 => assert_eq!(sig, private.sign::<Sha224>(msg)),
// 0x256 => assert_eq!(sig, private.sign::<Sha256>(msg)),
// 0x384 => assert_eq!(sig, private.sign::<Sha384>(msg)),
// 0x512 => assert_eq!(sig, private.sign::<Sha512>(msg)),
// v => panic!("Bad hash size {}!", v)
// }
// });
//}

View File

@@ -1,61 +1,54 @@
mod curves;
#[cfg(test)]
mod gold_tests;
mod point;
//mod private;
//mod public;
//
//pub use self::private::ECDSAPrivate;
//pub use self::public::ECDSAPublic;
pub use self::curves::{NIST_P192,NIST_P224,NIST_P256,NIST_P384,NIST_P521};
//
//use cryptonum::UCN;
//use rand::{Rng,OsRng};
//use self::curves::EllipticCurve;
//use self::math::ECCPoint;
//
//#[derive(Clone,Debug,PartialEq)]
//pub struct ECDSAKeyPair {
// pub private: ECDSAPrivate,
// pub public: ECDSAPublic
//}
//
//impl ECDSAKeyPair {
// pub fn generate(params: &'static EllipticCurve)
// -> ECDSAKeyPair
// {
// let mut rng = OsRng::new().unwrap();
// ECDSAKeyPair::generate_w_rng(&mut rng, params)
//
// }
//
// pub fn generate_w_rng<G: Rng>(rng: &mut G, params: &'static EllipticCurve)
// -> ECDSAKeyPair
// {
// let one = UCN::from(1u64);
// #[allow(non_snake_case)]
// let N = params.n.bits();
// let bits_to_generate = N + 64;
// let bytes_to_generate = (bits_to_generate + 7) / 8;
// let bits: Vec<u8> = rng.gen_iter().take(bytes_to_generate).collect();
// let bits_generated = bytes_to_generate * 8;
// let mut c = UCN::from_bytes(&bits);
// c >>= bits_generated - bits_to_generate;
// let nm1 = &params.n - &one;
// let d = (c % &nm1) + &one;
// #[allow(non_snake_case)]
// let Q = ECCPoint::default(params).scale(&d);
// ECDSAKeyPair {
// private: ECDSAPrivate {
// curve: params,
// d: d
// },
// public: ECDSAPublic {
// curve: params,
// Q: Q
// }
// }
// }
//}
//
//
pub mod curve;
pub mod point;
pub mod private;
pub mod public;
use cryptonum::signed::{I192,I256,I384,I576};
use cryptonum::unsigned::{CryptoNum,Decoder};
use cryptonum::unsigned::{U192,U256,U384,U576};
use rand::Rng;
use rand::distributions::Standard;
use self::curve::{EllipticCurve,P192,P224,P256,P384,P521};
use self::point::{ECCPoint,Point};
pub use self::private::{ECCPrivateKey,ECCPrivate};
pub use self::public::{ECCPublicKey,ECDSAPublic,ECCPubKey};
pub use self::public::{ECDSADecodeErr,ECDSAEncodeErr};
pub trait ECDSAKeyPair<Public,Private> {
fn generate<G: Rng>(g: &mut G) -> (Public, Private);
}
macro_rules! generate_impl {
($curve: ident, $un: ident, $si: ident) => {
impl ECDSAKeyPair<ECCPubKey<$curve>,ECCPrivate<$curve>> for $curve {
fn generate<G: Rng>(rng: &mut G) -> (ECCPubKey<$curve>, ECCPrivate<$curve>)
{
loop {
let size = ($curve::size() + 7) / 8;
let random_bytes: Vec<u8> = rng.sample_iter(&Standard).take(size).collect();
let proposed_d = $un::from_bytes(&random_bytes);
if proposed_d.is_zero() {
continue;
}
if proposed_d >= $curve::n() {
continue;
}
let d = $si::from(&proposed_d);
let public_point = Point::<$curve>::default().scale(&d);
let public = ECCPubKey::<$curve>::new(public_point);
let private = ECCPrivate::<$curve>::new(proposed_d);
return (public, private);
}
}
}
};
}
generate_impl!(P192, U192, I192);
generate_impl!(P224, U256, I256);
generate_impl!(P256, U256, I256);
generate_impl!(P384, U384, I384);
generate_impl!(P521, U576, I576);

View File

@@ -1,227 +1,293 @@
use cryptonum::{SCN,UCN};
use ecdsa::curves::EllipticCurve;
use cryptonum::signed::*;
use cryptonum::unsigned::*;
use ecdsa::curve::*;
#[derive(Clone,Debug,PartialEq)]
pub struct ECPoint {
pub curve: &'static EllipticCurve,
pub value: ECPointValue
pub trait ECCPoint : Sized {
type Curve: EllipticCurve;
type Scale;
fn default() -> Self;
fn negate(&self) -> Self;
fn double(&self) -> Self;
fn add(&self, other: &Self) -> Self;
fn scale(&self, amt: &Self::Scale) -> Self;
fn double_scalar_mult(x1: &Self::Scale, p1: &Self, x2: &Self::Scale, p2: &Self) -> Self
{
// FIXME: Replace this with something not stupid.
let big1 = p1.scale(x1);
let big2 = p2.scale(x2);
big1.add(&big2)
}
}
#[derive(Clone,Debug,PartialEq)]
pub enum ECPointValue {
Infinity,
Point(SCN, SCN)
pub struct Point<T: EllipticCurve>
{
pub x: T::Signed,
pub y: T::Signed
}
impl ECPoint {
pub fn new(ec: &'static EllipticCurve, x: SCN, y: SCN) -> ECPoint {
ECPoint {
curve: ec,
value: ECPointValue::Point(x, y)
}
}
pub fn zero(ec: &'static EllipticCurve) -> ECPoint {
ECPoint { curve: ec, value: ECPointValue::Infinity }
}
pub fn negate(&self) -> ECPoint {
match self.value {
ECPointValue::Infinity =>
self.clone(),
ECPointValue::Point(ref x, ref y) => {
let newy = SCN::from(self.curve.get_p()) - y;
let newv = ECPointValue::Point(x.clone(), newy);
ECPoint{ curve: self.curve, value: newv }
macro_rules! point_impl
{
($curve: ident, $base: ident,
$s2: ident, $u2: ident,
$s2p1: ident, $u2p1: ident) =>
{
impl Clone for Point<$curve> {
fn clone(&self) -> Point<$curve> {
Point {
x: self.x.clone(),
y: self.y.clone()
}
}
}
}
pub fn get_x(&self) -> SCN {
match self.value {
ECPointValue::Infinity =>
SCN::zero(),
ECPointValue::Point(ref x, _) =>
x.clone()
}
}
impl ECCPoint for Point<$curve> {
type Curve = $curve;
type Scale = $base;
pub fn get_y(&self) -> SCN {
match self.value {
ECPointValue::Infinity =>
SCN::zero(),
ECPointValue::Point(_, ref y) =>
y.clone()
}
}
fn default() -> Point<$curve>
{
Point {
x: $curve::Gx(),
y: $curve::Gy()
}
}
pub fn double(&self) -> ECPoint {
match self.value {
ECPointValue::Infinity =>
self.clone(),
ECPointValue::Point(ref x, ref y) => {
let ua = SCN::from(self.curve.get_a());
let up = SCN::from(self.curve.get_p());
fn negate(&self) -> Point<$curve>
{
let mut newy = $base::new(false, $curve::p());
newy -= &self.y;
Point{ x: self.x.clone(), y: newy }
}
fn double(&self) -> Point<$curve>
{
let up = $curve::p();
let bigp = $s2::new(false, $u2::from(&up));
// lambda = (3 * xp ^ 2 + a) / 2 yp
let mut lambda = x * x;
lambda *= SCN::from(3);
lambda += &ua;
let twoy = y << 1;
lambda = lambda.divmod(&twoy, &self.curve.get_pu());
// xr = lambda ^ 2 - 2 xp
let mut xr = &lambda * &lambda;
let xr_right = x << 1;
let xsquared = self.x.square();
let mut lambda_top = &xsquared * 3u64;
lambda_top += $s2p1::new(false, $u2p1::from($curve::a()));
let mut lambda_bot = $s2p1::from(&self.y);
lambda_bot <<= 1;
let lambda = $base::from(lambda_top.moddiv(&lambda_bot, &$s2p1::from(&bigp)));
// xr = lambda^2 - 2 xp
let mut xr = lambda.square();
let mut xr_right = $s2::from(&self.x);
xr_right <<= 1;
xr -= xr_right;
assert!(!xr.is_negative());
xr %= &up;
xr %= &bigp;
let x = $base::from(xr);
// yr = lambda (xp - xr) - yp
let xdiff = x - &xr;
let xdiff = $base::from(&self.x - &x);
let mut yr = &lambda * &xdiff;
yr -= y;
assert!(!yr.is_negative());
yr %= up;
yr -= $s2::from(&self.y);
let y = $base::from(&yr % &bigp);
//
ECPoint {
curve: self.curve,
value: ECPointValue::Point(xr, yr)
}
Point{ x, y }
}
}
}
pub fn add(&self, other: &ECPoint) -> ECPoint {
assert_eq!(self.curve, other.curve);
match (&self.value, &other.value) {
(ECPointValue::Infinity, ECPointValue::Infinity) =>
self.clone(),
(ECPointValue::Infinity, _) =>
other.clone(),
(_, ECPointValue::Infinity) =>
self.clone(),
(ECPointValue::Point(ref sx, ref sy),
ECPointValue::Point(ref ox, ref oy)) => {
let xdiff = sx - ox;
let ydiff = sy - oy;
let pu = self.curve.get_pu();
let s = ydiff.divmod(&xdiff, &pu);
fn add(&self, other: &Point<$curve>) -> Point<$curve>
{
let mut xdiff = self.x.clone(); xdiff -= &other.x;
let mut ydiff = self.y.clone(); ydiff -= &other.y;
let signedp = $base::new(false, $curve::p());
let s = ydiff.moddiv(&xdiff, &signedp);
let mut xr = &s * &s;
xr -= sx;
xr -= ox;
xr = xr.reduce(&pu);
let mut yr = sx - &xr;
yr *= &s;
yr -= sy;
yr = yr.reduce(&pu);
let val = ECPointValue::Point(xr, yr);
ECPoint{ curve: self.curve, value: val }
}
}
}
xr -= $s2::from(&self.x);
xr -= $s2::from(&other.x);
let bigsignedp = $s2::from(&signedp);
xr %= &bigsignedp;
let mut yr = $s2::from(&self.x);
yr -= &xr;
yr *= $s2::from(&s);
yr -= $s2::from(&self.y);
yr %= &bigsignedp;
Point{ x: $base::from(xr), y: $base::from(yr) }
}
pub fn scale(&self, d: &UCN) -> ECPoint {
match self.value {
ECPointValue::Infinity =>
self.clone(),
ECPointValue::Point(_, _) => {
if d.is_zero() {
return ECPoint::zero(self.curve);
fn scale(&self, d: &$base) -> Point<$curve>
{
assert!(!d.is_zero());
#[allow(non_snake_case)]
let mut Q: Point<$curve> = self.clone();
let mut bit = ($base::bit_length() - 1) as isize;
// Skip down until we hit a set bit
while !d.testbit(bit as usize) {
bit -= 1;
}
// drop one
bit -= 1;
// do the double and add algorithm
while bit >= 0 {
Q = Q.double();
let mut q = self.clone();
let i = d.bits() - 2;
let mut mask = UCN::from(1u64) << i;
while !mask.is_zero() {
q = q.double();
let test = d & &mask;
if !test.is_zero() {
q = q.add(&self);
let test = d.testbit(bit as usize);
if test {
Q = Q.add(&self);
}
mask >>= 1;
bit -= 1;
}
q
if d.is_negative() {
Q.negate()
} else {
Q
}
}
}
}
}
//
// 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
// }
//
// pub fn point_add_two_muls(k1: &UCN, p1: &ECCPoint, k2: &UCN, p2: &ECCPoint)
// -> ECCPoint
// {
// panic!("point_add_two_muls()")
// }
//
// #[cfg(test)]
// mod tests {
// use super::*;
//
// #[test]
// fn p256_double() {
// let xbytes = vec![0x7c, 0xf2, 0x7b, 0x18, 0x8d, 0x03, 0x4f, 0x7e,
// 0x8a, 0x52, 0x38, 0x03, 0x04, 0xb5, 0x1a, 0xc3,
// 0xc0, 0x89, 0x69, 0xe2, 0x77, 0xf2, 0x1b, 0x35,
// 0xa6, 0x0b, 0x48, 0xfc, 0x47, 0x66, 0x99, 0x78];
// let ybytes = vec![0x07, 0x77, 0x55, 0x10, 0xdb, 0x8e, 0xd0, 0x40,
// 0x29, 0x3d, 0x9a, 0xc6, 0x9f, 0x74, 0x30, 0xdb,
// 0xba, 0x7d, 0xad, 0xe6, 0x3c, 0xe9, 0x82, 0x29,
// 0x9e, 0x04, 0xb7, 0x9d, 0x22, 0x78, 0x73, 0xd1];
// let x = SCN::from(UCN::from_bytes(&xbytes));
// let y = SCN::from(UCN::from_bytes(&ybytes));
// let base = ECCPoint::default(&EllipticCurve::p256());
// let res = base.double();
// let goal = ECCPoint{ curve: base.curve,
// value: ECCPointValue::Point(x,y) };
// assert_eq!(res, goal);
// }
//
// #[test]
// fn p256_add() {
// let xbytes = vec![0x5e, 0xcb, 0xe4, 0xd1, 0xa6, 0x33, 0x0a, 0x44,
// 0xc8, 0xf7, 0xef, 0x95, 0x1d, 0x4b, 0xf1, 0x65,
// 0xe6, 0xc6, 0xb7, 0x21, 0xef, 0xad, 0xa9, 0x85,
// 0xfb, 0x41, 0x66, 0x1b, 0xc6, 0xe7, 0xfd, 0x6c];
// let ybytes = vec![0x87, 0x34, 0x64, 0x0c, 0x49, 0x98, 0xff, 0x7e,
// 0x37, 0x4b, 0x06, 0xce, 0x1a, 0x64, 0xa2, 0xec,
// 0xd8, 0x2a, 0xb0, 0x36, 0x38, 0x4f, 0xb8, 0x3d,
// 0x9a, 0x79, 0xb1, 0x27, 0xa2, 0x7d, 0x50, 0x32];
// let x = SCN::from(UCN::from_bytes(&xbytes));
// let y = SCN::from(UCN::from_bytes(&ybytes));
// let base = ECCPoint::default(&EllipticCurve::p256());
// let res = base.add(&base.double());
// let goal = ECCPoint{ curve: base.curve,
// value: ECCPointValue::Point(x,y) };
// assert_eq!(res, goal);
// }
//
// #[test]
// fn p256_scale() {
// let xbytes = vec![0xea, 0x68, 0xd7, 0xb6, 0xfe, 0xdf, 0x0b, 0x71,
// 0x87, 0x89, 0x38, 0xd5, 0x1d, 0x71, 0xf8, 0x72,
// 0x9e, 0x0a, 0xcb, 0x8c, 0x2c, 0x6d, 0xf8, 0xb3,
// 0xd7, 0x9e, 0x8a, 0x4b, 0x90, 0x94, 0x9e, 0xe0];
// let ybytes = vec![0x2a, 0x27, 0x44, 0xc9, 0x72, 0xc9, 0xfc, 0xe7,
// 0x87, 0x01, 0x4a, 0x96, 0x4a, 0x8e, 0xa0, 0xc8,
// 0x4d, 0x71, 0x4f, 0xea, 0xa4, 0xde, 0x82, 0x3f,
// 0xe8, 0x5a, 0x22, 0x4a, 0x4d, 0xd0, 0x48, 0xfa];
// let x = SCN::from(UCN::from_bytes(&xbytes));
// let y = SCN::from(UCN::from_bytes(&ybytes));
// let base = ECCPoint::default(&EllipticCurve::p256());
// let res = base.scale(&UCN::from(9 as u64));
// let goal = ECCPoint{ curve: base.curve,
// value: ECCPointValue::Point(x,y) };
// assert_eq!(res, goal);
// }
// }
point_impl!(P192, I192, I384, U384, I448, U448);
point_impl!(P224, I256, I512, U512, I576, U576);
point_impl!(P256, I256, I512, U512, I576, U576);
point_impl!(P384, I384, I768, U768, I832, U832);
point_impl!(P521, I576, I1152, U1152, I1216, U1216);
macro_rules! point_tests
{
($curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
#[cfg(test)]
mod $lcurve {
use super::*;
use testing::*;
#[test]
fn negate() {
let fname = build_test_path("ecc/negate",stringify!($curve));
run_test(fname.to_string(), 4, |case| {
let (negx, xbytes) = case.get("x").unwrap();
let (negy, ybytes) = case.get("y").unwrap();
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let x = $stype::new(*negx, $utype::from_bytes(xbytes));
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
let a = $stype::new(*nega, $utype::from_bytes(abytes));
let b = $stype::new(*negb, $utype::from_bytes(bbytes));
let point = Point::<$curve>{ x, y };
let dbl = point.negate();
assert_eq!(a, dbl.x, "x equivalence");
assert_eq!(b, dbl.y, "y equivalence");
});
}
#[test]
fn double() {
let fname = build_test_path("ecc/double",stringify!($curve));
run_test(fname.to_string(), 4, |case| {
let (negx, xbytes) = case.get("x").unwrap();
let (negy, ybytes) = case.get("y").unwrap();
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let x = $stype::new(*negx, $utype::from_bytes(xbytes));
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
let a = $stype::new(*nega, $utype::from_bytes(abytes));
let b = $stype::new(*negb, $utype::from_bytes(bbytes));
let point = Point::<$curve>{ x, y };
let dbl = point.double();
assert_eq!(a, dbl.x, "x equivalence");
assert_eq!(b, dbl.y, "y equivalence");
});
}
#[test]
fn add() {
let fname = build_test_path("ecc/add",stringify!($curve));
run_test(fname.to_string(), 6, move |case| {
let (negx, xbytes) = case.get("x").unwrap();
let (negy, ybytes) = case.get("y").unwrap();
let (negu, ubytes) = case.get("u").unwrap();
let (negv, vbytes) = case.get("v").unwrap();
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let x = $stype::new(*negx, $utype::from_bytes(xbytes));
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
let u = $stype::new(*negu, $utype::from_bytes(ubytes));
let v = $stype::new(*negv, $utype::from_bytes(vbytes));
let a = $stype::new(*nega, $utype::from_bytes(abytes));
let b = $stype::new(*negb, $utype::from_bytes(bbytes));
let point1 = Point::<$curve>{ x: x, y: y };
let point2 = Point::<$curve>{ x: u, y: v };
let res = point1.add(&point2);
assert_eq!(a, res.x, "x equivalence");
assert_eq!(b, res.y, "y equivalence");
});
}
#[test]
fn scale() {
let fname = build_test_path("ecc/scale",stringify!($curve));
run_test(fname.to_string(), 5, |case| {
let (negx, xbytes) = case.get("x").unwrap();
let (negy, ybytes) = case.get("y").unwrap();
let (negk, kbytes) = case.get("k").unwrap();
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let x = $stype::new(*negx, $utype::from_bytes(xbytes));
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
let k = $stype::new(*negk, $utype::from_bytes(kbytes));
let a = $stype::new(*nega, $utype::from_bytes(abytes));
let b = $stype::new(*negb, $utype::from_bytes(bbytes));
let point = Point::<$curve>{ x: x, y: y };
let res = point.scale(&k);
assert_eq!(a, res.x, "x equivalence");
assert_eq!(b, res.y, "y equivalence");
});
}
#[test]
fn add_scale2() {
let fname = build_test_path("ecc/add_scale2",stringify!($curve));
run_test(fname.to_string(), 8, |case| {
println!("-----------------------------------------------");
let (negx, xbytes) = case.get("x").unwrap();
let (negy, ybytes) = case.get("y").unwrap();
let (negp, pbytes) = case.get("p").unwrap();
let (negq, qbytes) = case.get("q").unwrap();
let (negn, nbytes) = case.get("n").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negr, rbytes) = case.get("r").unwrap();
let (negs, sbytes) = case.get("s").unwrap();
let x = $stype::new(*negx, $utype::from_bytes(xbytes));
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
println!("x1: {:X}", x);
println!("y1: {:X}", y);
let p = $stype::new(*negp, $utype::from_bytes(pbytes));
let q = $stype::new(*negq, $utype::from_bytes(qbytes));
println!("x2: {:X}", p);
println!("y2: {:X}", q);
let n = $stype::new(*negn, $utype::from_bytes(nbytes));
println!("n: {:X}", n);
let m = $stype::new(*negm, $utype::from_bytes(mbytes));
println!("m: {:X}", m);
let r = $stype::new(*negr, $utype::from_bytes(rbytes));
let s = $stype::new(*negs, $utype::from_bytes(sbytes));
println!("rx: {:X}", r);
println!("ry: {:X}", s);
let p1 = Point::<$curve>{ x: x, y: y };
let p2 = Point::<$curve>{ x: p, y: q };
let res = Point::<$curve>::double_scalar_mult(&n, &p1, &m, &p2);
println!("mx: {:X}", res.x);
println!("my: {:X}", res.y);
assert_eq!(r, res.x, "x equivalence");
assert_eq!(s, res.y, "y equivalence");
});
}
}
}
}
point_tests!(P192, p192, I192, U192);
point_tests!(P224, p224, I256, U256);
point_tests!(P256, p256, I256, U256);
point_tests!(P384, p384, I384, U384);
point_tests!(P521, p521, I576, U576);

View File

@@ -1,93 +1,158 @@
use cryptonum::{SCN,UCN};
use digest::{BlockInput,FixedOutput,Input};
use digest::generic_array::ArrayLength;
use dsa::rfc6979::{DSASignature,KIterator};
use ecdsa::curves::EllipticCurve;
use ecdsa::math::{ECCPoint,bits2int};
use hmac::Hmac;
use cryptonum::signed::*;
use cryptonum::unsigned::*;
use digest::{BlockInput,Digest,Input,FixedOutput,Reset};
use dsa::rfc6979::{DSASignature,KIterator,bits2int};
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
use ecdsa::point::{ECCPoint,Point};
use hmac::{Hmac,Mac};
#[derive(Clone,Debug,PartialEq)]
pub struct ECDSAPrivate {
pub(crate) curve: &'static EllipticCurve,
pub(crate) d: UCN
pub struct ECCPrivate<Curve: EllipticCurve> {
d: Curve::Unsigned
}
impl ECDSAPrivate {
pub fn new(c: &'static EllipticCurve, d: &UCN)
-> ECDSAPrivate
{
ECDSAPrivate {
curve: c,
d: d.clone()
}
}
pub trait ECCPrivateKey {
type Unsigned;
pub fn sign<Hash>(&self, m: &[u8]) -> DSASignature
fn new(d: Self::Unsigned) -> Self;
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<Self::Unsigned>
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 = self.curve.p.bits();
let h1: Vec<u8> = digest.fixed_result()
.as_slice()
.iter()
.map(|x| *x)
.collect();
let h0 = bits2int(&h1, n);
let h = h0 % &self.curve.n;
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac;
}
// 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.curve.n, &self.curve.b) {
// 3. A value r (modulo q) is computed from k and the key
// parameters:
// * For DSA ...
// * For ECDSA: the point kG is computed; its X coordinate (a
// member of the field over which E is defined) is converted
// to an integer, which is reduced modulo q, yielding r.
//
// If r turns out to be zero, a new k should be selected and r
// computed again (this is an utterly improbable occurrence).
let g = ECCPoint::default(self.curve);
let kg = g.scale(&k);
let ni = SCN::from(self.curve.n.clone());
let r = &kg.get_x() % &ni;
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 = SCN::from(k.modinv(&ni.value));
let s = ((SCN::from(h.clone()) + (&kg.get_x() * &r)) * &kinv) % &ni;
if s.is_zero() {
continue;
macro_rules! generate_privates
{
($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 }
}
assert!(!r.is_negative());
assert!(!s.is_negative());
return DSASignature{ r: r.value, s: s.value };
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<$base>
where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac
{
// This algorithm is per RFC 6979, which has a nice, relatively
// straightforward description of how to do DSA signing.
//
// 1. H(m) is transformed into an integer modulo q using the bits2int
// transform and an extra modular reduction:
//
// h = bits2int(H(m)) mod q
//
// As was noted in the description of bits2octets, the extra
// modular reduction is no more than a conditional subtraction.
//
let h1 = <Hash>::digest(m);
let size = <$curve>::size();
let h0: $base = bits2int(&h1, size);
let n = <$curve>::n();
let h = h0 % &n;
// 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,$base>::new(&h1, size, &n, &self.d) {
// 3. A value r (modulo q) is computed from k and the key
// parameters:
// * For DSA ...
// * 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 g = Point::<$curve>::default();
let ki = $sig::new(false, k.clone());
let kg = g.scale(&ki);
let ni = $sig::from(&n);
let ri = &kg.x % &ni;
if ri.is_zero() {
continue;
}
if ri.is_negative() {
continue;
}
let r = $base::from(ri);
// 4. The value s (modulo q) is computed:
//
// s = (h+x*r)/k mod q
//
// The pair (r, s) is the signature.
if let Some(kinv) = k.modinv(&n) {
let mut hxr = &self.d * &r;
hxr += $dbl::from(&h);
let base = hxr * $dbl::from(kinv);
let s = $base::from(base % $quad::from(n));
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().");
}
}
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);

View File

@@ -1,62 +1,222 @@
use digest::{BlockInput,FixedOutput,Input};
use digest::generic_array::ArrayLength;
use cryptonum::signed::*;
use cryptonum::unsigned::*;
use digest::{BlockInput,Digest,Input,FixedOutput,Reset};
use dsa::rfc6979::DSASignature;
use ecdsa::curves::EllipticCurve;
use ecdsa::math::{ECCPoint,bits2int,point_add_two_muls};
use hmac::Hmac;
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
use ecdsa::point::{ECCPoint,Point};
use hmac::{Hmac,Mac};
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,FromASN1,ToASN1};
use std::cmp::min;
#[allow(non_snake_case)]
#[derive(Clone,Debug,PartialEq)]
pub struct ECDSAPublic {
pub(crate) curve: &'static EllipticCurve,
pub(crate) Q: ECCPoint
pub struct ECCPubKey<Curve: EllipticCurve> {
q: Point<Curve>
}
impl ECDSAPublic {
pub fn new(curve: &'static EllipticCurve, point: &ECCPoint)
-> ECDSAPublic
{
ECDSAPublic {
curve: curve,
Q: point.clone()
}
}
pub enum ECDSAPublic {
ECCPublicP192(ECCPubKey<P192>),
ECCPublicP224(ECCPubKey<P224>),
ECCPublicP256(ECCPubKey<P256>),
ECCPublicP384(ECCPubKey<P384>),
ECCPublicP521(ECCPubKey<P521>),
}
pub fn verify<Hash>(&self, m: &[u8], sig: &DSASignature) -> bool
pub trait ECCPublicKey {
type Curve : EllipticCurve;
type Unsigned;
fn new(d: Point<Self::Curve>) -> Self;
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<Self::Unsigned>) -> bool
where
Hash: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<Hash>: Clone,
Hash::BlockSize: ArrayLength<u8>
{
let n = &self.curve.n;
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac;
}
if &sig.r > n {
return false;
}
if &sig.s > n {
return false;
}
pub enum ECDSAEncodeErr {
ASN1EncodeErr(ASN1EncodeErr),
XValueNegative, YValueNegative
}
let c = sig.s.modinv(&n);
let mut digest = <Hash>::default();
digest.process(m);
let h1: Vec<u8> = digest.fixed_result()
.as_slice()
.iter()
.map(|x| *x)
.collect();
let h0 = bits2int(&h1, self.curve.p.bits()) % n;
let u1 = (&h0 * &c) % n;
let u2 = (&sig.r * &c) % n;
let x = point_add_two_muls(&u1, &ECCPoint::default(&self.curve),
&u2, &self.Q);
let xx = x.get_x();
if xx.is_negative() {
return false;
}
(xx.value % n) == sig.r
impl From<ASN1EncodeErr> for ECDSAEncodeErr {
fn from(x: ASN1EncodeErr) -> ECDSAEncodeErr {
ECDSAEncodeErr::ASN1EncodeErr(x)
}
}
#[derive(Debug)]
pub enum ECDSADecodeErr {
ASN1DecodeErr(ASN1DecodeErr),
NoKeyFound,
InvalidKeyFormat,
InvalidKeyBlockSize
}
impl From<ASN1DecodeErr> for ECDSADecodeErr {
fn from(x: ASN1DecodeErr) -> ECDSADecodeErr {
ECDSADecodeErr::ASN1DecodeErr(x)
}
}
macro_rules! public_impl {
($curve: ident, $un: ident, $si: ident) => {
impl ECCPublicKey for ECCPubKey<$curve>
{
type Curve = $curve;
type Unsigned = $un;
fn new(q: Point<$curve>) -> ECCPubKey<$curve>
{
ECCPubKey{ q }
}
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<Self::Unsigned>) -> bool
where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac
{
let n = <$curve>::n();
if sig.r.is_zero() || (sig.r >= n) {
return false;
}
if sig.s.is_zero() || (sig.s >= n) {
return false;
}
// e = the leftmost min(N, outlen) bits of Hash(M').
let mut digest_bytes = <Hash>::digest(m).to_vec();
let len = min(digest_bytes.len(), $curve::size() / 8);
digest_bytes.truncate(len);
if let Some(c) = sig.s.modinv(&n) {
let e = $un::from_bytes(&digest_bytes);
let u1 = e.modmul(&c, &n);
let u2 = sig.r.modmul(&c, &n);
let g = Point::<$curve>::default();
let u1i = $si::from(u1);
let u2i = $si::from(u2);
let point = Point::<$curve>::double_scalar_mult(&u1i, &g, &u2i, &self.q);
!point.x.is_negative() && (sig.r == $un::from(point.x))
} else {
false
}
}
}
impl ToASN1 for ECCPubKey<$curve> {
type Error = ECDSAEncodeErr;
fn to_asn1_class(&self, c: ASN1Class) -> Result<Vec<ASN1Block>,ECDSAEncodeErr>
{
if self.q.x.is_negative() {
return Err(ECDSAEncodeErr::XValueNegative);
}
if self.q.y.is_negative() {
return Err(ECDSAEncodeErr::YValueNegative);
}
let xval = $un::from(&self.q.x);
let yval = $un::from(&self.q.y);
let mut xbytes = xval.to_bytes();
let mut ybytes = yval.to_bytes();
let goalsize = ($curve::size() + 7) / 8;
let mut target = Vec::with_capacity(1 + (goalsize * 2));
while xbytes.len() > goalsize { xbytes.remove(0); };
while xbytes.len() < goalsize { xbytes.insert(0,0) };
while ybytes.len() > goalsize { ybytes.remove(0); };
while ybytes.len() < goalsize { ybytes.insert(0,0) };
target.push(4);
target.append(&mut xbytes);
target.append(&mut ybytes);
let result = ASN1Block::BitString(c, 0, target.len() * 8, target);
Ok(vec![result])
}
}
impl FromASN1 for ECCPubKey<$curve> {
type Error = ECDSADecodeErr;
fn from_asn1(bs: &[ASN1Block]) -> Result<(ECCPubKey<$curve>,&[ASN1Block]),ECDSADecodeErr>
{
let (x, rest) = bs.split_first().ok_or(ECDSADecodeErr::NoKeyFound)?;
if let ASN1Block::BitString(_, _, _, target) = x {
let (hdr, xy_bstr) = target.split_first().ok_or(ECDSADecodeErr::InvalidKeyFormat)?;
if *hdr != 4 {
return Err(ECDSADecodeErr::InvalidKeyFormat);
}
let goalsize = ($curve::size() + 7) / 8;
if xy_bstr.len() != (2 * goalsize) {
return Err(ECDSADecodeErr::InvalidKeyBlockSize);
}
let (xbstr, ybstr) = xy_bstr.split_at(goalsize);
let x = $un::from_bytes(xbstr);
let y = $un::from_bytes(ybstr);
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
let res = ECCPubKey::<$curve>::new(point);
Ok((res, rest))
} else {
Err(ECDSADecodeErr::InvalidKeyFormat)
}
}
}
};
}
public_impl!(P192, U192, I192);
public_impl!(P224, U256, I256);
public_impl!(P256, U256, I256);
public_impl!(P384, U384, I384);
public_impl!(P521, U576, I576);
#[cfg(test)]
use sha2::{Sha224,Sha256,Sha384,Sha512};
#[cfg(test)]
use testing::*;
macro_rules! test_impl {
($name: ident, $curve: ident, $un: ident, $si: 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 _ = $un::from_bytes(dbytes);
let x = $un::from_bytes(xbytes);
let y = $un::from_bytes(ybytes);
let h = $un::from_bytes(hbytes);
let r = $un::from_bytes(rbytes);
let s = $un::from_bytes(sbytes);
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
let public = ECCPubKey::<$curve>::new(point);
let sig = DSASignature::new(r, s);
match usize::from(h) {
224 => assert!(public.verify::<Sha224>(mbytes, &sig)),
256 => assert!(public.verify::<Sha256>(mbytes, &sig)),
384 => assert!(public.verify::<Sha384>(mbytes, &sig)),
512 => assert!(public.verify::<Sha512>(mbytes, &sig)),
x => panic!("Unknown hash algorithm {}", x)
};
});
}
};
}
test_impl!(p192,P192,U192,I192);
test_impl!(p224,P224,U256,I256);
test_impl!(p256,P256,U256,I256);
test_impl!(p384,P384,U384,I384);
test_impl!(p521,P521,U576,I576);

View File

@@ -9,7 +9,9 @@
//! that a new user should use, along with documentation regarding how and
//! when they should use it, and examples. For now, it mostly just fowards
//! off to more detailed modules. Help requested!
extern crate byteorder;
extern crate chrono;
extern crate cryptonum;
extern crate digest;
extern crate hmac;
extern crate num;
@@ -19,28 +21,24 @@ extern crate quickcheck;
extern crate rand;
extern crate sha1;
extern crate sha2;
#[macro_use]
extern crate simple_asn1;
/// The `cryptonum` module provides support for large numbers for use in various
/// cryptographically-relevant algorithms.
pub mod cryptonum;
/// The `rsa` module provides support for RSA-related core algorithms, including
/// signing / verification and encryption / decryption. You can also generate
/// key material there.
/// The `rsa` module provides bare-bones support for RSA signing, verification,
/// encryption, decryption, and key generation.
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.
/// The `dsa` module provides bare-bones support for DSA signing, verification,
/// and key generation. You shouldn't need to use these if you're building a
/// new system, but might need to use them to interact with legacy systems or
/// protocols.
pub mod dsa;
/// The 'ecdsa' module provides support for ECDSA-related signing and
/// verification algorithms, as well as key generation. This and RSA should be
/// your go-to choice for asymmetric crypto.
/// The `ecdsa` module provides bare-bones support for ECDSA signing,
/// verification, and key generation.
pub mod ecdsa;
/// The `x509` module supports parsing and generating x.509 certificates, as
/// used by TLS and others.
pub mod x509;
#[cfg(test)]
mod testing;
#[cfg(test)]
mod test {
}
mod utils;

View File

@@ -1,123 +1,9 @@
use cryptonum::{BarrettUCN,UCN};
use rand::Rng;
use num::bigint::BigUint;
use rsa::errors::RSAError;
use simple_asn1::{ASN1Block,ASN1DecodeErr};
pub static ACCEPTABLE_KEY_SIZES: [(usize,usize); 8] =
[(512, 7),
(1024, 7),
(2048, 4),
(3072, 3),
(4096, 3),
(7680, 3),
(8192, 3),
(15360, 3)];
fn iterations_for_size(l: usize) -> usize {
for &(m, i) in ACCEPTABLE_KEY_SIZES.iter() {
if m == l {
return i;
}
}
panic!("Bad key size, can't get M-R iterations")
}
pub fn generate_pq<G: Rng>(rng: &mut G, e: &UCN, bitlen: usize) -> (UCN, UCN) {
let iterations = iterations_for_size(bitlen);
let sqrt2 = UCN::from(6074001000 as u64);
let topbit = UCN::from(1 as u64) << ((bitlen / 2) - 1);
let minval = sqrt2 << ((bitlen / 2) - 33);
let mindiff = UCN::from(1 as u64) << ((bitlen / 2) - 101);
let validate = |inval| {
let x = &inval | &topbit;
if x < minval {
return None
}
if !gcd_is_one(&e, &x) {
return None
}
Some(x)
};
let p = UCN::generate_prime(rng, bitlen / 2, iterations, validate);
loop {
let q = UCN::generate_prime(rng, bitlen / 2, iterations, validate);
if diff(&p, &q) >= mindiff {
return (p, q);
}
}
}
fn diff(a: &UCN, b: &UCN) -> UCN {
if a > b {
a - b
} else {
b - a
}
}
fn gcd_is_one(a: &UCN, b: &UCN) -> bool {
let mut u = a.clone();
let mut v = b.clone();
if u.is_zero() {
return v == UCN::from(1 as u8);
}
if v.is_zero() {
return u == UCN::from(1 as u8);
}
if u.is_even() && v.is_even() {
return false;
}
while u.is_even() {
u >>= 1;
}
loop {
while v.is_even() {
v >>= 1;
}
// u and v guaranteed to be odd right now.
if u > v {
// make sure that v > u, so that our subtraction works
// out.
let t = u;
u = v;
v = t;
}
v = v - &u;
if v.is_zero() {
return u == UCN::from(1 as u64);
}
}
}
// the RSA encryption function
pub fn ep(nu: &BarrettUCN, e: &UCN, m: &UCN) -> UCN {
m.fastmodexp(e, nu)
}
// the RSA decryption function
pub fn dp(nu: &BarrettUCN, d: &UCN, c: &UCN) -> UCN {
c.fastmodexp(d, nu)
}
// the RSA signature generation function
pub fn sp1(nu: &BarrettUCN, d: &UCN, m: &UCN) -> UCN {
m.fastmodexp(d, nu)
}
// the RSA signature verification function
pub fn vp1(nu: &BarrettUCN, e: &UCN, s: &UCN) -> UCN {
s.fastmodexp(e, nu)
}
// encoding PKCS1 stuff
pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec<u8> {
pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec<u8>
{
let mut idhash = Vec::new();
idhash.extend_from_slice(ident);
idhash.extend_from_slice(hash);
@@ -125,39 +11,38 @@ pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec<u8> {
assert!(keylen > (tlen + 3));
let mut padding = Vec::new();
padding.resize(keylen - tlen - 3, 0xFF);
let mut result = vec![0x00, 0x01];
let mut result = vec![0x00,0x01];
result.append(&mut padding);
result.push(0x00);
result.append(&mut idhash);
result
}
pub fn drop0s(a: &[u8]) -> &[u8] {
let mut idx = 0;
while (idx < a.len()) && (a[idx] == 0) {
idx = idx + 1;
}
&a[idx..]
}
pub fn xor_vecs(a: &Vec<u8>, b: &Vec<u8>) -> Vec<u8> {
a.iter().zip(b.iter()).map(|(a,b)| a^b).collect()
}
#[cfg(test)]
mod tests {
use rand::OsRng;
use super::*;
#[test]
#[ignore]
fn can_get_p_and_q() {
let mut rng = OsRng::new().unwrap();
let e = UCN::from(65537 as u64);
for &(size, _) in ACCEPTABLE_KEY_SIZES.iter().take(3) {
let (p,q) = generate_pq(&mut rng, &e, size);
let minval = UCN::from(1 as u8) << ((size / 2) - 1);
assert!(p > minval);
assert!(q > minval);
assert!(p != q);
assert!(p.is_odd());
assert!(q.is_odd());
let phi = (p - UCN::from(1 as u64)) * (q - UCN::from(1 as u64));
let d = e.modinv(&phi);
assert_eq!( (&e * &d) % phi, UCN::from(1 as u64) );
pub fn decode_biguint(b: &ASN1Block) -> Result<BigUint,RSAError> {
match b {
&ASN1Block::Integer(_, _, ref v) => {
match v.to_biguint() {
Some(sn) => Ok(sn),
_ => Err(RSAError::InvalidKey)
}
}
_ =>
Err(RSAError::ASN1DecodeErr(ASN1DecodeErr::EmptyBuffer))
}
}

View File

@@ -1,16 +1,5 @@
use simple_asn1::ASN1DecodeErr;
use std::io;
#[derive(Debug)]
pub enum RSAKeyGenError {
InvalidKeySize(usize), RngFailure(io::Error)
}
impl From<io::Error> for RSAKeyGenError {
fn from(e: io::Error) -> RSAKeyGenError {
RSAKeyGenError::RngFailure(e)
}
}
use rand;
#[derive(Debug)]
pub enum RSAError {
@@ -19,12 +8,12 @@ pub enum RSAError {
DecryptionError,
DecryptHashMismatch,
InvalidKey,
RandomGenError(io::Error),
RandomGenError(rand::Error),
ASN1DecodeErr(ASN1DecodeErr)
}
impl From<io::Error> for RSAError {
fn from(e: io::Error) -> RSAError {
impl From<rand::Error> for RSAError {
fn from(e: rand::Error) -> RSAError {
RSAError::RandomGenError(e)
}
}

View File

@@ -1,208 +0,0 @@
use rsa::*;
use rsa::oaep::OAEPParams;
use sha1::Sha1;
use sha2::{Sha224,Sha256,Sha384,Sha512};
use testing::run_test;
fn get_signing_hash(s: usize) -> &'static SigningHash {
match s {
0x1 => &SIGNING_HASH_SHA1,
0x224 => &SIGNING_HASH_SHA224,
0x256 => &SIGNING_HASH_SHA256,
0x384 => &SIGNING_HASH_SHA384,
0x512 => &SIGNING_HASH_SHA512,
_ => panic!("Unacceptable hash")
}
}
#[test]
#[ignore]
fn rsa_signing_tests()
{
run_test("tests/rsa/signature.test", 7, |case| {
let (neg0, dbytes) = case.get("d").unwrap();
let (neg1, nbytes) = case.get("n").unwrap();
let (neg2, hbytes) = case.get("h").unwrap();
let (neg3, kbytes) = case.get("k").unwrap();
let (neg4, msg) = case.get("m").unwrap();
let (neg5, sig) = case.get("s").unwrap();
assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4 & !neg5);
let hash = get_signing_hash(usize::from(UCN::from_bytes(hbytes)));
let size = usize::from(UCN::from_bytes(kbytes));
let key = RSAPrivate::new(UCN::from_bytes(nbytes),
UCN::from_bytes(dbytes));
assert!(size % 8 == 0);
assert_eq!(key.byte_len * 8, size);
let sig2 = key.sign(hash, &msg);
assert_eq!(*sig, sig2);
});
}
#[test]
fn rsa_verification_tests()
{
run_test("tests/rsa/signature.test", 7, |case| {
let (neg1, nbytes) = case.get("n").unwrap();
let (neg2, hbytes) = case.get("h").unwrap();
let (neg3, kbytes) = case.get("k").unwrap();
let (neg4, msg) = case.get("m").unwrap();
let (neg5, sig) = case.get("s").unwrap();
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5);
let hash = get_signing_hash(usize::from(UCN::from_bytes(hbytes)));
let size = usize::from(UCN::from_bytes(kbytes));
let key = RSAPublic::new(UCN::from_bytes(nbytes),
UCN::from(65537u64));
assert_eq!(key.byte_len * 8, size);
assert!(key.verify(hash, &msg, sig));
});
}
#[test]
fn rsa_decryption_tests()
{
run_test("tests/rsa/encryption.test", 6, |case| {
let (neg1, dbytes) = case.get("d").unwrap();
let (neg2, nbytes) = case.get("n").unwrap();
let (neg3, hbytes) = case.get("h").unwrap();
let (neg4, lbytes) = case.get("l").unwrap();
let (neg5, msg) = case.get("m").unwrap();
let (neg6, cphtxt) = case.get("c").unwrap();
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5 & !neg6);
let label = String::from_utf8(lbytes.clone()).unwrap();
let key = RSAPrivate::new(UCN::from_bytes(nbytes),
UCN::from_bytes(dbytes));
let wrapped = match usize::from(UCN::from_bytes(hbytes)) {
0x1 => key.decrypt(&OAEPParams::new(Sha1::default(), label),cphtxt),
0x224 => key.decrypt(&OAEPParams::new(Sha224::default(),label),cphtxt),
0x256 => key.decrypt(&OAEPParams::new(Sha256::default(),label),cphtxt),
0x384 => key.decrypt(&OAEPParams::new(Sha384::default(),label),cphtxt),
0x512 => key.decrypt(&OAEPParams::new(Sha512::default(),label),cphtxt),
_ => panic!("Unacceptable hash")
};
let mymsg = wrapped.unwrap();
assert_eq!(msg, &mymsg);
});
}
#[test]
#[ignore]
fn rsa_long_decryption_tests()
{
run_test("tests/rsa/encryption.ext.test", 6, |case| {
let (neg1, dbytes) = case.get("d").unwrap();
let (neg2, nbytes) = case.get("n").unwrap();
let (neg3, hbytes) = case.get("h").unwrap();
let (neg4, lbytes) = case.get("l").unwrap();
let (neg5, msg) = case.get("m").unwrap();
let (neg6, cphtxt) = case.get("c").unwrap();
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5 & !neg6);
let label = String::from_utf8(lbytes.clone()).unwrap();
let key = RSAPrivate::new(UCN::from_bytes(nbytes),
UCN::from_bytes(dbytes));
let wrapped = match usize::from(UCN::from_bytes(hbytes)) {
0x1 => key.decrypt(&OAEPParams::new(Sha1::default(), label),cphtxt),
0x224 => key.decrypt(&OAEPParams::new(Sha224::default(),label),cphtxt),
0x256 => key.decrypt(&OAEPParams::new(Sha256::default(),label),cphtxt),
0x384 => key.decrypt(&OAEPParams::new(Sha384::default(),label),cphtxt),
0x512 => key.decrypt(&OAEPParams::new(Sha512::default(),label),cphtxt),
_ => panic!("Unacceptable hash")
};
let mymsg = wrapped.unwrap();
assert_eq!(msg, &mymsg);
});
}
#[test]
fn rsa_encryption_tests()
{
run_test("tests/rsa/encryption.test", 6, |case| {
let (neg1, dbytes) = case.get("d").unwrap();
let (neg2, nbytes) = case.get("n").unwrap();
let (neg3, hbytes) = case.get("h").unwrap();
let (neg4, lbytes) = case.get("l").unwrap();
let (neg5, msg) = case.get("m").unwrap();
// This one's a little tricky, because there's randomness in the
// encryption phase. So we can't just encrypt and see if we get the
// same value. Instead, we just use this as a test vector to round
// trip, and trust that the decryption test above makes sure we're
// not going off into la la land.
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5);
let label = String::from_utf8(lbytes.clone()).unwrap();
let private = RSAPrivate::new(UCN::from_bytes(nbytes),
UCN::from_bytes(dbytes));
let public = RSAPublic::new(UCN::from_bytes(nbytes),
UCN::from(65537u64));
let wrappedc = match usize::from(UCN::from_bytes(hbytes)) {
0x1 => public.encrypt(&OAEPParams::new(Sha1::default(), label.clone()), &msg),
0x224 => public.encrypt(&OAEPParams::new(Sha224::default(),label.clone()), &msg),
0x256 => public.encrypt(&OAEPParams::new(Sha256::default(),label.clone()), &msg),
0x384 => public.encrypt(&OAEPParams::new(Sha384::default(),label.clone()), &msg),
0x512 => public.encrypt(&OAEPParams::new(Sha512::default(),label.clone()), &msg),
_ => panic!("Unacceptable hash")
};
let ciphertext = wrappedc.unwrap();
let wrappedm = match usize::from(UCN::from_bytes(hbytes)) {
0x1 => private.decrypt(&OAEPParams::new(Sha1::default(), label), &ciphertext),
0x224 => private.decrypt(&OAEPParams::new(Sha224::default(),label), &ciphertext),
0x256 => private.decrypt(&OAEPParams::new(Sha256::default(),label), &ciphertext),
0x384 => private.decrypt(&OAEPParams::new(Sha384::default(),label), &ciphertext),
0x512 => private.decrypt(&OAEPParams::new(Sha512::default(),label), &ciphertext),
_ => panic!("Unacceptable hash")
};
let message = wrappedm.unwrap();
assert_eq!(msg, &message);
});
}
#[test]
#[ignore]
fn rsa_long_encryption_tests()
{
run_test("tests/rsa/encryption.ext.test", 6, |case| {
let (neg1, dbytes) = case.get("d").unwrap();
let (neg2, nbytes) = case.get("n").unwrap();
let (neg3, hbytes) = case.get("h").unwrap();
let (neg4, lbytes) = case.get("l").unwrap();
let (neg5, msg) = case.get("m").unwrap();
// This one's a little tricky, because there's randomness in the
// encryption phase. So we can't just encrypt and see if we get the
// same value. Instead, we just use this as a test vector to round
// trip, and trust that the decryption test above makes sure we're
// not going off into la la land.
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5);
let label = String::from_utf8(lbytes.clone()).unwrap();
let private = RSAPrivate::new(UCN::from_bytes(nbytes),
UCN::from_bytes(dbytes));
let public = RSAPublic::new(UCN::from_bytes(nbytes),
UCN::from(65537u64));
let wrappedc = match usize::from(UCN::from_bytes(hbytes)) {
0x1 => public.encrypt(&OAEPParams::new(Sha1::default(), label.clone()), &msg),
0x224 => public.encrypt(&OAEPParams::new(Sha224::default(),label.clone()), &msg),
0x256 => public.encrypt(&OAEPParams::new(Sha256::default(),label.clone()), &msg),
0x384 => public.encrypt(&OAEPParams::new(Sha384::default(),label.clone()), &msg),
0x512 => public.encrypt(&OAEPParams::new(Sha512::default(),label.clone()), &msg),
_ => panic!("Unacceptable hash")
};
let ciphertext = wrappedc.unwrap();
let wrappedm = match usize::from(UCN::from_bytes(hbytes)) {
0x1 => private.decrypt(&OAEPParams::new(Sha1::default(), label), &ciphertext),
0x224 => private.decrypt(&OAEPParams::new(Sha224::default(),label), &ciphertext),
0x256 => private.decrypt(&OAEPParams::new(Sha256::default(),label), &ciphertext),
0x384 => private.decrypt(&OAEPParams::new(Sha384::default(),label), &ciphertext),
0x512 => private.decrypt(&OAEPParams::new(Sha512::default(),label), &ciphertext),
_ => panic!("Unacceptable hash")
};
let message = wrappedm.unwrap();
assert_eq!(msg, &message);
});
}

View File

@@ -1,109 +1,184 @@
//! A simple RSA library.
//!
//! This library performs all the standard bits and pieces that you'd expect
//! from an RSA library, and does so using only Rust. It's a bit slow at the
//! moment, but it gets the job done.
//!
//! Key generation is supported, using either the native `OsRng` or a random
//! number generator of your choice. Obviously, you should be careful to use
//! a cryptographically-sound random number generator sufficient for the
//! security level you're going for.
//!
//! Signing and verification are via standard PKCS1 padding, but can be
//! adjusted based on the exact hash you want. This library also supports
//! somewhat arbitrary signing mechanisms used by your weirder network
//! protocols. (I'm looking at you, Tor.)
//!
//! Encryption and decryption are via the OAEP mechanism, as described in
//! NIST documents.
//!
mod core;
mod errors;
#[cfg(test)]
mod gold_tests;
mod oaep;
mod public;
mod private;
mod public;
mod signing_hashes;
pub use self::public::RSAPublic;
pub use self::private::RSAPrivate;
pub use self::errors::RSAError;
pub use self::signing_hashes::{SigningHash,
SIGNING_HASH_NULL, SIGNING_HASH_SHA1,
SIGNING_HASH_SHA224, SIGNING_HASH_SHA256,
SIGNING_HASH_SHA384, SIGNING_HASH_SHA512};
SIGNING_HASH_NULL,
SIGNING_HASH_SHA1,
SIGNING_HASH_SHA224,
SIGNING_HASH_SHA256,
SIGNING_HASH_SHA384,
SIGNING_HASH_SHA512};
pub use self::oaep::OAEPParams;
pub use self::private::{RSAPrivate, RSAPrivateKey,
RSA512Private, RSA1024Private, RSA2048Private,
RSA3072Private, RSA4096Private, RSA8192Private,
RSA15360Private};
pub use self::public::{RSAPublic, RSAPublicKey,
RSA512Public, RSA1024Public, RSA2048Public,
RSA3072Public, RSA4096Public, RSA8192Public,
RSA15360Public};
use cryptonum::UCN;
use rand::{OsRng,Rng};
use self::core::{ACCEPTABLE_KEY_SIZES,generate_pq};
use self::errors::*;
use cryptonum::signed::{EGCD,ModInv};
use cryptonum::unsigned::{CryptoNum,PrimeGen};
use cryptonum::unsigned::{U256,U512,U1024,U1536,U2048,U3072,U4096,U7680,U8192,U15360};
use rand::RngCore;
use std::ops::Sub;
#[derive(Clone,Debug)]
pub struct RSAKeyPair {
pub public: RSAPublic,
pub private: RSAPrivate
fn diff<T>(a: &T, b: &T) -> T
where
T: Clone + PartialOrd,
T: Sub<T,Output=T>
{
if a > b {
a.clone() - b.clone()
} else {
b.clone() - a.clone()
}
}
impl RSAKeyPair {
/// Generates a fresh RSA key pair of the given bit size. Valid bit sizes
/// are 512, 1024, 2048, 3072, 4096, 7680, 8192, and 15360. If you
/// actually want to protect data, use a value greater than or equal to
/// 2048. If you don't want to spend all day waiting for RSA computations
/// to finish, choose a value less than or equal to 4096.
///
/// This routine will use `OsRng` for entropy. If you want to use your
/// own random number generator, use `generate_w_rng`.
pub fn generate(len_bits: usize) -> Result<RSAKeyPair,RSAKeyGenError> {
let mut rng = OsRng::new()?;
RSAKeyPair::generate_w_rng(&mut rng, len_bits)
}
/// Generates a fresh RSA key pair of the given bit size. Valid bit sizes
/// are 512, 1024, 2048, 3072, 4096, 7680, 8192, and 15360. If you
/// actually want to protect data, use a value greater than or equal to
/// 2048. If you don't want to spend all day waiting for RSA computations
/// to finish, choose a value less than or equal to 4096.
///
/// If you provide your own random number generator that is not `OsRng`,
/// you should know what you're doing, and be using a cryptographically-
/// strong RNG of your own choosing. We've warned you. Use a good one.
/// So now it's on you.
pub fn generate_w_rng<G: Rng>(rng: &mut G, len_bits: usize)
-> Result<RSAKeyPair,RSAKeyGenError>
{
let e = UCN::from(65537 as u32);
for &(length, _) in ACCEPTABLE_KEY_SIZES.iter() {
if length == len_bits {
let (p, q) = generate_pq(rng, &e, len_bits);
let n = &p * &q;
let one = UCN::from(1 as u8);
let phi = (p - &one) * (q - &one);
let d = e.modinv(&phi);
let public_key = RSAPublic::new(n.clone(), e);
let private_key = RSAPrivate::new(n, d);
return Ok(RSAKeyPair{
private: private_key,
public: public_key
})
}
macro_rules! generate_rsa_pair
{
($pair: ident, $pub: ident, $priv: ident, $uint: ident, $half: ident, $iterations: expr) => {
pub struct $pair {
pub public: $pub,
pub private: $priv
}
Err(RSAKeyGenError::InvalidKeySize(len_bits))
}
impl $pair {
pub fn new(pu: $pub, pr: $priv) -> $pair {
$pair {
public: pu,
private: pr
}
}
pub fn generate<G>(rng: &mut G) -> $pair
where G: RngCore
{
loop {
let ebase = 65537u32;
let e = $uint::from(ebase);
let (p, q) = $pair::generate_pq(rng, &$half::from(ebase));
let one = $half::from(1u32);
let pminus1 = &p - &one;
let qminus1 = &q - &one;
let phi = pminus1 * qminus1;
let n = &p * &q;
if let Some(d) = e.modinv(&phi) {
let public = $pub::new(n.clone(), e);
let private = $priv::new(n, d);
return $pair::new(public, private);
}
}
}
fn generate_pq<G>(rng: &mut G, e: &$half) -> ($half, $half)
where G: RngCore
{
let sqrt2_32 = 6074001000u64;
let half_bitlen = $half::bit_length();
let minval = $half::from(sqrt2_32) << (half_bitlen - 33);
let mindiff = $half::from(1u64) << (half_bitlen - 101);
let p = $half::random_primef(rng, $iterations, |x| {
if (x >= minval) && x.gcd_is_one(e) {
Some(x)
} else {
None
}
});
loop {
let q = $half::random_primef(rng, $iterations, |x| {
if (x >= minval) && x.gcd_is_one(e) {
Some(x)
} else {
None
}
});
if diff(&p, &q) >= mindiff {
return (p, q);
}
}
}
}
}
}
generate_rsa_pair!(RSA512KeyPair, RSA512Public, RSA512Private, U512, U256, 7);
generate_rsa_pair!(RSA1024KeyPair, RSA1024Public, RSA1024Private, U1024, U512, 7);
generate_rsa_pair!(RSA2048KeyPair, RSA2048Public, RSA2048Private, U2048, U1024, 4);
generate_rsa_pair!(RSA3072KeyPair, RSA3072Public, RSA3072Private, U3072, U1536, 3);
generate_rsa_pair!(RSA4096KeyPair, RSA4096Public, RSA4096Private, U4096, U2048, 3);
generate_rsa_pair!(RSA8192KeyPair, RSA8192Public, RSA8192Private, U8192, U4096, 3);
generate_rsa_pair!(RSA15360KeyPair, RSA15360Public, RSA15360Private, U15360, U7680, 3);
#[cfg(test)]
mod tests {
mod generation {
use quickcheck::{Arbitrary,Gen};
use rsa::core::{ep,dp,sp1,vp1};
use std::fmt;
use super::*;
const TEST_KEY_SIZES: [usize; 2] = [512, 1024];
impl Clone for RSA512KeyPair {
fn clone(&self) -> RSA512KeyPair {
RSA512KeyPair{
public: RSA512Public {
n: self.public.n.clone(),
nu: self.public.nu.clone(),
e: self.public.e.clone(),
},
private: RSA512Private {
nu: self.private.nu.clone(),
d: self.private.d.clone()
}
}
}
}
impl Arbitrary for RSAKeyPair {
fn arbitrary<G: Gen>(g: &mut G) -> RSAKeyPair {
let size = g.choose(&TEST_KEY_SIZES).unwrap();
RSAKeyPair::generate_w_rng(g, *size).unwrap()
impl fmt::Debug for RSA512KeyPair {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RSA512KeyPair")
.field("n", &self.public.n)
.field("e", &self.public.e)
.field("d", &self.private.d)
.finish()
}
}
impl Arbitrary for RSA512KeyPair {
fn arbitrary<G: Gen>(g: &mut G) -> RSA512KeyPair {
RSA512KeyPair::generate(g)
}
}
quickcheck! {
#[ignore]
fn rsa_ep_dp_inversion(kp: RSAKeyPair, n: UCN) -> bool {
let m = n.reduce(&kp.public.nu);
let ciphertext = ep(&kp.public.nu, &kp.public.e, &m);
let mprime = dp(&kp.private.nu, &kp.private.d, &ciphertext);
mprime == m
}
#[ignore]
fn rsa_sp_vp_inversion(kp: RSAKeyPair, n: UCN) -> bool {
let m = n.reduce(&kp.public.nu);
let sig = sp1(&kp.private.nu, &kp.private.d, &m);
let mprime = vp1(&kp.public.nu, &kp.public.e, &sig);
mprime == m
fn generate_and_sign(keypair: RSA512KeyPair, msg: Vec<u8>) -> bool {
let sig = keypair.private.sign(&SIGNING_HASH_SHA256, &msg);
keypair.public.verify(&SIGNING_HASH_SHA256, &msg, &sig)
}
}
}

View File

@@ -1,44 +1,43 @@
use cryptonum::UCN;
use digest::{FixedOutput,Input};
use byteorder::{BigEndian,ByteOrder};
use digest::{Digest,FixedOutput};
use std::marker::PhantomData;
/// Parameters for OAEP encryption and decryption: a hash function to use as part of the message
/// generation function (MGF1, if you're curious), and any labels you want to include as part of
/// the encryption.
pub struct OAEPParams<H: Clone + Input + FixedOutput> {
pub hash: H,
pub label: String
/// Parameters for OAEP encryption and decryption: a hash function to use as
/// part of the message generation function (MGF1, if you're curious),
/// and any labels you want to include as part of the encryption.
pub struct OAEPParams<H: Default + Digest + FixedOutput> {
pub label: String,
phantom: PhantomData<H>
}
impl<H: Clone + Input + FixedOutput> OAEPParams<H> {
pub fn new(hash: H, label: String)
impl<H: Default + Digest + FixedOutput> OAEPParams<H> {
pub fn new(label: String)
-> OAEPParams<H>
{
OAEPParams { hash: hash, label: label }
OAEPParams { label: label, phantom: PhantomData }
}
pub fn hash_len(&self) -> usize {
self.hash.clone().fixed_result().as_slice().len()
H::default().fixed_result().as_slice().len()
}
pub fn hash(&self, input: &[u8]) -> Vec<u8> {
let mut digest = self.hash.clone();
digest.process(input);
digest.fixed_result().as_slice().to_vec()
H::digest(input).as_slice().to_vec()
}
pub fn mgf1(&self, input: &[u8], len: usize) -> Vec<u8> {
let mut res = Vec::with_capacity(len);
let mut counter = UCN::from(0u64);
let one = UCN::from(1u64);
let mut counter = 0u32;
while res.len() < len {
let c = counter.to_bytes(4);
let mut digest = self.hash.clone();
digest.process(input);
digest.process(&c);
let mut buffer = [0; 4];
BigEndian::write_u32(&mut buffer, counter);
let mut digest = H::default();
digest.input(input);
digest.input(&buffer);
let chunk = digest.fixed_result();
res.extend_from_slice(chunk.as_slice());
counter = counter + &one;
counter = counter + 1;
}
res.truncate(len);

View File

@@ -1,149 +1,273 @@
use cryptonum::{BarrettUCN,UCN};
use digest::{FixedOutput,Input};
use rsa::core::{ACCEPTABLE_KEY_SIZES,dp,pkcs1_pad,sp1,xor_vecs};
use cryptonum::unsigned::*;
use digest::{Digest,FixedOutput};
use rsa::core::{drop0s,pkcs1_pad,xor_vecs};
use rsa::errors::RSAError;
use rsa::oaep::OAEPParams;
use rsa::signing_hashes::SigningHash;
use std::fmt;
#[derive(Clone)]
pub struct RSAPrivate {
pub(crate) byte_len: usize,
pub(crate) n: UCN,
pub(crate) nu: BarrettUCN,
pub(crate) d: UCN
pub trait RSAPrivateKey<N> {
/// Generate a new private key using the given modulus and private
/// exponent. You probably don't want to use this function directly
/// unless you're writing your own key generation routine or key
/// parsing library.
fn new(n: N, d: N) -> Self;
/// Sign the given message with the given private key.
fn sign(&self, signhash: &SigningHash, msg: &[u8]) -> Vec<u8>;
/// Decrypt the provided message using the given OAEP parameters. As
/// mentioned in the comment for encryption, RSA decryption is really,
/// really slow. So if your plaintext is larger than about half the
/// bit size of the key, it's almost certainly a better idea to generate
/// a fresh symmetric encryption key, encrypt only the key with RSA, and
/// then encrypt the message with that key.
fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where H: Default + Digest + FixedOutput;
}
#[cfg(test)]
impl fmt::Debug for RSAPrivate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RSAPrivate")
.field("byte_len", &self.byte_len)
.field("n", &self.n)
.field("nu", &self.nu)
.field("d", &self.d)
.finish()
}
pub enum RSAPrivate {
Key512(RSA512Private),
Key1024(RSA1024Private),
Key2048(RSA2048Private),
Key3072(RSA3072Private),
Key4096(RSA4096Private),
Key8192(RSA8192Private),
Key15360(RSA15360Private)
}
#[cfg(test)]
impl PartialEq for RSAPrivate {
fn eq(&self, rhs: &RSAPrivate) -> bool {
(self.byte_len == rhs.byte_len) &&
(self.n == rhs.n) &&
(self.nu == rhs.nu) &&
(self.d == rhs.d)
}
}
// fn print_vector(name: &'static str, bytes: &[u8])
// {
// print!("{}: (length {}) ", name, bytes.len());
// for x in bytes.iter() {
// print!("{:02X}", *x);
// }
// println!("");
// }
#[cfg(test)]
impl Eq for RSAPrivate {}
macro_rules! generate_rsa_private
{
($rsa: ident, $num: ident, $bar: ident, $size: expr) => {
pub struct $rsa {
pub(crate) nu: $bar,
pub(crate) d: $num
}
#[cfg(not(test))]
impl fmt::Debug for RSAPrivate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("RSAPrivateKey<PRIVATE>")
}
}
impl RSAPrivateKey<$num> for $rsa {
fn new(n: $num, d: $num) -> $rsa {
let nu = $bar::new(n.clone());
$rsa { nu: nu, d: d }
}
impl RSAPrivate {
/// Create a new RSA public key from the given components, which you found
/// via some other mechanism.
pub fn new(n: UCN, d: UCN) -> RSAPrivate {
let len = n.bits();
fn sign(&self, signhash: &SigningHash, msg: &[u8])
-> Vec<u8>
{
let hash = (signhash.run)(msg);
let em = pkcs1_pad(&signhash.ident, &hash, $size/8);
let m = $num::from_bytes(&em);
let s = self.sp1(&m);
let sig = s.to_bytes();
sig
}
for &(valid_bits, _) in ACCEPTABLE_KEY_SIZES.iter() {
if valid_bits >= len {
return RSAPrivate {
byte_len: valid_bits / 8,
n: n.clone(),
nu: n.barrett_u(),
d: d.clone()
};
fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where H: Default + Digest + FixedOutput
{
let mut res = Vec::new();
for chunk in msg.chunks($size/8) {
let mut dchunk = self.oaep_decrypt(oaep, chunk)?;
res.append(&mut dchunk);
}
Ok(res)
}
}
panic!("Invalid RSA key size in new()")
}
/// Sign a message using the given hash.
pub fn sign(&self, sighash: &SigningHash, msg: &[u8]) -> Vec<u8> {
let hash = (sighash.run)(msg);
let em = pkcs1_pad(&sighash.ident, &hash, self.byte_len);
let m = UCN::from_bytes(&em);
let s = sp1(&self.nu, &self.d, &m);
let sig = s.to_bytes(self.byte_len);
sig
}
impl $rsa {
fn sp1(&self, m: &$num) -> $num {
m.modexp(&self.d, &self.nu)
}
/// Decrypt a message with the given parameters.
pub fn decrypt<H: Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
{
let mut res = Vec::new();
fn dp(&self, c: &$num) -> $num {
c.modexp(&self.d, &self.nu)
}
for chunk in msg.chunks(self.byte_len) {
let mut dchunk = self.oaep_decrypt(oaep, chunk)?;
res.append(&mut dchunk);
}
fn oaep_decrypt<H>(&self, oaep: &OAEPParams<H>, c: &[u8])
-> Result<Vec<u8>,RSAError>
where
H: Default + Digest + FixedOutput
{
let byte_len = $size / 8;
// Step 1b
if c.len() != byte_len {
return Err(RSAError::DecryptionError);
}
// Step 1c
if byte_len < ((2 * oaep.hash_len()) + 2) {
return Err(RSAError::DecryptHashMismatch);
}
// Step 2a
let c_ip = $num::from_bytes(&c);
// Step 2b
let m_ip = self.dp(&c_ip);
// Step 2c
let em = m_ip.to_bytes();
// Step 3a
let l_hash = oaep.hash(oaep.label.as_bytes());
// Step 3b
let (y, rest) = em.split_at(1);
let (masked_seed, masked_db) = rest.split_at(oaep.hash_len());
// Step 3c
let seed_mask = oaep.mgf1(masked_db, oaep.hash_len());
// Step 3d
let seed = xor_vecs(&masked_seed.to_vec(), &seed_mask);
// Step 3e
let db_mask = oaep.mgf1(&seed, byte_len - oaep.hash_len() - 1);
// Step 3f
let db = xor_vecs(&masked_db.to_vec(), &db_mask);
// Step 3g
let (l_hash2, ps_o_m) = db.split_at(oaep.hash_len());
let o_m = drop0s(ps_o_m);
let (o, m) = o_m.split_at(1);
// Checks!
if o != [1] {
return Err(RSAError::DecryptionError);
}
if l_hash != l_hash2 {
return Err(RSAError::DecryptionError);
}
if y != [0] {
return Err(RSAError::DecryptionError);
}
Ok(res)
}
fn oaep_decrypt<H: Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, c: &[u8])
-> Result<Vec<u8>,RSAError>
{
// Step 1b
if c.len() != self.byte_len {
return Err(RSAError::DecryptionError);
Ok(m.to_vec())
}
}
// Step 1c
if self.byte_len < ((2 * oaep.hash_len()) + 2) {
return Err(RSAError::DecryptHashMismatch);
}
// Step 2a
let c_ip = UCN::from_bytes(&c.to_vec());
// Step 2b
let m_ip = dp(&self.nu, &self.d, &c_ip);
// Step 2c
let em = &m_ip.to_bytes(self.byte_len);
// Step 3a
let l_hash = oaep.hash(oaep.label.as_bytes());
// Step 3b
let (y, rest) = em.split_at(1);
let (masked_seed, masked_db) = rest.split_at(oaep.hash_len());
// Step 3c
let seed_mask = oaep.mgf1(masked_db, oaep.hash_len());
// Step 3d
let seed = xor_vecs(&masked_seed.to_vec(), &seed_mask);
// Step 3e
let db_mask = oaep.mgf1(&seed, self.byte_len - oaep.hash_len() - 1);
// Step 3f
let db = xor_vecs(&masked_db.to_vec(), &db_mask);
// Step 3g
let (l_hash2, ps_o_m) = db.split_at(oaep.hash_len());
let o_m = drop0s(ps_o_m);
let (o, m) = o_m.split_at(1);
// Checks!
if o != [1] {
return Err(RSAError::DecryptionError);
}
if l_hash != l_hash2 {
return Err(RSAError::DecryptionError);
}
if y != [0] {
return Err(RSAError::DecryptionError);
}
Ok(m.to_vec())
}
}
fn drop0s(a: &[u8]) -> &[u8] {
let mut idx = 0;
generate_rsa_private!(RSA512Private, U512, BarrettU512, 512);
generate_rsa_private!(RSA1024Private, U1024, BarrettU1024, 1024);
generate_rsa_private!(RSA2048Private, U2048, BarrettU2048, 2048);
generate_rsa_private!(RSA3072Private, U3072, BarrettU3072, 3072);
generate_rsa_private!(RSA4096Private, U4096, BarrettU4096, 4096);
generate_rsa_private!(RSA8192Private, U8192, BarrettU8192, 8192);
generate_rsa_private!(RSA15360Private, U15360, BarrettU15360, 15360);
while (idx < a.len()) && (a[idx] == 0) {
idx = idx + 1;
macro_rules! generate_tests {
( $( ($mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) ),* ) => {
$(
#[cfg(test)]
#[allow(non_snake_case)]
mod $mod {
use cryptonum::unsigned::Decoder;
use super::*;
use testing::run_test;
use rsa::signing_hashes::*;
use sha1::Sha1;
use sha2::{Sha224,Sha256,Sha384,Sha512};
#[test]
fn sign() {
let fname = format!("tests/rsa/rsa{}.test", $size);
run_test(fname.to_string(), 8, |case| {
let (neg0, dbytes) = case.get("d").unwrap();
let (neg1, nbytes) = case.get("n").unwrap();
let (neg2, hbytes) = case.get("h").unwrap();
let (neg3, mbytes) = case.get("m").unwrap();
let (neg4, sbytes) = case.get("s").unwrap();
let (neg5, ubytes) = case.get("u").unwrap();
let (neg6, kbytes) = case.get("k").unwrap();
assert!(!neg0&&!neg1&&!neg2&&!neg3&&!neg4&&!neg5&&!neg6);
let n = $num64::from_bytes(nbytes);
let nu = $num64::from_bytes(ubytes);
let bigk = $num::from_bytes(kbytes);
let k = usize::from(bigk);
let d = $num::from_bytes(dbytes);
let privkey = $rsa{ nu: $bar::from_components(k, n, nu), d: d };
let hashnum = ((hbytes[0] as u16)<<8) + (hbytes[1] as u16);
let sighash = match hashnum {
0x160 => &SIGNING_HASH_SHA1,
0x224 => &SIGNING_HASH_SHA224,
0x256 => &SIGNING_HASH_SHA256,
0x384 => &SIGNING_HASH_SHA384,
0x512 => &SIGNING_HASH_SHA512,
_ => panic!("Bad signing hash: {}", hashnum)
};
let sig = privkey.sign(sighash, &mbytes);
assert_eq!(sig, *sbytes);
});
}
#[test]
fn decrypt() {
let fname = format!("tests/rsa/rsa{}.test", $size);
run_test(fname.to_string(), 8, |case| {
let (neg0, dbytes) = case.get("d").unwrap();
let (neg1, nbytes) = case.get("n").unwrap();
let (neg2, hbytes) = case.get("h").unwrap();
let (neg3, mbytes) = case.get("m").unwrap();
let (neg4, cbytes) = case.get("c").unwrap();
let (neg5, ubytes) = case.get("u").unwrap();
let (neg6, kbytes) = case.get("k").unwrap();
assert!(!neg0&&!neg1&&!neg2&&!neg3&&!neg4&&!neg5&&!neg6);
let n = $num64::from_bytes(nbytes);
let nu = $num64::from_bytes(ubytes);
let bigk = $num::from_bytes(kbytes);
let k = usize::from(bigk);
let d = $num::from_bytes(dbytes);
let privkey = $rsa{ nu: $bar::from_components(k, n, nu), d: d };
let hashnum = ((hbytes[0] as u16)<<8) + (hbytes[1] as u16);
let empty = "".to_string();
match hashnum {
0x160 => {
let oaep = OAEPParams::<Sha1>::new(empty);
let plain = privkey.decrypt(&oaep, &cbytes);
assert!(plain.is_ok());
assert_eq!(*mbytes, plain.unwrap());
}
0x224 =>{
let oaep = OAEPParams::<Sha224>::new(empty);
let plain = privkey.decrypt(&oaep, &cbytes);
assert!(plain.is_ok());
assert_eq!(*mbytes, plain.unwrap());
}
0x256 => {
let oaep = OAEPParams::<Sha256>::new(empty);
let plain = privkey.decrypt(&oaep, &cbytes);
assert!(plain.is_ok());
assert_eq!(*mbytes, plain.unwrap());
}
0x384 => {
let oaep = OAEPParams::<Sha384>::new(empty);
let plain = privkey.decrypt(&oaep, &cbytes);
assert!(plain.is_ok());
assert_eq!(*mbytes, plain.unwrap());
}
0x512 => {
let oaep = OAEPParams::<Sha512>::new(empty);
let plain = privkey.decrypt(&oaep, &cbytes);
assert!(plain.is_ok());
assert_eq!(*mbytes, plain.unwrap());
}
_ => panic!("Bad signing hash: {}", hashnum)
};
});
}
}
)*
}
&a[idx..]
}
generate_tests!( (RSA512, RSA512Private, U512, BarrettU512, U576, 512),
(RSA1024, RSA1024Private, U1024, BarrettU1024, U1088, 1024),
(RSA2048, RSA2048Private, U2048, BarrettU2048, U2112, 2048)
// (RSA3072, RSA3072Private, U3072, BarrettU3072, U3136, 3072),
// (RSA4096, RSA4096Private, U4096, BarrettU4096, U4160, 4096),
// (RSA8192, RSA8192Private, U8192, BarrettU8192, U8256, 8192),
// (RSA15360, RSA15360Private, U15360, BarrettU15360, U15424, 15360)
);

View File

@@ -1,124 +1,457 @@
use cryptonum::{BarrettUCN,UCN};
use digest::{FixedOutput,Input};
use rand::{OsRng,Rng};
use rsa::core::{ACCEPTABLE_KEY_SIZES,ep,pkcs1_pad,vp1,xor_vecs};
use cryptonum::unsigned::*;
use digest::{Digest,FixedOutput};
use rand::Rng;
use rand::rngs::OsRng;
use rsa::core::{decode_biguint,pkcs1_pad,xor_vecs};
use rsa::errors::RSAError;
use rsa::oaep::OAEPParams;
use rsa::signing_hashes::SigningHash;
use simple_asn1::{ASN1Block,ASN1DecodeErr,ASN1EncodeErr,
ASN1Class,FromASN1,ToASN1};
#[cfg(test)]
use std::fmt;
use utils::TranslateNums;
#[derive(Clone,Debug,PartialEq,Eq)]
pub struct RSAPublic {
pub(crate) byte_len: usize,
pub(crate) n: UCN,
pub(crate) nu: BarrettUCN,
pub(crate) e: UCN
pub trait RSAPublicKey<N> {
/// Generate a new public key pair for the given modulus and
/// exponent. You should probably not call this directly unless
/// you're writing a key generation function or writing your own
/// public key parser.
fn new(n: N, e: N) -> Self;
/// Verify that the provided signature is valid; that the private
/// key associated with this public key sent exactly this message.
/// The hash used here must exactly match the hash used to sign
/// the message, including its ASN.1 metadata.
fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool;
/// Encrypt the message with a hash function, given the appropriate
/// label. Please note that RSA encryption is not particularly fast,
/// and decryption is very slow indeed. Thus, most crypto systems that
/// need asymmetric encryption should generate a symmetric key, encrypt
/// that key with RSA encryption, and then encrypt the actual message
/// with that symmetric key.
///
/// In this variant of the function, we use an explicit random number
/// generator, just in case you have one you really like. It better be
/// cryptographically strong, though, as some of the padding protections
/// are relying on it.
fn encrypt_rng<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where
G: Rng,
H: Default + Digest + FixedOutput;
/// Encrypt the message with a hash function, given the appropriate
/// label. Please note that RSA encryption is not particularly fast,
/// and decryption is very slow indeed. Thus, most crypto systems that
/// need asymmetric encryption should generate a symmetric key, encrypt
/// that key with RSA encryption, and then encrypt the actual message
/// with that symmetric key.
///
/// This variant will just use the system RNG for its randomness.
fn encrypt<H>(&self,oaep:&OAEPParams<H>,msg:&[u8])
-> Result<Vec<u8>,RSAError>
where
H: Default + Digest + FixedOutput
{
let mut g = OsRng::new()?;
self.encrypt_rng(&mut g, oaep, msg)
}
}
pub enum RSAPublic {
Key512(RSA512Public),
Key1024(RSA1024Public),
Key2048(RSA2048Public),
Key3072(RSA3072Public),
Key4096(RSA4096Public),
Key8192(RSA8192Public),
Key15360(RSA15360Public)
}
impl RSAPublic {
/// Create a new RSA public key from the given components, which you found
/// via some other mechanism.
pub fn new(n: UCN, e: UCN) -> RSAPublic {
let len = n.bits();
for &(valid_bits, _) in ACCEPTABLE_KEY_SIZES.iter() {
if valid_bits >= len {
return RSAPublic{
byte_len: valid_bits / 8,
n: n.clone(),
nu: n.barrett_u(),
e: e.clone()
};
}
}
panic!("Invalid RSA key size in new()")
}
/// Verify the signature for a given message, using the given signing hash,
/// returning true iff the signature validates.
pub fn verify(&self, shash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool {
let hash = (shash.run)(msg);
let s = UCN::from_bytes(&sig);
let m = vp1(&self.nu, &self.e, &s);
let em = m.to_bytes(self.byte_len);
let em_ = pkcs1_pad(&shash.ident, &hash, self.byte_len);
(em == em_)
}
/// Encrypt the given data with the public key and parameters, returning
/// the encrypted blob or an error encountered during encryption.
///
/// OAEP encoding is used for this process, which requires a random number
/// generator. This version of the function uses `OsRng`. If you want to
/// use your own RNG, use `encrypt_w_rng`.
pub fn encrypt<H:Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool
{
let mut g = OsRng::new()?;
self.encrypt_with_rng(&mut g, oaep, msg)
}
/// Encrypt the given data with the public key and parameters, returning
/// the encrypted blob or an error encountered during encryption. This
/// version also allows you to provide your own RNG, if you really feel
/// like shooting yourself in the foot.
pub fn encrypt_with_rng<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where G: Rng, H: Clone + Input + FixedOutput
{
if self.byte_len <= ((2 * oaep.hash_len()) + 2) {
return Err(RSAError::KeyTooSmallForHash);
match self {
RSAPublic::Key512(x) => x.verify(signhash, msg, sig),
RSAPublic::Key1024(x) => x.verify(signhash, msg, sig),
RSAPublic::Key2048(x) => x.verify(signhash, msg, sig),
RSAPublic::Key3072(x) => x.verify(signhash, msg, sig),
RSAPublic::Key4096(x) => x.verify(signhash, msg, sig),
RSAPublic::Key8192(x) => x.verify(signhash, msg, sig),
RSAPublic::Key15360(x) => x.verify(signhash, msg, sig)
}
let mut res = Vec::new();
for chunk in msg.chunks(self.byte_len - (2 * oaep.hash_len()) - 2) {
let mut newchunk = self.oaep_encrypt(g, oaep, chunk)?;
res.append(&mut newchunk)
}
Ok(res)
}
fn oaep_encrypt<G: Rng,H:Clone + Input + FixedOutput>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
{
// Step 1b
if msg.len() > (self.byte_len - (2 * oaep.hash_len()) - 2) {
return Err(RSAError::BadMessageSize)
}
// Step 2a
let mut lhash = oaep.hash(oaep.label.as_bytes());
// Step 2b
let num0s = self.byte_len - msg.len() - (2 * oaep.hash_len()) - 2;
let mut ps = Vec::new();
ps.resize(num0s, 0);
// Step 2c
let mut db = Vec::new();
db.append(&mut lhash);
db.append(&mut ps);
db.push(1);
db.extend_from_slice(msg);
// Step 2d
let seed : Vec<u8> = g.gen_iter().take(oaep.hash_len()).collect();
// Step 2e
let db_mask = oaep.mgf1(&seed, self.byte_len - oaep.hash_len() - 1);
// Step 2f
let mut masked_db = xor_vecs(&db, &db_mask);
// Step 2g
let seed_mask = oaep.mgf1(&masked_db, oaep.hash_len());
// Step 2h
let mut masked_seed = xor_vecs(&seed, &seed_mask);
// Step 2i
let mut em = Vec::new();
em.push(0);
em.append(&mut masked_seed);
em.append(&mut masked_db);
// Step 3a
let m_i = UCN::from_bytes(&em);
// Step 3b
let c_i = ep(&self.nu, &self.e, &m_i);
// Step 3c
let c = c_i.to_bytes(self.byte_len);
Ok(c)
}
}
impl FromASN1 for RSAPublic {
type Error = RSAError;
fn from_asn1(bs: &[ASN1Block])
-> Result<(RSAPublic,&[ASN1Block]),RSAError>
{
match bs.split_first() {
None =>
Err(RSAError::ASN1DecodeErr(ASN1DecodeErr::EmptyBuffer)),
Some((&ASN1Block::Sequence(_, _, ref items), rest))
if items.len() == 2 =>
{
let n = decode_biguint(&items[0])?;
let e = decode_biguint(&items[1])?;
let nsize = n.bits();
let mut rsa_size = 512;
println!("n': {:X}", n);
println!("nsize: {}", nsize);
while rsa_size < nsize {
rsa_size = rsa_size + 256;
}
match rsa_size {
512 => {
let n2 = U512::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U512::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSA512Public::new(n2, e2);
Ok((RSAPublic::Key512(res), rest))
}
1024 => {
let n2 = U1024::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U1024::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSA1024Public::new(n2, e2);
Ok((RSAPublic::Key1024(res), rest))
}
2048 => {
let n2 = U2048::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U2048::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSA2048Public::new(n2, e2);
Ok((RSAPublic::Key2048(res), rest))
}
3072 => {
let n2 = U3072::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U3072::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSA3072Public::new(n2, e2);
Ok((RSAPublic::Key3072(res), rest))
}
4096 => {
let n2 = U4096::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U4096::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSA4096Public::new(n2, e2);
Ok((RSAPublic::Key4096(res), rest))
}
8192 => {
let n2 = U8192::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U8192::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSA8192Public::new(n2, e2);
Ok((RSAPublic::Key8192(res), rest))
}
15360 => {
let n2 = U15360::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U15360::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSA15360Public::new(n2, e2);
Ok((RSAPublic::Key15360(res), rest))
}
_ =>
Err(RSAError::InvalidKey)
}
}
Some(_) =>
Err(RSAError::InvalidKey)
}
}
}
impl ToASN1 for RSAPublic {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,Self::Error>
{
match self {
RSAPublic::Key512(x) => x.to_asn1_class(c),
RSAPublic::Key1024(x) => x.to_asn1_class(c),
RSAPublic::Key2048(x) => x.to_asn1_class(c),
RSAPublic::Key3072(x) => x.to_asn1_class(c),
RSAPublic::Key4096(x) => x.to_asn1_class(c),
RSAPublic::Key8192(x) => x.to_asn1_class(c),
RSAPublic::Key15360(x) => x.to_asn1_class(c)
}
}
}
// fn print_vector(name: &'static str, bytes: &[u8])
// {
// print!("{}: (length {}) ", name, bytes.len());
// for x in bytes.iter() {
// print!("{:02X}", *x);
// }
// println!("");
// }
macro_rules! generate_rsa_public
{
($rsa: ident, $num: ident, $bar: ident, $var: ident, $size: expr) => {
#[derive(PartialEq)]
pub struct $rsa {
pub(crate) n: $num,
pub(crate) nu: $bar,
pub(crate) e: $num
}
impl RSAPublicKey<$num> for $rsa {
fn new(n: $num, e: $num) -> $rsa {
let nu = $bar::new(n.clone());
$rsa { n: n, nu: nu, e: e }
}
fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8])
-> bool
{
let hash: Vec<u8> = (signhash.run)(msg);
let s = $num::from_bytes(&sig);
let m = self.vp1(&s);
let em = m.to_bytes();
let em_ = pkcs1_pad(signhash.ident, &hash, $size/8);
em == em_
}
fn encrypt_rng<G,H>(&self,g: &mut G,oaep: &OAEPParams<H>,msg: &[u8])
-> Result<Vec<u8>,RSAError>
where
G: Rng,
H: Default + Digest + FixedOutput
{
let byte_len = $size / 8;
let mut res = Vec::new();
if byte_len <= ((2 * oaep.hash_len()) + 2) {
return Err(RSAError::KeyTooSmallForHash);
}
for chunk in msg.chunks(byte_len - (2 * oaep.hash_len()) - 2) {
let mut newchunk = self.oaep_encrypt(g, oaep, chunk)?;
res.append(&mut newchunk);
}
Ok(res)
}
}
impl $rsa {
fn vp1(&self, s: &$num) -> $num {
s.modexp(&self.e, &self.nu)
}
fn ep(&self, m: &$num) -> $num {
m.modexp(&self.e, &self.nu)
}
fn oaep_encrypt<G,H>(&self,g: &mut G,oaep: &OAEPParams<H>,m: &[u8])
-> Result<Vec<u8>,RSAError>
where
G: Rng,
H: Default + Digest + FixedOutput
{
let byte_len = $size / 8;
// Step 1b
if m.len() > (byte_len - (2 * oaep.hash_len()) - 2) {
return Err(RSAError::BadMessageSize)
}
// Step 2a
let mut lhash = oaep.hash(oaep.label.as_bytes());
// Step 2b
let num0s = byte_len - m.len() - (2 * oaep.hash_len()) - 2;
let mut ps = Vec::new();
ps.resize(num0s, 0);
// Step 2c
let mut db = Vec::new();
db.append(&mut lhash);
db.append(&mut ps);
db.push(1);
db.extend_from_slice(m);
// Step 2d
let mut seed: Vec<u8> = Vec::with_capacity(oaep.hash_len());
seed.resize(oaep.hash_len(), 0);
g.fill(seed.as_mut_slice());
// Step 2e
let db_mask = oaep.mgf1(&seed, byte_len - oaep.hash_len() - 1);
// Step 2f
let mut masked_db = xor_vecs(&db, &db_mask);
// Step 2g
let seed_mask = oaep.mgf1(&masked_db, oaep.hash_len());
// Step 2h
let mut masked_seed = xor_vecs(&seed, &seed_mask);
// Step 2i
let mut em = Vec::new();
em.push(0);
em.append(&mut masked_seed);
em.append(&mut masked_db);
// Step 3a
let m_i = $num::from_bytes(&em);
// Step 3b
let c_i = self.ep(&m_i);
// Step 3c
let c = c_i.to_bytes();
Ok(c)
}
}
impl FromASN1 for $rsa {
type Error = RSAError;
fn from_asn1(bs: &[ASN1Block])
-> Result<($rsa,&[ASN1Block]),RSAError>
{
let (core, rest) = RSAPublic::from_asn1(bs)?;
match core {
RSAPublic::$var(x) => Ok((x, rest)),
_ => Err(RSAError::InvalidKey)
}
}
}
impl ToASN1 for $rsa {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,Self::Error>
{
let n = self.n.to_num();
let e = self.e.to_num();
let enc_n = ASN1Block::Integer(c, 0, n);
let enc_e = ASN1Block::Integer(c, 0, e);
let seq = ASN1Block::Sequence(c, 0, vec![enc_n, enc_e]);
Ok(vec![seq])
}
}
#[cfg(test)]
impl fmt::Debug for $rsa {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct(stringify!($rsa))
.field("n", &self.n)
.field("nu", &self.nu)
.field("e", &self.e)
.finish()
}
}
}
}
generate_rsa_public!(RSA512Public, U512, BarrettU512, Key512, 512);
generate_rsa_public!(RSA1024Public, U1024, BarrettU1024, Key1024, 1024);
generate_rsa_public!(RSA2048Public, U2048, BarrettU2048, Key2048, 2048);
generate_rsa_public!(RSA3072Public, U3072, BarrettU3072, Key3072, 3072);
generate_rsa_public!(RSA4096Public, U4096, BarrettU4096, Key4096, 4096);
generate_rsa_public!(RSA8192Public, U8192, BarrettU8192, Key8192, 8192);
generate_rsa_public!(RSA15360Public, U15360, BarrettU15360, Key15360, 15360);
macro_rules! generate_tests {
( $( ($mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) ),* ) => {
$(
#[cfg(test)]
#[allow(non_snake_case)]
mod $mod {
use cryptonum::unsigned::Decoder;
use super::*;
use testing::run_test;
use rsa::signing_hashes::*;
#[test]
fn encode() {
let fname = format!("tests/rsa/rsa{}.test", $size);
run_test(fname.to_string(), 8, |case| {
let (neg0, nbytes) = case.get("n").unwrap();
let (neg1, ubytes) = case.get("u").unwrap();
let (neg2, kbytes) = case.get("k").unwrap();
assert!(!neg0&&!neg1&&!neg2);
let n = $num::from_bytes(nbytes);
println!("n: {:X}", n);
let n64 = $num64::from(&n);
let nu = $num64::from_bytes(ubytes);
let bigk = $num::from_bytes(kbytes);
let k = usize::from(bigk);
let e = $num::from(65537u64);
let pubkey = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
let asn1 = pubkey.to_asn1().unwrap();
let (pubkey2, _) = $rsa::from_asn1(&asn1).unwrap();
assert_eq!(pubkey, pubkey2);
});
}
#[test]
fn verify() {
let fname = format!("tests/rsa/rsa{}.test", $size);
run_test(fname.to_string(), 8, |case| {
let (neg0, nbytes) = case.get("n").unwrap();
let (neg1, hbytes) = case.get("h").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, sbytes) = case.get("s").unwrap();
let (neg4, ubytes) = case.get("u").unwrap();
let (neg5, kbytes) = case.get("k").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5);
let n = $num::from_bytes(nbytes);
let n64 = $num64::from(&n);
let nu = $num64::from_bytes(ubytes);
let bigk = $num::from_bytes(kbytes);
let k = usize::from(bigk);
let e = $num::from(65537u64);
let pubkey = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
let hashnum = ((hbytes[0] as u16)<<8) + (hbytes[1] as u16);
let sighash = match hashnum {
0x160 => &SIGNING_HASH_SHA1,
0x224 => &SIGNING_HASH_SHA224,
0x256 => &SIGNING_HASH_SHA256,
0x384 => &SIGNING_HASH_SHA384,
0x512 => &SIGNING_HASH_SHA512,
_ => panic!("Bad signing hash: {}", hashnum)
};
assert!(pubkey.verify(sighash, &mbytes, &sbytes));
});
}
#[test]
fn encrypt() {
let fname = format!("tests/rsa/rsa{}.test", $size);
run_test(fname.to_string(), 8, |case| {
let (neg0, nbytes) = case.get("n").unwrap();
let (neg1, hbytes) = case.get("h").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, sbytes) = case.get("s").unwrap();
let (neg4, ubytes) = case.get("u").unwrap();
let (neg5, kbytes) = case.get("k").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5);
let n = $num::from_bytes(nbytes);
let n64 = $num64::from(&n);
let nu = $num64::from_bytes(ubytes);
let bigk = $num::from_bytes(kbytes);
let k = usize::from(bigk);
let e = $num::from(65537u64);
let pubkey = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
let hashnum = ((hbytes[0] as u16)<<8) + (hbytes[1] as u16);
let sighash = match hashnum {
0x160 => &SIGNING_HASH_SHA1,
0x224 => &SIGNING_HASH_SHA224,
0x256 => &SIGNING_HASH_SHA256,
0x384 => &SIGNING_HASH_SHA384,
0x512 => &SIGNING_HASH_SHA512,
_ => panic!("Bad signing hash: {}", hashnum)
};
assert!(pubkey.verify(sighash, &mbytes, &sbytes));
});
}
}
)*
}
}
generate_tests!( (RSA512, RSA512Public, U512, BarrettU512, U576, 512),
(RSA1024, RSA1024Public, U1024, BarrettU1024, U1088, 1024),
(RSA2048, RSA2048Public, U2048, BarrettU2048, U2112, 2048),
(RSA3072, RSA3072Public, U3072, BarrettU3072, U3136, 3072),
(RSA4096, RSA4096Public, U4096, BarrettU4096, U4160, 4096),
(RSA8192, RSA8192Public, U8192, BarrettU8192, U8256, 8192),
(RSA15360, RSA15360Public, U15360, BarrettU15360, U15424, 15360)
);

View File

@@ -1,4 +1,4 @@
use digest::{FixedOutput,Input};
use digest::Digest;
use sha1::Sha1;
use sha2::{Sha224,Sha256,Sha384,Sha512};
use std::fmt;
@@ -46,9 +46,7 @@ pub static SIGNING_HASH_SHA1: SigningHash = SigningHash {
};
fn runsha1(i: &[u8]) -> Vec<u8> {
let mut d = Sha1::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
Sha1::digest(i).as_slice().to_vec()
}
/// Sign a hash based on SHA2-224. This is the first reasonable choice
@@ -63,9 +61,7 @@ pub static SIGNING_HASH_SHA224: SigningHash = SigningHash {
};
fn runsha224(i: &[u8]) -> Vec<u8> {
let mut d = Sha224::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
Sha224::digest(i).as_slice().to_vec()
}
/// Sign a hash based on SHA2-256. The first one I'd recommend!
@@ -78,9 +74,7 @@ pub static SIGNING_HASH_SHA256: SigningHash = SigningHash {
};
fn runsha256(i: &[u8]) -> Vec<u8> {
let mut d = Sha256::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
Sha256::digest(i).as_slice().to_vec()
}
/// Sign a hash based on SHA2-384. Approximately 50% better than
@@ -94,9 +88,7 @@ pub static SIGNING_HASH_SHA384: SigningHash = SigningHash {
};
fn runsha384(i: &[u8]) -> Vec<u8> {
let mut d = Sha384::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
Sha384::digest(i).as_slice().to_vec()
}
/// Sign a hash based on SHA2-512. At this point, you're getting a bit
@@ -111,9 +103,7 @@ pub static SIGNING_HASH_SHA512: SigningHash = SigningHash {
};
fn runsha512(i: &[u8]) -> Vec<u8> {
let mut d = Sha512::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
Sha512::digest(i).as_slice().to_vec()
}

View File

@@ -1,9 +1,13 @@
use cryptonum::{SCN,UCN};
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::str::Lines;
pub fn build_test_path(dir: &str, typename: &str) -> String
{
format!("testdata/{}/{}.test", dir, typename)
}
fn next_value_set(line: &str) -> (String, bool, Vec<u8>)
{
assert!(line.is_ascii());
@@ -11,7 +15,7 @@ fn next_value_set(line: &str) -> (String, bool, Vec<u8>)
let key = items.next().unwrap();
let valbits = items.next().unwrap();
let neg = valbits.contains('-');
let valbitsnoneg = valbits.trim_left_matches("-");
let valbitsnoneg = valbits.trim_start_matches("-");
let mut nibble_iter = valbitsnoneg.chars().rev();
let mut val = Vec::new();
@@ -49,32 +53,7 @@ fn next_test_case(contents: &mut Lines, lines: usize) ->
Some(res)
}
pub fn make_signed(m: HashMap<String,(bool,Vec<u8>)>) -> HashMap<String,SCN>
{
let mut res: HashMap<String,SCN> = HashMap::new();
for (key, (neg, bval)) in m.iter() {
let base = UCN::from_bytes(bval);
let val = SCN{ negative: *neg, value: base };
res.insert(key.clone(), val);
}
res
}
pub fn make_unsigned(m: HashMap<String,(bool,Vec<u8>)>) -> HashMap<String,UCN>
{
let mut res: HashMap<String,UCN> = HashMap::new();
for (key, (neg, bval)) in m.iter() {
assert!(!neg);
res.insert(key.clone(), UCN::from_bytes(bval));
}
res
}
pub fn run_test<F>(fname: &'static str, i: usize, f: F)
pub fn run_test<F>(fname: String, i: usize, f: F)
where F: Fn(HashMap<String,(bool,Vec<u8>)>)
{
let mut file = File::open(fname).unwrap();

57
src/utils.rs Normal file
View File

@@ -0,0 +1,57 @@
use cryptonum::unsigned::*;
use num::{BigInt,BigUint};
use num::bigint::Sign;
pub trait TranslateNums<N>: Sized {
fn from_num(x: &N) -> Option<Self>;
fn to_num(&self) -> N;
}
macro_rules! from_biguint {
($uname: ident, $size: expr) => {
impl TranslateNums<BigUint> for $uname {
fn from_num(x: &BigUint) -> Option<$uname> {
let mut base_vec = x.to_bytes_be();
let target_bytes = $size / 8;
if target_bytes < base_vec.len() {
return None;
}
while target_bytes > base_vec.len() {
base_vec.insert(0,0);
}
Some($uname::from_bytes(&base_vec))
}
fn to_num(&self) -> BigUint {
let bytes = self.to_bytes();
BigUint::from_bytes_be(&bytes)
}
}
impl TranslateNums<BigInt> for $uname {
fn from_num(x: &BigInt) -> Option<$uname> {
let ux = x.to_biguint()?;
$uname::from_num(&ux)
}
fn to_num(&self) -> BigInt {
BigInt::from_biguint(Sign::Plus, self.to_num())
}
}
};
}
from_biguint!(U192, 192);
from_biguint!(U256, 256);
from_biguint!(U384, 384);
from_biguint!(U512, 512);
from_biguint!(U576, 576);
from_biguint!(U1024, 1024);
from_biguint!(U2048, 2048);
from_biguint!(U3072, 3072);
from_biguint!(U4096, 4096);
from_biguint!(U8192, 8192);
from_biguint!(U15360, 15360);

377
src/x509/algident.rs Normal file
View File

@@ -0,0 +1,377 @@
use num::BigUint;
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
use x509::error::X509ParseError;
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum HashAlgorithm { SHA1, SHA224, SHA256, SHA384, SHA512 }
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum PublicKeyInfo { RSA, DSA, ECDSA }
#[derive(Clone,Debug,PartialEq)]
pub struct AlgorithmIdentifier {
pub hash: HashAlgorithm,
pub algo: PublicKeyInfo
}
impl FromASN1 for AlgorithmIdentifier {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block])
-> Result<(AlgorithmIdentifier,&[ASN1Block]),X509ParseError>
{
match v.split_first() {
None =>
Err(X509ParseError::NotEnoughData),
Some((x, rest)) => {
let v = decode_algorithm_ident(&x)?;
Ok((v, rest))
}
}
}
}
pub fn decode_algorithm_ident(x: &ASN1Block)
-> Result<AlgorithmIdentifier,X509ParseError>
{
// AlgorithmIdentifier ::= SEQUENCE {
// algorithm OBJECT IDENTIFIER,
// parameters ANY DEFINED BY algorithm OPTIONAL }
match x {
&ASN1Block::Sequence(_, _, ref v) if v.len() >= 1 => {
match v[0] {
ASN1Block::ObjectIdentifier(_, _, ref oid) => {
if oid == oid!(1,2,840,113549,1,1,5) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA1,
algo: PublicKeyInfo::RSA
});
}
if oid == oid!(1,2,840,113549,1,1,11) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA256,
algo: PublicKeyInfo::RSA
});
}
if oid == oid!(1,2,840,113549,1,1,12) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA384,
algo: PublicKeyInfo::RSA
});
}
if oid == oid!(1,2,840,113549,1,1,13) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA512,
algo: PublicKeyInfo::RSA
});
}
if oid == oid!(1,2,840,113549,1,1,14) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA224,
algo: PublicKeyInfo::RSA
});
}
if oid == oid!(1,2,840,10040,4,3) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA1,
algo: PublicKeyInfo::DSA
});
}
if oid == oid!(1,2,840,10045,4,1) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA1,
algo: PublicKeyInfo::ECDSA
});
}
if oid == oid!(1,2,840,10045,4,3,1) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA224,
algo: PublicKeyInfo::ECDSA
});
}
if oid == oid!(1,2,840,10045,4,3,2) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA256,
algo: PublicKeyInfo::ECDSA
});
}
if oid == oid!(1,2,840,10045,4,3,3) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA384,
algo: PublicKeyInfo::ECDSA
});
}
if oid == oid!(1,2,840,10045,4,3,4) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA512,
algo: PublicKeyInfo::ECDSA
});
}
// if oid == oid!(2,16,840,1,101,3,4,2,1) {
// return Ok(AlgorithmIdentifier {
// hash: HashAlgorithm::SHA256,
// algo: PublicKeyInfo::RSAPSS
// });
// }
// if oid == oid!(2,16,840,1,101,3,4,2,2) {
// return Ok(AlgorithmIdentifier {
// hash: HashAlgorithm::SHA384,
// algo: PublicKeyInfo::RSAPSS
// });
// }
// if oid == oid!(2,16,840,1,101,3,4,2,3) {
// return Ok(AlgorithmIdentifier {
// hash: HashAlgorithm::SHA512,
// algo: PublicKeyInfo::RSAPSS
// });
// }
// if oid == oid!(2,16,840,1,101,3,4,2,4) {
// return Ok(AlgorithmIdentifier {
// hash: HashAlgorithm::SHA224,
// algo: PublicKeyInfo::RSAPSS
// });
// }
if oid == oid!(2,16,840,1,101,3,4,3,1) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA224,
algo: PublicKeyInfo::DSA
});
}
if oid == oid!(2,16,840,1,101,3,4,3,2) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA256,
algo: PublicKeyInfo::DSA
});
}
Err(X509ParseError::UnknownAlgorithm)
}
_ =>
Err(X509ParseError::UnknownAlgorithm)
}
}
_ =>
Err(X509ParseError::IllFormedAlgoInfo)
}
}
pub enum SigAlgEncodeError {
ASN1Error(ASN1EncodeErr),
InvalidDSAValue, InvalidHash
}
impl From<ASN1EncodeErr> for SigAlgEncodeError {
fn from(e: ASN1EncodeErr) -> SigAlgEncodeError {
SigAlgEncodeError::ASN1Error(e)
}
}
impl ToASN1 for AlgorithmIdentifier {
type Error = SigAlgEncodeError;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,SigAlgEncodeError>
{
let block = encode_algorithm_ident(c, self)?;
Ok(vec![block])
}
}
fn encode_algorithm_ident(c: ASN1Class, x: &AlgorithmIdentifier)
-> Result<ASN1Block,SigAlgEncodeError>
{
match x.algo {
PublicKeyInfo::RSA => {
match x.hash {
HashAlgorithm::SHA1 => {
let o = oid!(1,2,840,113549,1,1,5);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA224 => {
let o = oid!(1,2,840,113549,1,1,14);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA256 => {
let o = oid!(1,2,840,113549,1,1,11);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA384 => {
let o = oid!(1,2,840,113549,1,1,12);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA512 => {
let o = oid!(1,2,840,113549,1,1,13);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
}
}
PublicKeyInfo::DSA => {
match x.hash {
HashAlgorithm::SHA1 => {
let o = oid!(1,2,840,10040,4,3);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA224 => {
let o = oid!(2,16,840,1,101,3,4,3,1);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA256 => {
let o = oid!(2,16,840,1,101,3,4,3,2);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
_ =>
Err(SigAlgEncodeError::InvalidHash),
}
}
PublicKeyInfo::ECDSA=> {
match x.hash {
HashAlgorithm::SHA1 => {
let o = oid!(1,2,840,10045,4,1);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA224 => {
let o = oid!(1,2,840,10045,4,3,1);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA256 => {
let o = oid!(1,2,840,10045,4,3,2);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA384 => {
let o = oid!(1,2,840,10045,4,3,3);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA512 => {
let o = oid!(1,2,840,10045,4,3,4);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
}
}
}
}
#[cfg(test)]
mod test {
use quickcheck::{Arbitrary,Gen};
use rand::prelude::SliceRandom;
use super::*;
const RSA1: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA1,
algo: PublicKeyInfo::RSA
};
const RSA224: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA224,
algo: PublicKeyInfo::RSA
};
const RSA256: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA256,
algo: PublicKeyInfo::RSA
};
const RSA384: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA384,
algo: PublicKeyInfo::RSA
};
const RSA512: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA512,
algo: PublicKeyInfo::RSA
};
const DSA1: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA1,
algo: PublicKeyInfo::DSA
};
const DSA224: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA224,
algo: PublicKeyInfo::DSA
};
const DSA256: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA256,
algo: PublicKeyInfo::DSA
};
const EC1: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA1,
algo: PublicKeyInfo::ECDSA
};
const EC224: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA224,
algo: PublicKeyInfo::ECDSA
};
const EC256: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA256,
algo: PublicKeyInfo::ECDSA
};
const EC384: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA384,
algo: PublicKeyInfo::ECDSA
};
const EC512: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA512,
algo: PublicKeyInfo::ECDSA
};
impl Arbitrary for AlgorithmIdentifier {
fn arbitrary<G: Gen>(g: &mut G) -> AlgorithmIdentifier {
let opts = [RSA1, RSA224, RSA256, RSA384, RSA512,
DSA1, DSA224, DSA256,
EC1, EC224, EC256, EC384, EC512];
opts.choose(g).unwrap().clone()
}
}
quickcheck!{
fn algident_roundtrips(v: AlgorithmIdentifier) -> bool {
match encode_algorithm_ident(ASN1Class::Universal, &v) {
Err(_) =>
false,
Ok(block) => {
match decode_algorithm_ident(&block) {
Err(_) =>
false,
Ok(v2) =>
v == v2
}
}
}
}
}
}

368
src/x509/atv.rs Normal file
View File

@@ -0,0 +1,368 @@
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
use std::ops::Index;
use x509::error::X509ParseError;
use x509::name::X520Name;
#[derive(Clone,Debug)]
pub struct InfoBlock {
fields: Vec<AttributeTypeValue>
}
const EMPTY_STRING: &'static str = "";
impl Index<X520Name> for InfoBlock {
type Output = str;
fn index(&self, name: X520Name) -> &str {
for atv in self.fields.iter() {
if name == atv.attrtype {
return &atv.value;
}
}
&EMPTY_STRING
}
}
impl PartialEq for InfoBlock {
fn eq(&self, other: &InfoBlock) -> bool {
for x in self.fields.iter() {
if !other.fields.contains(x) {
return false;
}
}
for x in other.fields.iter() {
if !self.fields.contains(x) {
return false;
}
}
true
}
}
fn decode_info_block(x: &ASN1Block)
-> Result<InfoBlock,X509ParseError>
{
// Name ::= CHOICE { -- only one possibility for now --
// rdnSequence RDNSequence }
//
// RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
//
// RelativeDistinguishedName ::=
// SET SIZE (1..MAX) OF AttributeTypeAndValue
match x {
&ASN1Block::Sequence(_, _, ref items) => {
let mut atvs = Vec::new();
for set in items.iter() {
match set {
&ASN1Block::Set(_, _, ref setitems) => {
for atv in setitems.iter() {
let v = decode_attribute_type_value(atv)?;
atvs.push(v);
}
}
_ =>
return Err(X509ParseError::IllFormedInfoBlock)
}
}
Ok(InfoBlock{ fields: atvs })
}
_ =>
Err(X509ParseError::IllFormedInfoBlock)
}
}
impl FromASN1 for InfoBlock {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block])
-> Result<(InfoBlock,&[ASN1Block]),X509ParseError>
{
match v.split_first() {
None =>
Err(X509ParseError::NotEnoughData),
Some((x, rest)) => {
let v = decode_info_block(&x)?;
Ok((v, rest))
}
}
}
}
fn encode_info_block(c: ASN1Class, b: &InfoBlock)
-> Result<ASN1Block,ASN1EncodeErr>
{
let mut encoded_fields = Vec::with_capacity(b.fields.len());
for fld in b.fields.iter() {
let val = encode_attribute_type_value(c, fld)?;
encoded_fields.push(val);
}
let set = ASN1Block::Set(c, 0, encoded_fields);
Ok(ASN1Block::Sequence(c, 0, vec![set]))
}
impl ToASN1 for InfoBlock {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let block = encode_info_block(c, self)?;
Ok(vec![block])
}
}
#[derive(Clone,Debug,PartialEq)]
struct AttributeTypeValue {
attrtype: X520Name,
value: String
}
fn decode_attribute_type_value(x: &ASN1Block)
-> Result<AttributeTypeValue,X509ParseError>
{
// AttributeTypeAndValue ::= SEQUENCE {
// type AttributeType,
// value AttributeValue }
match x {
&ASN1Block::Sequence(_, _, ref xs) => {
let (name, rest) = X520Name::from_asn1(xs)?;
match rest.first() {
None => Err(X509ParseError::NotEnoughData),
Some(ref x) => {
let atvstr = get_atv_string(name, x)?;
Ok(AttributeTypeValue{
attrtype: name,
value: atvstr
})
}
}
}
_ =>
Err(X509ParseError::IllFormedAttrTypeValue)
}
}
impl FromASN1 for AttributeTypeValue {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block])
-> Result<(AttributeTypeValue,&[ASN1Block]),X509ParseError>
{
match v.split_first() {
None =>
Err(X509ParseError::NotEnoughData),
Some((x, rest)) => {
let v = decode_attribute_type_value(&x)?;
Ok((v, rest))
}
}
}
}
fn encode_attribute_type_value(c: ASN1Class, x: &AttributeTypeValue)
-> Result<ASN1Block,ASN1EncodeErr>
{
let mut resvec = x.attrtype.to_asn1_class(c)?;
let value = match x.attrtype {
X520Name::CountryName =>
ASN1Block::PrintableString(c,0,x.value.clone()),
X520Name::SerialNumber =>
ASN1Block::PrintableString(c,0,x.value.clone()),
X520Name::DomainComponent =>
ASN1Block::IA5String(c,0,x.value.clone()),
X520Name::EmailAddress =>
ASN1Block::IA5String(c,0,x.value.clone()),
_ =>
ASN1Block::UTF8String(c,0,x.value.clone())
};
resvec.push(value);
Ok(ASN1Block::Sequence(c, 0, resvec))
}
impl ToASN1 for AttributeTypeValue {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let block = encode_attribute_type_value(c, self)?;
Ok(vec![block])
}
}
fn get_atv_string(n: X520Name, x: &ASN1Block)
-> Result<String,X509ParseError>
{
match n {
X520Name::CountryName => {
let res = get_printable_val(x)?;
if res.len() != 2 {
return Err(X509ParseError::IllegalStringValue);
}
Ok(res)
}
X520Name::SerialNumber => get_printable_val(x),
X520Name::DomainComponent => get_ia5_val(x),
X520Name::EmailAddress => get_ia5_val(x),
_ => get_string_val(x),
}
}
fn get_string_val(a: &ASN1Block) -> Result<String,X509ParseError>
{
match a {
&ASN1Block::TeletexString(_,_,ref v) => Ok(v.clone()),
&ASN1Block::PrintableString(_,_,ref v) => Ok(v.clone()),
&ASN1Block::UniversalString(_,_,ref v) => Ok(v.clone()),
&ASN1Block::UTF8String(_,_,ref v) => Ok(v.clone()),
&ASN1Block::BMPString(_,_,ref v) => Ok(v.clone()),
_ =>
Err(X509ParseError::IllegalStringValue)
}
}
fn get_printable_val(a: &ASN1Block) -> Result<String,X509ParseError>
{
match a {
&ASN1Block::PrintableString(_,_,ref v) => Ok(v.clone()),
_ =>
Err(X509ParseError::IllegalStringValue)
}
}
fn get_ia5_val(a: &ASN1Block) -> Result<String,X509ParseError>
{
match a {
&ASN1Block::IA5String(_,_,ref v) => Ok(v.clone()),
_ =>
Err(X509ParseError::IllegalStringValue)
}
}
#[cfg(test)]
mod test {
use quickcheck::{Arbitrary,Gen};
use rand::Rng;
use rand::prelude::SliceRandom;
use std::iter::FromIterator;
use super::*;
impl Arbitrary for X520Name {
fn arbitrary<G: Gen>(g: &mut G) -> X520Name {
let names = vec![X520Name::Name,
X520Name::Surname,
X520Name::GivenName,
X520Name::Initials,
X520Name::GenerationQualifier,
X520Name::CommonName,
X520Name::LocalityName,
X520Name::StateOrProvinceName,
X520Name::OrganizationName,
X520Name::OrganizationalUnit,
X520Name::Title,
X520Name::DNQualifier,
X520Name::CountryName,
X520Name::SerialNumber,
X520Name::Pseudonym,
X520Name::DomainComponent,
X520Name::EmailAddress];
names.choose(g).unwrap().clone()
}
}
impl Arbitrary for AttributeTypeValue {
fn arbitrary<G: Gen>(g: &mut G) -> AttributeTypeValue {
let name = X520Name::arbitrary(g);
let val = match name {
X520Name::CountryName => {
let mut base = gen_printable(g);
base.push('U');
base.push('S');
base.truncate(2);
base
}
X520Name::SerialNumber => gen_printable(g),
X520Name::DomainComponent => gen_ia5(g),
X520Name::EmailAddress => gen_ia5(g),
_ => gen_utf8(g)
};
AttributeTypeValue{ attrtype: name, value: val }
}
}
const PRINTABLE_CHARS: &'static str =
"ABCDEFGHIJKLMOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'()+,-./:=? ";
fn gen_printable<G: Gen>(g: &mut G) -> String {
let count = g.gen_range(0, 384);
let mut items = Vec::with_capacity(count);
for _ in 0..count {
let v = PRINTABLE_CHARS.as_bytes().choose(g).unwrap();
items.push(*v as char);
}
String::from_iter(items.iter())
}
fn gen_ia5<G: Gen>(g: &mut G) -> String {
let count = g.gen_range(0, 384);
let mut items = Vec::with_capacity(count);
for _ in 0..count {
items.push(g.gen::<u8>() as char);
}
String::from_iter(items.iter())
}
fn gen_utf8<G: Gen>(g: &mut G) -> String {
String::arbitrary(g)
}
impl Arbitrary for InfoBlock {
fn arbitrary<G: Gen>(g: &mut G) -> InfoBlock {
let count = g.gen_range(0,12);
let mut items = Vec::with_capacity(count);
let mut names = Vec::with_capacity(count);
while items.len() < count {
let atv = AttributeTypeValue::arbitrary(g);
if !names.contains(&atv.attrtype) {
names.push(atv.attrtype);
items.push(atv);
}
}
InfoBlock{ fields: items }
}
}
quickcheck! {
fn attrtypeval_roundtrips(v: AttributeTypeValue) -> bool {
match encode_attribute_type_value(ASN1Class::Universal, &v) {
Err(_) => false,
Ok(bstr) =>
match decode_attribute_type_value(&bstr) {
Err(_) => false,
Ok(v2) => v == v2
}
}
}
fn infoblock_roundtrips(v: InfoBlock) -> bool {
match encode_info_block(ASN1Class::Universal, &v) {
Err(_) => false,
Ok(bstr) =>
match decode_info_block(&bstr) {
Err(_) => false,
Ok(v2) => v == v2
}
}
}
}
}

53
src/x509/error.rs Normal file
View File

@@ -0,0 +1,53 @@
use dsa::rfc6979::DSADecodeError;
use ecdsa::ECDSADecodeErr;
use rsa::RSAError;
use simple_asn1::{ASN1DecodeErr,ASN1EncodeErr};
/// The error type for parsing and validating an X.509 certificate.
#[derive(Debug)]
pub enum X509ParseError {
ASN1DecodeError(ASN1DecodeErr), ASN1EncodeError(ASN1EncodeErr),
RSAError(RSAError), DSADecodeError(DSADecodeError), ECDSADecodeError(ECDSADecodeErr),
RSASignatureWrong, DSASignatureWrong,
NotEnoughData,
IllFormedName, IllFormedAttrTypeValue, IllFormedInfoBlock,
IllFormedValidity, IllFormedCertificateInfo, IllFormedSerialNumber,
IllFormedAlgoInfo, IllFormedKey, IllFormedEverything,
IllegalStringValue, NoSerialNumber, InvalidDSAInfo, ItemNotFound,
UnknownAlgorithm, InvalidRSAKey, InvalidDSAKey, InvalidSignatureData,
InvalidSignatureHash, InvalidECDSAKey, InvalidPointForm,
UnknownEllipticCurve,
CompressedPointUnsupported,
KeyNotFound,
SignatureNotFound, SignatureVerificationFailed
}
impl From<ASN1DecodeErr> for X509ParseError {
fn from(e: ASN1DecodeErr) -> X509ParseError {
X509ParseError::ASN1DecodeError(e)
}
}
impl From<ASN1EncodeErr> for X509ParseError {
fn from(e: ASN1EncodeErr) -> X509ParseError {
X509ParseError::ASN1EncodeError(e)
}
}
impl From<RSAError> for X509ParseError {
fn from(e: RSAError) -> X509ParseError {
X509ParseError::RSAError(e)
}
}
impl From<ECDSADecodeErr> for X509ParseError {
fn from(e: ECDSADecodeErr) -> X509ParseError {
X509ParseError::ECDSADecodeError(e)
}
}
impl From<DSADecodeError> for X509ParseError {
fn from(e: DSADecodeError) -> X509ParseError {
X509ParseError::DSADecodeError(e)
}
}

195
src/x509/misc.rs Normal file
View File

@@ -0,0 +1,195 @@
use num::{BigInt,BigUint,One,ToPrimitive,Zero};
use num::bigint::ToBigInt;
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
use x509::error::X509ParseError;
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum X509Version { V1, V2, V3 }
fn decode_version(bs: &[ASN1Block])
-> Result<(X509Version,&[ASN1Block]),X509ParseError>
{
match bs.split_first() {
Some((&ASN1Block::Integer(_, _, ref v), rest)) => {
match v.to_u8() {
Some(0) => Ok((X509Version::V1, rest)),
Some(1) => Ok((X509Version::V2, rest)),
Some(2) => Ok((X509Version::V3, rest)),
_ => Ok((X509Version::V1, &bs))
}
}
_ =>
Err(X509ParseError::NotEnoughData)
}
}
impl FromASN1 for X509Version {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block])
-> Result<(X509Version,&[ASN1Block]),X509ParseError>
{
decode_version(v)
}
}
fn encode_version(c: ASN1Class, v: X509Version) -> Vec<ASN1Block> {
match v {
X509Version::V1 => {
let zero: BigInt = Zero::zero();
let block = ASN1Block::Integer(c, 0, zero);
vec![block]
}
X509Version::V2 => {
let one: BigInt = One::one();
let block = ASN1Block::Integer(c, 0, one);
vec![block]
}
X509Version::V3 => {
let two: BigInt = BigInt::from(2 as u64);
let block = ASN1Block::Integer(c, 0, two);
vec![block]
}
}
}
impl ToASN1 for X509Version {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
Ok(encode_version(c, *self))
}
}
/******************************************************************************/
#[derive(Clone,Debug,PartialEq)]
pub struct X509Serial {
num: BigUint
}
fn decode_serial(x: &ASN1Block)
-> Result<X509Serial,X509ParseError>
{
match x {
&ASN1Block::Integer(_, _, ref v) => {
match v.to_biguint() {
None =>
Err(X509ParseError::IllFormedSerialNumber),
Some(n) =>
Ok(X509Serial{ num: n })
}
}
_ =>
Err(X509ParseError::NoSerialNumber)
}
}
impl FromASN1 for X509Serial {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block])
-> Result<(X509Serial,&[ASN1Block]),X509ParseError>
{
match v.split_first() {
None =>
Err(X509ParseError::NoSerialNumber),
Some((x, rest)) => {
let v = decode_serial(x)?;
Ok((v, rest))
}
}
}
}
pub enum SerialEncodeErr { ASN1Error(ASN1EncodeErr), InvalidSerialNumber }
impl From<ASN1EncodeErr> for SerialEncodeErr {
fn from(e: ASN1EncodeErr) -> SerialEncodeErr {
SerialEncodeErr::ASN1Error(e)
}
}
fn encode_serial(c: ASN1Class, serial: &X509Serial)
-> Result<ASN1Block,SerialEncodeErr>
{
match serial.num.to_bigint() {
None =>
Err(SerialEncodeErr::InvalidSerialNumber),
Some(n) =>
Ok(ASN1Block::Integer(c, 0, n))
}
}
impl ToASN1 for X509Serial {
type Error = SerialEncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,SerialEncodeErr>
{
let v = encode_serial(c, self)?;
Ok(vec![v])
}
}
pub fn decode_signature(x: &ASN1Block)
-> Result<Vec<u8>,X509ParseError>
{
match x {
&ASN1Block::BitString(_, _, size, ref sig) if size % 8 == 0 => {
Ok(sig.to_vec())
}
_ =>
Err(X509ParseError::SignatureNotFound)
}
}
#[cfg(test)]
mod test {
use quickcheck::{Arbitrary,Gen};
use rand::Rng;
use rand::distributions::Uniform;
use super::*;
fn check_version_roundtrip(v: X509Version) {
let blocks = encode_version(ASN1Class::Universal, v);
match decode_version(&blocks) {
Err(_) =>
assert!(false),
Ok((v2,_)) =>
assert_eq!(v, v2)
}
}
#[test]
fn versions_roundtrip() {
check_version_roundtrip(X509Version::V1);
check_version_roundtrip(X509Version::V2);
check_version_roundtrip(X509Version::V3);
}
impl Arbitrary for X509Serial {
fn arbitrary<G: Gen>(g: &mut G) -> X509Serial {
let count = g.gen_range(0,16);
let dist = Uniform::new_inclusive(0,255);
let bits = g.sample_iter(&dist).take(count).collect();
let val = BigUint::new(bits);
X509Serial{ num: val }
}
}
quickcheck! {
fn serial_roundtrips(s: X509Serial) -> bool {
match encode_serial(ASN1Class::Universal, &s) {
Err(_) => false,
Ok(block) =>
match decode_serial(&block) {
Err(_) => false,
Ok(s2) => s == s2
}
}
}
}
}

301
src/x509/mod.rs Normal file
View File

@@ -0,0 +1,301 @@
mod algident;
mod atv;
mod error;
mod misc;
mod name;
mod publickey;
mod validity;
use dsa::{DSAPublic,DSAPublicKey};
use ecdsa::{ECDSAPublic,ECCPublicKey};
use rsa::{SIGNING_HASH_SHA1,SIGNING_HASH_SHA224,SIGNING_HASH_SHA256,SIGNING_HASH_SHA384,SIGNING_HASH_SHA512};
use sha1::Sha1;
use sha2::{Sha224,Sha256,Sha384,Sha512};
use simple_asn1::{ASN1Block,FromASN1,der_decode,from_der};
use x509::validity::Validity;
use x509::algident::{AlgorithmIdentifier,HashAlgorithm,PublicKeyInfo,
decode_algorithm_ident};
use x509::atv::InfoBlock;
use x509::error::X509ParseError;
use x509::misc::{X509Serial,X509Version,decode_signature};
use x509::publickey::X509PublicKey;
/*******************************************************************************
*
* The actual certificate data type and methods
*
******************************************************************************/
/// The type of an X.509 certificate.
pub struct GenericCertificate {
pub version: X509Version,
pub serial: X509Serial,
pub signature_alg: AlgorithmIdentifier,
pub issuer: InfoBlock,
pub subject: InfoBlock,
pub validity: Validity,
pub subject_key: X509PublicKey,
pub extensions: Vec<()>
}
fn decode_certificate(x: &ASN1Block)
-> Result<GenericCertificate,X509ParseError>
{
//
// TBSCertificate ::= SEQUENCE {
// version [0] Version DEFAULT v1,
// serialNumber CertificateSerialNumber,
// signature AlgorithmIdentifier,
// issuer Name,
// validity Validity,
// subject Name,
// subjectPublicKeyInfo SubjectPublicKeyInfo,
// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
// -- If present, version MUST be v2 or v3
// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
// -- If present, version MUST be v2 or v3
// extensions [3] Extensions OPTIONAL
// -- If present, version MUST be v3 -- }
//
match x {
&ASN1Block::Sequence(_, _, ref b0) => {
println!("STEP1");
let (version, b1) = X509Version::from_asn1(b0)?;
println!("STEP2");
let (serial, b2) = X509Serial::from_asn1(b1)?;
println!("STEP3");
let (ident, b3) = AlgorithmIdentifier::from_asn1(b2)?;
println!("STEP4");
let (issuer, b4) = InfoBlock::from_asn1(b3)?;
println!("STEP5");
let (validity, b5) = Validity::from_asn1(b4)?;
println!("STEP6");
let (subject, b6) = InfoBlock::from_asn1(b5)?;
println!("STEP7");
let (subkey, _ ) = X509PublicKey::from_asn1(b6)?;
println!("STEP8");
Ok(GenericCertificate {
version: version,
serial: serial,
signature_alg: ident,
issuer: issuer,
subject: subject,
validity: validity,
subject_key: subkey,
extensions: vec![]
})
}
_ =>
Err(X509ParseError::IllFormedCertificateInfo)
}
}
/*******************************************************************************
*
* X.509 parsing routines
*
******************************************************************************/
pub fn parse_x509(buffer: &[u8]) -> Result<GenericCertificate,X509ParseError> {
let blocks = from_der(&buffer[..])?;
match blocks.first() {
None =>
Err(X509ParseError::NotEnoughData),
Some(&ASN1Block::Sequence(_, _, ref x)) => {
let cert = decode_certificate(&x[0])?;
let cert_block_start = x[0].offset();
let cert_block_end = x[1].offset();
let cert_block = &buffer[cert_block_start..cert_block_end];
let alginfo = decode_algorithm_ident(&x[1])?;
let sig = decode_signature(&x[2])?;
check_signature(&alginfo, &cert.subject_key, cert_block, sig)?;
Ok(cert)
}
Some(_) =>
Err(X509ParseError::IllFormedEverything)
}
}
fn check_signature(alg: &AlgorithmIdentifier,
key: &X509PublicKey,
block: &[u8],
sig: Vec<u8>)
-> Result<(),X509ParseError>
{
match (alg.algo, key) {
(PublicKeyInfo::RSA, &X509PublicKey::RSA(ref key)) => {
let sighash = match alg.hash {
HashAlgorithm::SHA1 => &SIGNING_HASH_SHA1,
HashAlgorithm::SHA224 => &SIGNING_HASH_SHA224,
HashAlgorithm::SHA256 => &SIGNING_HASH_SHA256,
HashAlgorithm::SHA384 => &SIGNING_HASH_SHA384,
HashAlgorithm::SHA512 => &SIGNING_HASH_SHA512,
};
if !key.verify(sighash, block, &sig) {
return Err(X509ParseError::RSASignatureWrong);
}
Ok(())
}
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL1024N160(ref key))) => {
let dsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1
if key.verify::<Sha1>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA224
if key.verify::<Sha224>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &dsa_sig) =>
Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL2048N224(ref key))) => {
let dsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1
if key.verify::<Sha1>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA224
if key.verify::<Sha224>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &dsa_sig) =>
Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL2048N256(ref key))) => {
let dsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1
if key.verify::<Sha1>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA224
if key.verify::<Sha224>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &dsa_sig) =>
Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL3072N256(ref key))) => {
let dsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1
if key.verify::<Sha1>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA224
if key.verify::<Sha224>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &dsa_sig) =>
Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP192(ref key))) => {
let ecdsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA224 if key.verify::<Sha224>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP224(ref key))) => {
let ecdsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA224 if key.verify::<Sha224>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP256(ref key))) => {
let ecdsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA224 if key.verify::<Sha224>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP384(ref key))) => {
let ecdsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA224 if key.verify::<Sha224>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP521(ref key))) => {
let ecdsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA224 if key.verify::<Sha224>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
_ =>
Err(X509ParseError::InvalidSignatureData)
}
}
/*******************************************************************************
*
* Testing is for winners!
*
******************************************************************************/
#[cfg(test)]
mod tests {
use std::fs::File;
use std::io::Read;
use super::*;
fn can_parse(f: &str) -> Result<GenericCertificate,X509ParseError> {
let mut fd = File::open(f).unwrap();
let mut buffer = Vec::new();
let _amt = fd.read_to_end(&mut buffer);
parse_x509(&buffer)
}
#[test]
fn rsa_tests() {
assert!(can_parse("testdata/x509/rsa2048-1.der").is_ok());
assert!(can_parse("testdata/x509/rsa2048-2.der").is_ok());
assert!(can_parse("testdata/x509/rsa4096-1.der").is_ok());
assert!(can_parse("testdata/x509/rsa4096-2.der").is_ok());
assert!(can_parse("testdata/x509/rsa4096-3.der").is_ok());
}
#[test]
fn dsa_tests() {
assert!(can_parse("testdata/x509/dsa2048-1.der").is_ok());
assert!(can_parse("testdata/x509/dsa2048-2.der").is_ok());
assert!(can_parse("testdata/x509/dsa3072-1.der").is_ok());
assert!(can_parse("testdata/x509/dsa3072-2.der").is_ok());
}
#[test]
fn ecc_tests() {
assert!(can_parse("testdata/x509/ec384-1.der").is_ok());
assert!(can_parse("testdata/x509/ec384-2.der").is_ok());
assert!(can_parse("testdata/x509/ec384-3.der").is_ok());
}
}

136
src/x509/name.rs Normal file
View File

@@ -0,0 +1,136 @@
use num::BigUint;
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
use x509::error::X509ParseError;
#[derive(Copy,Clone,Debug,Eq,Hash,PartialEq)]
pub enum X520Name {
Name, Surname, GivenName, Initials, GenerationQualifier, CommonName,
LocalityName, StateOrProvinceName, OrganizationName, OrganizationalUnit,
Title, DNQualifier, CountryName, SerialNumber, Pseudonym, DomainComponent,
EmailAddress
}
impl FromASN1 for X520Name {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block])
-> Result<(X520Name,&[ASN1Block]),X509ParseError>
{
match v.split_first() {
None =>
Err(X509ParseError::NotEnoughData),
Some((x,rest)) => {
let name = decode_name(&x)?;
Ok((name,rest))
}
}
}
}
fn decode_name(val: &ASN1Block)
-> Result<X520Name,X509ParseError>
{
match val {
&ASN1Block::ObjectIdentifier(_, _, ref oid) => {
if oid == oid!(2,5,4,41) {return Ok(X520Name::Name) }
if oid == oid!(2,5,4,4) {return Ok(X520Name::Surname) }
if oid == oid!(2,5,4,42) {return Ok(X520Name::GivenName) }
if oid == oid!(2,5,4,43) {return Ok(X520Name::Initials) }
if oid == oid!(2,5,4,44) {return Ok(X520Name::GenerationQualifier)}
if oid == oid!(2,5,4,3) {return Ok(X520Name::CommonName) }
if oid == oid!(2,5,4,7) {return Ok(X520Name::LocalityName) }
if oid == oid!(2,5,4,8) {return Ok(X520Name::StateOrProvinceName)}
if oid == oid!(2,5,4,10) {return Ok(X520Name::OrganizationName) }
if oid == oid!(2,5,4,11) {return Ok(X520Name::OrganizationalUnit) }
if oid == oid!(2,5,4,12) {return Ok(X520Name::Title) }
if oid == oid!(2,5,4,46) {return Ok(X520Name::DNQualifier) }
if oid == oid!(2,5,4,6) {return Ok(X520Name::CountryName) }
if oid == oid!(2,5,4,5) {return Ok(X520Name::SerialNumber) }
if oid == oid!(2,5,4,65) {return Ok(X520Name::Pseudonym) }
if oid == oid!(0,9,2342,19200300,100,1,25) {
return Ok(X520Name::DomainComponent);
}
if oid == oid!(1,2,840,113549,1,9,1) {
return Ok(X520Name::EmailAddress);
}
Err(X509ParseError::IllFormedName)
}
_ =>
Err(X509ParseError::IllFormedName)
}
}
impl ToASN1 for X520Name {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let block = encode_name(c, *self);
Ok(vec![block])
}
}
fn encode_name(class: ASN1Class, name: X520Name)
-> ASN1Block
{
let oid = match name {
X520Name::Name => oid!(2,5,4,41),
X520Name::Surname => oid!(2,5,4,4),
X520Name::GivenName => oid!(2,5,4,42),
X520Name::Initials => oid!(2,5,4,43),
X520Name::GenerationQualifier => oid!(2,5,4,44),
X520Name::CommonName => oid!(2,5,4,3),
X520Name::LocalityName => oid!(2,5,4,7),
X520Name::StateOrProvinceName => oid!(2,5,4,8),
X520Name::OrganizationName => oid!(2,5,4,10),
X520Name::OrganizationalUnit => oid!(2,5,4,11),
X520Name::Title => oid!(2,5,4,12),
X520Name::DNQualifier => oid!(2,5,4,46),
X520Name::CountryName => oid!(2,5,4,6),
X520Name::SerialNumber => oid!(2,5,4,5),
X520Name::Pseudonym => oid!(2,5,4,65),
X520Name::DomainComponent => oid!(0,9,2342,19200300,100,1,25),
X520Name::EmailAddress => oid!(1,2,840,113549,1,9,1)
};
ASN1Block::ObjectIdentifier(class, 0, oid)
}
#[cfg(test)]
mod tests {
use super::*;
fn encdec_test(n: X520Name) {
let block = encode_name(ASN1Class::Universal, n);
let vec = vec![block];
match X520Name::from_asn1(&vec) {
Err(_) =>
assert!(false),
Ok((m, _)) =>
assert_eq!(n,m)
}
}
#[test]
fn name_encoding_roundtrips() {
encdec_test(X520Name::Name);
encdec_test(X520Name::Surname);
encdec_test(X520Name::GivenName);
encdec_test(X520Name::Initials);
encdec_test(X520Name::GenerationQualifier);
encdec_test(X520Name::CommonName);
encdec_test(X520Name::LocalityName);
encdec_test(X520Name::StateOrProvinceName);
encdec_test(X520Name::OrganizationName);
encdec_test(X520Name::OrganizationalUnit);
encdec_test(X520Name::Title);
encdec_test(X520Name::DNQualifier);
encdec_test(X520Name::CountryName);
encdec_test(X520Name::SerialNumber);
encdec_test(X520Name::Pseudonym);
encdec_test(X520Name::DomainComponent);
encdec_test(X520Name::EmailAddress);
}
}

328
src/x509/publickey.rs Normal file
View File

@@ -0,0 +1,328 @@
use cryptonum::unsigned::{U3072,U2048,U1024,U256,U192};
use dsa::{DSAPublic,DSAPublicKey,DSAPubKey,DSAParameters};
use dsa::{L3072N256,L2048N256,L2048N224,L1024N160};
use ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPubKey};
use ecdsa::curve::{P192,P224,P256,P384,P521};
use num::BigUint;
use rsa::RSAPublic;
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1,
der_decode,der_encode,from_der};
use utils::TranslateNums;
use x509::error::X509ParseError;
pub enum X509PublicKey {
DSA(DSAPublic),
RSA(RSAPublic),
ECDSA(ECDSAPublic)
}
impl From<X509PublicKey> for Option<DSAPublic> {
fn from(x: X509PublicKey) -> Option<DSAPublic> {
match x {
X509PublicKey::DSA(x) => Some(x),
_ => None
}
}
}
impl From<X509PublicKey> for Option<RSAPublic> {
fn from(x: X509PublicKey) -> Option<RSAPublic> {
match x {
X509PublicKey::RSA(x) => Some(x),
_ => None
}
}
}
impl From<X509PublicKey> for Option<ECDSAPublic> {
fn from(x: X509PublicKey) -> Option<ECDSAPublic> {
match x {
X509PublicKey::ECDSA(x) => Some(x),
_ => None
}
}
}
pub enum X509EncodeErr {
ASN1EncodeErr(ASN1EncodeErr),
ECDSAEncodeErr(ECDSAEncodeErr)
}
impl From<ASN1EncodeErr> for X509EncodeErr {
fn from(x: ASN1EncodeErr) -> X509EncodeErr {
X509EncodeErr::ASN1EncodeErr(x)
}
}
impl From<ECDSAEncodeErr> for X509EncodeErr {
fn from(x: ECDSAEncodeErr) -> X509EncodeErr {
X509EncodeErr::ECDSAEncodeErr(x)
}
}
impl ToASN1 for X509PublicKey {
type Error = X509EncodeErr;
fn to_asn1_class(&self, c: ASN1Class) -> Result<Vec<ASN1Block>,X509EncodeErr> {
let block = match self {
X509PublicKey::RSA(x) => encode_rsa_key(c, x)?,
X509PublicKey::DSA(x) => encode_dsa_key(c, x)?,
X509PublicKey::ECDSA(x) => encode_ecdsa_key(c, x)?,
};
Ok(vec![block])
}
}
impl FromASN1 for X509PublicKey {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block]) -> Result<(X509PublicKey, &[ASN1Block]), Self::Error>
{
let (block, rest) = v.split_first().ok_or(X509ParseError::NotEnoughData)?;
// SubjectPublicKeyInfo ::= SEQUENCE {
// algorithm AlgorithmIdentifier,
// subjectPublicKey BIT STRING }
if let &ASN1Block::Sequence(_, _, ref info) = block {
let (id, malginfo) = strip_algident(&info[0])?;
if id == oid!(1,2,840,113549,1,1,1) {
let key = decode_rsa_key(&info[1])?;
return Ok((X509PublicKey::RSA(key), rest));
}
if id == oid!(1,2,840,10040,4,1) {
if let Some(alginfo) = malginfo {
let key = decode_dsa_key(alginfo, &info[1])?;
return Ok((X509PublicKey::DSA(key), rest));
}
}
if id == oid!(1,2,840,10045,2,1) {
if let Some(alginfo) = malginfo {
let key = decode_ecdsa_key(alginfo, &info[1..])?;
return Ok((X509PublicKey::ECDSA(key), rest));
}
}
}
Err(X509ParseError::IllFormedKey)
}
}
//------------------------------------------------------------------------------
//
// RSA Public Key encoding / decoding
//
//------------------------------------------------------------------------------
fn encode_rsa_key(c: ASN1Class, x: &RSAPublic) -> Result<ASN1Block,ASN1EncodeErr>
{
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,113549,1,1,1));
let bstr = der_encode(x)?;
let objkey = ASN1Block::BitString(c, 0, bstr.len() * 8, bstr);
Ok(ASN1Block::Sequence(c, 0, vec![objoid, objkey]))
}
fn decode_rsa_key(x: &ASN1Block) -> Result<RSAPublic,X509ParseError>
{
if let &ASN1Block::BitString(_, _, _, ref bstr) = x {
der_decode(bstr).map_err(|x| X509ParseError::RSAError(x))
} else {
Err(X509ParseError::NotEnoughData)
}
}
//------------------------------------------------------------------------------
//
// DSA Public Key encoding / decoding
//
//------------------------------------------------------------------------------
fn encode_dsa_key(c: ASN1Class, x: &DSAPublic) -> Result<ASN1Block,ASN1EncodeErr>
{
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,10040,4,1));
let (mut objparams, bstr) = match x {
DSAPublic::DSAPublicL1024N160(x) => (x.params.to_asn1_class(c)?, der_encode(x)?),
DSAPublic::DSAPublicL2048N224(x) => (x.params.to_asn1_class(c)?, der_encode(x)?),
DSAPublic::DSAPublicL2048N256(x) => (x.params.to_asn1_class(c)?, der_encode(x)?),
DSAPublic::DSAPublicL3072N256(x) => (x.params.to_asn1_class(c)?, der_encode(x)?)
};
objparams.insert(0, objoid);
let headinfo = ASN1Block::Sequence(c, 0, objparams);
let objkey = ASN1Block::BitString(c, 0, bstr.len() * 8, bstr);
Ok(ASN1Block::Sequence(c, 0, vec![headinfo, objkey]))
}
fn decode_dsa_key(info: ASN1Block, key: &ASN1Block) -> Result<DSAPublic,X509ParseError>
{
if let ASN1Block::Sequence(_, _, pqg) = info {
if pqg.len() != 3 { return Err(X509ParseError::InvalidDSAInfo); }
let puint = decode_biguint(&pqg[0])?;
let guint = decode_biguint(&pqg[1])?;
let quint = decode_biguint(&pqg[2])?;
if puint.bits() > 2048 {
let p = U3072::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
let q = U3072::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
let g = U256::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
let params = L3072N256::new(p, q, g);
if let ASN1Block::BitString(_, _, _, ybstr) = key {
let blocks = from_der(ybstr)?;
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
if let ASN1Block::Integer(_,_,ynum) = iblk {
let y = U3072::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
let key = DSAPubKey::<L3072N256,U3072>::new(params, y);
let reskey = DSAPublic::DSAPublicL3072N256(key);
return Ok(reskey);
}
}
return Err(X509ParseError::InvalidDSAKey)
}
if puint.bits() > 1024 {
if guint.bits() > 224 {
let p = U2048::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
let q = U2048::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
let g = U256::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
let params = L2048N256::new(p, q, g);
if let ASN1Block::BitString(_, _, _, ybstr) = key {
let blocks = from_der(ybstr)?;
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
if let ASN1Block::Integer(_,_,ynum) = iblk {
let y = U2048::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
let key = DSAPubKey::<L2048N256,U2048>::new(params, y);
let reskey = DSAPublic::DSAPublicL2048N256(key);
return Ok(reskey);
}
}
return Err(X509ParseError::InvalidDSAKey)
} else {
let p = U2048::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
let q = U2048::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
let g = U256::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
let params = L2048N224::new(p, q, g);
if let ASN1Block::BitString(_, _, _, ybstr) = key {
let blocks = from_der(ybstr)?;
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
if let ASN1Block::Integer(_,_,ynum) = iblk {
let y = U2048::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
let key = DSAPubKey::<L2048N224,U2048>::new(params, y);
let reskey = DSAPublic::DSAPublicL2048N224(key);
return Ok(reskey);
}
}
return Err(X509ParseError::InvalidDSAKey)
}
}
let p = U1024::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
let q = U1024::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
let g = U192::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
let params = L1024N160::new(p, q, g);
if let ASN1Block::BitString(_, _, _, ybstr) = key {
let blocks = from_der(ybstr)?;
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
if let ASN1Block::Integer(_,_,ynum) = iblk {
let y = U1024::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
let key = DSAPubKey::<L1024N160,U1024>::new(params, y);
let reskey = DSAPublic::DSAPublicL1024N160(key);
return Ok(reskey);
}
}
return Err(X509ParseError::InvalidDSAKey)
}
Err(X509ParseError::InvalidDSAInfo)
}
//------------------------------------------------------------------------------
//
// ECDSA Public Key encoding
//
//------------------------------------------------------------------------------
fn encode_ecdsa_key(c: ASN1Class, x: &ECDSAPublic) -> Result<ASN1Block,ECDSAEncodeErr>
{
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,10045,2,1));
let (base_curve_oid, mut keyvec) = match x {
ECDSAPublic::ECCPublicP192(k) => (oid!(1,2,840,10045,3,1,1), k.to_asn1_class(c)?),
ECDSAPublic::ECCPublicP224(k) => (oid!(1,3,132,0,33), k.to_asn1_class(c)?),
ECDSAPublic::ECCPublicP256(k) => (oid!(1,2,840,10045,3,1,7), k.to_asn1_class(c)?),
ECDSAPublic::ECCPublicP384(k) => (oid!(1,3,132,0,34), k.to_asn1_class(c)?),
ECDSAPublic::ECCPublicP521(k) => (oid!(1,3,132,0,35), k.to_asn1_class(c)?),
};
let curve_oid = ASN1Block::ObjectIdentifier(c, 0, base_curve_oid);
let header = ASN1Block::Sequence(c, 0, vec![objoid, curve_oid]);
keyvec.insert(0, header);
Ok(ASN1Block::Sequence(c, 0, keyvec))
}
fn decode_ecdsa_key(info: ASN1Block, keybls: &[ASN1Block]) -> Result<ECDSAPublic,X509ParseError>
{
if let ASN1Block::ObjectIdentifier(_, _, oid) = info {
if oid == oid!(1,2,840,10045,3,1,1) {
let (res, _) = ECCPubKey::<P192>::from_asn1(keybls)?;
return Ok(ECDSAPublic::ECCPublicP192(res));
}
if oid == oid!(1,3,132,0,33) {
let (res, _) = ECCPubKey::<P224>::from_asn1(keybls)?;
return Ok(ECDSAPublic::ECCPublicP224(res));
}
if oid == oid!(1,2,840,10045,3,1,7) {
let (res, _) = ECCPubKey::<P256>::from_asn1(keybls)?;
return Ok(ECDSAPublic::ECCPublicP256(res));
}
if oid == oid!(1,3,132,0,34) {
let (res, _) = ECCPubKey::<P384>::from_asn1(keybls)?;
return Ok(ECDSAPublic::ECCPublicP384(res));
}
if oid == oid!(1,3,132,0,35) {
let (res, _) = ECCPubKey::<P521>::from_asn1(keybls)?;
return Ok(ECDSAPublic::ECCPublicP521(res));
}
}
Err(X509ParseError::UnknownEllipticCurve)
}
fn strip_algident(block: &ASN1Block)
-> Result<(OID, Option<ASN1Block>),X509ParseError>
{
match block {
&ASN1Block::ObjectIdentifier(_, _, ref oid) => {
Ok((oid.clone(), None))
}
&ASN1Block::Sequence(_, _, ref items) => {
let (oid, _) = strip_algident(&items[0])?;
Ok((oid, Some(items[1].clone())))
}
_ => Err(X509ParseError::IllFormedAlgoInfo)
}
}
fn decode_biguint(b: &ASN1Block) -> Result<BigUint,X509ParseError> {
match b {
&ASN1Block::Integer(_, _, ref v) => {
match v.to_biguint() {
Some(sn) => Ok(sn),
_ => Err(X509ParseError::InvalidDSAInfo)
}
}
_ =>
Err(X509ParseError::InvalidDSAInfo)
}
}

118
src/x509/validity.rs Normal file
View File

@@ -0,0 +1,118 @@
use chrono::{DateTime,Utc};
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
use x509::error::X509ParseError;
#[derive(Clone,Debug,PartialEq)]
pub struct Validity {
not_before: DateTime<Utc>,
not_after: DateTime<Utc>
}
fn decode_validity_data(bs: &ASN1Block) -> Result<Validity,X509ParseError> {
// Validity ::= SEQUENCE {
// notBefore Time,
// notAfter Time }
match bs {
&ASN1Block::Sequence(_, _, ref valxs) => {
if valxs.len() != 2 {
return Err(X509ParseError::IllFormedValidity);
}
let nb = get_time(&valxs[0])?;
let na = get_time(&valxs[1])?;
Ok(Validity{ not_before: nb, not_after: na })
}
_ =>
Err(X509ParseError::IllFormedValidity)
}
}
impl FromASN1 for Validity {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block])
-> Result<(Validity,&[ASN1Block]),X509ParseError>
{
match v.split_first() {
None =>
Err(X509ParseError::NotEnoughData),
Some((x, rest)) => {
let v = decode_validity_data(&x)?;
Ok((v, rest))
}
}
}
}
fn encode_validity_data(c: ASN1Class, v: &Validity) -> ASN1Block {
let mut vs = Vec::with_capacity(2);
vs.push(ASN1Block::GeneralizedTime(c, 0, v.not_before));
vs.push(ASN1Block::GeneralizedTime(c, 0, v.not_after));
ASN1Block::Sequence(c, 0, vs)
}
impl ToASN1 for Validity {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let block = encode_validity_data(c, self);
Ok(vec![block])
}
}
fn get_time(b: &ASN1Block) -> Result<DateTime<Utc>, X509ParseError> {
match b {
&ASN1Block::UTCTime(_, _, v) => Ok(v.clone()),
&ASN1Block::GeneralizedTime(_, _, v) => Ok(v.clone()),
_ =>
Err(X509ParseError::IllFormedValidity)
}
}
#[cfg(test)]
mod test {
use chrono::TimeZone;
use chrono::offset::LocalResult;
use quickcheck::{Arbitrary,Gen};
use rand::Rng;
use super::*;
fn arbitrary_date<G: Gen>(g: &mut G) -> DateTime<Utc> {
loop {
let y = g.gen_range(1900,3000);
let mo = g.gen_range(0,12);
let d = g.gen_range(0,31);
let h = g.gen_range(0,24);
let mi = g.gen_range(0,60);
let s = g.gen_range(0,60);
match Utc.ymd_opt(y,mo,d).and_hms_opt(h,mi,s) {
LocalResult::None =>
continue,
LocalResult::Single(x) =>
return x,
LocalResult::Ambiguous(x,_) =>
return x
}
}
}
impl Arbitrary for Validity {
fn arbitrary<G: Gen>(g: &mut G) -> Validity {
Validity {
not_before: arbitrary_date(g),
not_after: arbitrary_date(g)
}
}
}
quickcheck! {
fn validity_roundtrips(v: Validity) -> bool {
let bstr = encode_validity_data(ASN1Class::Universal, &v);
match decode_validity_data(&bstr) {
Err(_) => false,
Ok(v2) => v == v2
}
}
}
}

2
test-generator/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
dist/
dist-newstyle/

View File

@@ -0,0 +1,41 @@
module Database(
Database,
emptyDatabase,
generateNum, genSign
)
where
import Crypto.Random(DRG(..),SystemDRG)
import Data.Bits(shiftL,testBit)
import qualified Data.ByteString as S
import Data.Map.Strict(Map)
import qualified Data.Map.Strict as Map
type Database = (Map String [Integer], SystemDRG)
emptyDatabase :: SystemDRG -> Database
emptyDatabase g0 = (Map.empty, g0)
generateNum :: Database -> String -> Int -> (Integer, Database)
generateNum (db, rng0) varname size =
let (x, rng1) = randomBytesGenerate (size `div` 8) rng0
x' = integerize x
before = Map.findWithDefault [] varname db
in if length (filter (== x') before) < 10
then (x', (Map.insert varname (x':before) db, rng1))
else generateNum (db, rng1) varname size
genSign :: (Integer, Database) -> (Integer, Database)
genSign (x, (db, rng0)) =
let (n, rng1) = randomBytesGenerate 0 rng0
n' = integerize n
in if testBit n' 0 then (0 - x, (db, rng1)) else (x, (db, rng1))
integerize :: S.ByteString -> Integer
integerize = go 0
where
go acc bstr =
case S.uncons bstr of
Nothing -> acc
Just (v,rest) ->
go ((acc `shiftL` 8) + fromIntegral v) rest

View File

@@ -0,0 +1,192 @@
module ECDSATesting(
ecdsaTasks
)
where
import Crypto.Hash(SHA224(..),SHA256(..),SHA384(..),SHA512(..))
import Crypto.Number.Generate(generateBetween)
import Crypto.PubKey.ECC.ECDSA(PrivateKey(..),PublicKey(..),Signature(..),signWith)
import Crypto.PubKey.ECC.Generate(generate)
import Crypto.PubKey.ECC.Prim(scalarGenerate,pointAdd,pointNegate,pointDouble,pointBaseMul,pointMul,pointAddTwoMuls)
import Crypto.PubKey.ECC.Types(Curve,CurveName(..),Point(..),common_curve,curveSizeBits,ecc_n,getCurveByName)
import Crypto.Random(DRG(..),getRandomBytes,withDRG)
import qualified Data.ByteString as S
import qualified Data.Map.Strict as Map
import Math(showX,showBin)
import RFC6979(generateKStream)
import Task(Task(..))
import Utils(HashAlg(..),generateHash,runHash,showHash)
curves :: [(String, Curve)]
curves = [("P192", getCurveByName SEC_p192r1),
("P224", getCurveByName SEC_p224r1),
("P256", getCurveByName SEC_p256r1),
("P384", getCurveByName SEC_p384r1),
("P521", getCurveByName SEC_p521r1)]
negateTest :: String -> Curve -> Task
negateTest name curve = Task {
taskName = name ++ " point negation",
taskFile = "../testdata/ecc/negate/" ++ name ++ ".test",
taskTest = go,
taskCount = 1000
}
where
go (memory0, drg) =
let (scalar, drg') = withDRG drg (scalarGenerate curve)
point = pointBaseMul curve scalar
dbl = pointNegate curve point
in case (point, dbl) of
(PointO, _) -> go (memory0, drg')
(_, PointO) -> go (memory0, drg')
(Point basex basey, Point dblx dbly) ->
let res = Map.fromList [("x", showX basex), ("y", showX basey),
("a", showX dblx), ("b", showX dbly)]
in (res, scalar, (memory0, drg'))
doubleTest :: String -> Curve -> Task
doubleTest name curve = Task {
taskName = name ++ " point doubling",
taskFile = "../testdata/ecc/double/" ++ name ++ ".test",
taskTest = go,
taskCount = 1000
}
where
go (memory0, drg) =
let (scalar, drg') = withDRG drg (scalarGenerate curve)
point = pointBaseMul curve scalar
dbl = pointDouble curve point
in case (point, dbl) of
(PointO, _) -> go (memory0, drg')
(_, PointO) -> go (memory0, drg')
(Point basex basey, Point dblx dbly) ->
let res = Map.fromList [("x", showX basex), ("y", showX basey),
("a", showX dblx), ("b", showX dbly)]
in (res, scalar, (memory0, drg'))
addTest :: String -> Curve -> Task
addTest name curve = Task {
taskName = name ++ " point addition",
taskFile = "../testdata/ecc/add/" ++ name ++ ".test",
taskTest = go,
taskCount = 1000
}
where
go (memory0, drg0) =
let (scalar1, drg1) = withDRG drg0 (scalarGenerate curve)
(scalar2, drg2) = withDRG drg1 (scalarGenerate curve)
point1 = pointBaseMul curve scalar1
point2 = pointBaseMul curve scalar2
pointr = pointAdd curve point1 point2
in case (point1, point2, pointr) of
(Point x1 y1, Point x2 y2, Point xr yr) ->
let res = Map.fromList [("x", showX x1), ("y", showX y1),
("u", showX x2), ("v", showX y2),
("a", showX xr), ("b", showX yr)]
in (res, scalar1, (memory0, drg2))
_ ->
go (memory0, drg2)
scaleTest :: String -> Curve -> Task
scaleTest name curve = Task {
taskName = name ++ " point scaling",
taskFile = "../testdata/ecc/scale/" ++ name ++ ".test",
taskTest = go,
taskCount = 1000
}
where
go (memory0, drg0) =
let (scalar0, drg1) = withDRG drg0 (scalarGenerate curve)
(scalar1, drg2) = withDRG drg1 (scalarGenerate curve)
(negbs, drg3) = randomBytesGenerate 1 drg2
[negbyte] = S.unpack negbs
k = if odd negbyte then scalar1 else -scalar1
point = pointBaseMul curve scalar0
respnt = pointMul curve k point
in case (point, respnt) of
(PointO, _) -> go (memory0, drg3)
(_, PointO) -> go (memory0, drg3)
(Point basex basey, Point resx resy) ->
let res = Map.fromList [("x", showX basex), ("y", showX basey),
("k", showX k),
("a", showX resx), ("b", showX resy)]
in (res, scalar0, (memory0, drg3))
addScaleTest :: String -> Curve -> Task
addScaleTest name curve = Task {
taskName = name ++ " point addition of two scalings",
taskFile = "../testdata/ecc/add_scale2/" ++ name ++ ".test",
taskTest = go,
taskCount = 1000
}
where
go (memory0, drg0) =
let (scalar1, drg1) = withDRG drg0 (scalarGenerate curve)
(scalar2, drg2) = withDRG drg1 (scalarGenerate curve)
(n, drg3) = withDRG drg2 (scalarGenerate curve)
(m, drg4) = withDRG drg3 (scalarGenerate curve)
point1 = pointBaseMul curve scalar1
point2 = pointBaseMul curve scalar2
pointr = pointAddTwoMuls curve n point1 m point2
in case (point1, point2, pointr) of
(Point x1 y1, Point x2 y2, Point xr yr) ->
let res = Map.fromList [("x", showX x1), ("y", showX y1),
("p", showX x2), ("q", showX y2),
("n", showX n), ("m", showX m),
("r", showX xr), ("s", showX yr)]
in (res, scalar1, (memory0, drg4))
_ ->
go (memory0, drg4)
signTest :: String -> Curve -> Task
signTest name curve = Task {
taskName = name ++ " curve signing",
taskFile = "../testdata/ecc/sign/" ++ name ++ ".test",
taskTest = go,
taskCount = 1000
}
where
go (memory0, drg0) =
let ((pub, priv), drg1) = withDRG drg0 (generate curve)
(msg, drg2) = withDRG drg1 $ do x <- generateBetween 0 256
getRandomBytes (fromIntegral x)
(hash, drg3) = withDRG drg2 generateHash
n = ecc_n (common_curve curve)
PrivateKey _ d = priv
kStream = generateKStream hash msg d n (curveSizeBits curve)
findGoodK stream =
case stream of
[] ->
go (memory0, drg3)
(k : restks) ->
case signWith' k priv hash msg of
Nothing ->
findGoodK restks
Just sig ->
let PublicKey _ (Point x y) = pub
res = Map.fromList [("d", showX d), ("k", showX k),
("x", showX x), ("y", showX y),
("m", showBin msg), ("h", showHash hash),
("n", showBin (runHash hash msg)),
("r", showX (sign_r sig)),
("s", showX (sign_s sig))]
in (res, d, (memory0, drg3))
in findGoodK kStream
signWith' :: Integer -> PrivateKey -> HashAlg -> S.ByteString -> Maybe Signature
signWith' k priv Sha224 msg = signWith k priv SHA224 msg
signWith' k priv Sha256 msg = signWith k priv SHA256 msg
signWith' k priv Sha384 msg = signWith k priv SHA384 msg
signWith' k priv Sha512 msg = signWith k priv SHA512 msg
generateTasks :: (String, Curve) -> [Task]
generateTasks (name, curve) = [negateTest name curve,
doubleTest name curve,
addTest name curve,
scaleTest name curve,
addScaleTest name curve,
signTest name curve]
ecdsaTasks :: [Task]
ecdsaTasks = concatMap generateTasks curves

40
test-generator/Main.hs Normal file
View File

@@ -0,0 +1,40 @@
{-# LANGUAGE LambdaCase #-}
import Control.Concurrent(forkIO)
import Control.Concurrent.Chan(Chan,newChan,readChan,writeChan)
import Control.Concurrent.MVar(MVar,newMVar,modifyMVar)
import Control.Exception(SomeException,catch)
import Control.Monad(replicateM_,void)
import Crypto.Random(SystemDRG,getSystemDRG)
import ECDSATesting(ecdsaTasks)
import GHC.Conc(getNumCapabilities)
import RFC6979(rfcTasks)
import System.Console.AsciiProgress
import Task(Task, runTask)
taskExecutor :: MVar [Task] -> Chan () -> SystemDRG -> IO SystemDRG
taskExecutor taskList done gen =
do mnext <- modifyMVar taskList (\case
[] -> return ([], Nothing)
(x:xs) -> return (xs, Just x))
case mnext of
Nothing -> do writeChan done ()
return gen
Just x -> do gen' <- runTask gen x
taskExecutor taskList done gen'
spawnExecutor :: MVar [Task] -> Chan () -> IO ()
spawnExecutor tasks done =
do gen <- getSystemDRG
void (forkIO (catch (void (taskExecutor tasks done gen)) handler))
where
handler :: SomeException -> IO ()
handler e = putStrLn ("ERROR: " ++ show e)
main :: IO ()
main = displayConsoleRegions $
do
executors <- getNumCapabilities
done <- newChan
tasks <- newMVar (ecdsaTasks ++ rfcTasks)
replicateM_ executors (spawnExecutor tasks done)
replicateM_ executors (void $ readChan done)

166
test-generator/Math.hs Normal file
View File

@@ -0,0 +1,166 @@
{-# LANGUAGE RecordWildCards #-}
module Math(
extendedGCD
, barrett, computeK, base
, modulate, modulate'
, isqrt
, divmod
, showX, showB, showBin
)
where
import Data.Bits(shiftL,shiftR,(.&.))
import qualified Data.ByteString as S
import GHC.Integer.GMP.Internals(recipModInteger)
import Numeric(showHex)
data AlgState = AlgState {
u :: Integer,
v :: Integer,
bigA :: Integer,
bigB :: Integer,
bigC :: Integer,
bigD :: Integer
}
printState :: AlgState -> IO ()
printState a =
do putStrLn ("u: " ++ showX (u a))
putStrLn ("v: " ++ showX (v a))
putStrLn ("A: " ++ showX (bigA a))
putStrLn ("B: " ++ showX (bigB a))
putStrLn ("C: " ++ showX (bigC a))
putStrLn ("D: " ++ showX (bigD a))
extendedGCD :: Integer -> Integer -> (Integer, Integer, Integer)
extendedGCD x y = (a, b, g * (v finalState))
where
(x', y', g, initState) = initialState x y 1
finalState = runAlgorithm x' y' initState
a = bigC finalState
b = bigD finalState
initialState :: Integer -> Integer -> Integer -> (Integer, Integer, Integer, AlgState)
initialState x y g | even x && even y = initialState (x `div` 2) (y `div` 2) (g * 2)
| otherwise = (x, y, g, AlgState x y 1 0 0 1)
runAlgorithm :: Integer -> Integer -> AlgState -> AlgState
runAlgorithm x y state | u state == 0 = state
| otherwise = runAlgorithm x y state6
where
state4 = step4 x y state
state5 = step5 x y state4
state6 = step6 state5
step4 :: Integer -> Integer -> AlgState -> AlgState
step4 x y input@AlgState{..} | even u = step4 x y input'
| otherwise = input
where
input' = AlgState u' v bigA' bigB' bigC bigD
u' = u `div` 2
bigA' | even bigA && even bigB = bigA `div` 2
| otherwise = (bigA + y) `div` 2
bigB' | even bigA && even bigB = bigB `div` 2
| otherwise = (bigB - x) `div` 2
step5 :: Integer -> Integer -> AlgState -> AlgState
step5 x y input@AlgState{..} | even v = step5 x y input'
| otherwise = input
where
input' = AlgState u v' bigA bigB bigC' bigD'
v' = v `div` 2
bigC' | even bigC && even bigD = bigC `div` 2
| otherwise = (bigC + y) `div` 2
bigD' | even bigC && even bigD = bigD `div` 2
| otherwise = (bigD - x) `div` 2
step6 :: AlgState -> AlgState
step6 AlgState{..}
| u >= v = AlgState (u - v) v (bigA - bigC) (bigB - bigD) bigC bigD
| otherwise = AlgState u (v - u) bigA bigB (bigC - bigA) (bigD - bigB)
barrett :: Integer -> Integer
barrett m = (base ^ (2 * k)) `div` m
where
k = computeK m
computeK :: Integer -> Int
computeK v = go 0 1
where
go k acc | v <= acc = k
| otherwise = go (k + 1) (acc * base)
base :: Integer
base = 2 ^ (64 :: Integer)
modulate :: Integer -> Int -> Integer
modulate x size = x `mod` (2 ^ size)
modulate' :: Integer -> Int -> Integer
modulate' x size = signum x * (abs x `mod` (2 ^ size))
showX :: (Integral a, Show a) => a -> String
showX x | x < 0 = "-" ++ showX (abs x)
| otherwise = showHex x ""
showB :: Bool -> String
showB False = "0"
showB True = "1"
showBin :: S.ByteString -> String
showBin bstr =
case S.uncons bstr of
Nothing -> ""
Just (x,rest) ->
showX (x `shiftR` 4) ++ showX (x .&. 0xF) ++ showBin rest
isqrt :: Int -> Integer -> Integer
isqrt bits val = final
where
bit' = part1 (1 `shiftL` (bits - 2))
--
part1 x | x > val = part1 (x `shiftR` 2)
| otherwise = x
--
final = loop val 0 bit'
--
loop num res bit
| bit == 0 = res
| otherwise = let (num', res') = adjust num res bit
in loop num' (res' `shiftR` 1) (bit `shiftR` 2)
adjust num res bit
| num >= (res + bit) = (num - (res + bit), res + (bit `shiftL` 1))
| otherwise = (num, res)
divmod :: Integer -> Integer -> Integer -> Maybe Integer
divmod x y m =
let y' = y `mod` m
in case recipModInteger y' m of
0 -> Nothing
i -> Just ((x * i) `mod` m)
_run :: Integer -> Integer -> IO ()
_run inputx inputy =
do let (x, y, g, initState) = initialState inputx inputy 1
finalState <- go x y initState
putStrLn ("-- FINAL STATE -----------------------")
printState finalState
putStrLn ("Final value: " ++ showX (g * v finalState))
putStrLn ("-- RUN ------")
printState (runAlgorithm x y initState)
putStrLn ("-- NORMAL ------")
let (a, b, v) = extendedGCD inputx inputy
putStrLn ("a: " ++ showX a)
putStrLn ("b: " ++ showX b)
putStrLn ("v: " ++ showX v)
where
go x y state =
do putStrLn "-- STATE -----------------------------"
printState state
if u state == 0
then return state
else do let state' = step4 x y state
state'' = step5 x y state'
state''' = step6 state''
go x y state'''

112
test-generator/RFC6979.hs Normal file
View File

@@ -0,0 +1,112 @@
module RFC6979
-- (
-- rfcTasks
-- )
where
import Crypto.Hash(SHA224(..),SHA256(..),SHA384(..),SHA512(..))
import Crypto.MAC.HMAC(HMAC,hmac)
import Crypto.Number.Generate(generateBetween)
import Crypto.Random(getRandomBytes,withDRG)
import Data.Bits(shiftL,shiftR,(.&.))
import qualified Data.ByteArray as B
import qualified Data.ByteString as S
import Data.Char(toUpper)
import qualified Data.Map.Strict as Map
import Math(showBin,showX)
import Task(Task(..))
import Utils(HashAlg(..), runHash)
runHMAC :: HashAlg -> S.ByteString -> S.ByteString -> S.ByteString
runHMAC Sha224 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA224))
runHMAC Sha256 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA256))
runHMAC Sha384 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA384))
runHMAC Sha512 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA512))
generateKStream :: HashAlg -> S.ByteString -> Integer -> Integer -> Int -> [Integer]
generateKStream alg m x q qlen = nextK bigK2 bigV2
where
h1 = runHash alg m
bigV0 = S.replicate (S.length h1) 0x01
bigK0 = S.replicate (S.length h1) 0x00
seed1 = S.concat [bigV0, S.singleton 0x00, int2octets qlen x, bits2octets qlen q h1]
bigK1 = runHMAC alg bigK0 seed1
bigV1 = runHMAC alg bigK1 bigV0
seed2 = S.concat [bigV1, S.singleton 0x01, int2octets qlen x, bits2octets qlen q h1]
bigK2 = runHMAC alg bigK1 seed2
bigV2 = runHMAC alg bigK2 bigV1
--
nextK bigK bigV =
let (bigV', bigT) = buildT bigK bigV S.empty
k = bits2int qlen bigT
bigK' = runHMAC alg bigK (bigV' `S.append` S.singleton 0)
bigV'' = runHMAC alg bigK' bigV'
in if k < q then (k : nextK bigK' bigV'') else nextK bigK' bigV''
buildT bigK bigV bigT
| S.length bigT * 8 >= qlen = (bigV, bigT)
| otherwise =
let bigV' = runHMAC alg bigK bigV
in buildT bigK bigV' (bigT `S.append` bigV')
bits2int :: Int -> S.ByteString -> Integer
bits2int qlen bstr = reduce (go bstr 0)
where
reduce x =
let vlen = S.length bstr * 8
in if vlen > qlen
then x `shiftR` (vlen - qlen)
else x
--
go x acc =
case S.uncons x of
Nothing -> acc
Just (v, rest) ->
go rest ((acc `shiftL` 8) + fromIntegral v)
int2octets :: Int -> Integer -> S.ByteString
int2octets lenBits x =
S.pack (pad (rlen `div` 8) (reverse (go x)))
where
rlen = 8 * ((lenBits + 7) `div` 8)
pad target ls
| length ls > target = drop (length ls - target) ls
| length ls < target = pad target (0 : ls)
| otherwise = ls
--
go 0 = []
go v = (fromIntegral (v .&. 0xFF)) : go (v `shiftR` 8)
bits2octets :: Int -> Integer -> S.ByteString -> S.ByteString
bits2octets qlen q bstr =
let z1 = bits2int qlen bstr
z2 = if z1 > q then z1 - q else z1
in int2octets qlen z2
rfc6979Test :: HashAlg -> Task
rfc6979Test alg = Task {
taskName = name ++ " RFC 6979 deterministic k-generation",
taskFile = "../testdata/rfc6979/" ++ name ++ ".test",
taskTest = go,
taskCount = 1000
}
where
name = map toUpper (show alg)
go (memory0, drg0) =
let (qlen, drg1) = withDRG drg0 $ generateBetween 160 521
(key, drg2) = withDRG drg1 $ generateBetween 1 ((2 ^ qlen) - 1)
(q, drg3) = withDRG drg2 $ generateBetween 1 ((2 ^ qlen) - 1)
(dataSize, drg4) = withDRG drg3 $ generateBetween 1 1024
(msg, drg5) = withDRG drg4 $ getRandomBytes (fromIntegral dataSize)
h1 = runHash alg msg
ks = generateKStream alg msg key q (fromIntegral qlen)
res = Map.fromList [("q", showX q), ("l", showX qlen),
("x", showX key), ("h", showBin h1),
("k", showX (ks !! 0)),
("y", showX (ks !! 1)),
("z", showX (ks !! 2))]
in (res, qlen, (memory0, drg5))
rfcTasks :: [Task]
rfcTasks = [rfc6979Test Sha224, rfc6979Test Sha256,
rfc6979Test Sha384, rfc6979Test Sha512]

50
test-generator/Task.hs Normal file
View File

@@ -0,0 +1,50 @@
module Task(
Test,
Task(..),
runTask
)
where
import Control.Monad(foldM, forM_)
import Crypto.Random(SystemDRG)
import qualified Data.Map.Strict as Map
import Database
import System.Console.AsciiProgress
import System.Directory(createDirectoryIfMissing,doesFileExist)
import System.FilePath(takeDirectory)
import System.IO(Handle,IOMode(..),hPutStrLn,withFile)
type Test = Database -> (Map.Map String String, Integer, Database)
data Task = Task {
taskName :: String,
taskFile :: FilePath,
taskTest :: Test,
taskCount :: Int
}
runTask :: SystemDRG -> Task -> IO SystemDRG
runTask gen task =
do createDirectoryIfMissing True (takeDirectory (taskFile task))
alreadyDone <- doesFileExist (taskFile task)
if alreadyDone
then return gen
else withFile (taskFile task) WriteMode $ \ hndl ->
do pg <- newProgressBar def{ pgOnCompletion = Just ("Finished " ++ taskName task),
pgFormat = taskName task ++ " " ++ pgFormat def,
pgTotal = fromIntegral (taskCount task) }
let initval = emptyDatabase gen
(_, gen') <- foldM (writer hndl pg (taskTest task)) initval [0..taskCount task]
return gen'
where
writer :: Handle -> ProgressBar -> Test -> Database -> Int -> IO Database
writer hndl pg runner db x =
do let (output, key, acc@(db',gen')) = runner db
before = Map.findWithDefault [] "RESULT" db'
if length (filter (== key) before) >= 10
then writer hndl pg runner acc x
else do forM_ (Map.toList output) $ \ (outkey, val) ->
hPutStrLn hndl (outkey ++ ": " ++ val)
tick pg
return (Map.insert "RESULT" (key : before) db', gen')

34
test-generator/Utils.hs Normal file
View File

@@ -0,0 +1,34 @@
module Utils(HashAlg(..), generateHash, runHash, showHash)
where
import Crypto.Hash(Digest,SHA224(..),SHA256(..),SHA384(..),SHA512(..),hash)
import Crypto.Number.Generate(generateBetween)
import Crypto.Random(MonadRandom)
import qualified Data.ByteArray as B
import qualified Data.ByteString as S
import Math(showX)
data HashAlg = Sha224 | Sha256 | Sha384 | Sha512
deriving (Eq, Show)
runHash :: HashAlg -> S.ByteString -> S.ByteString
runHash Sha224 x = S.pack (B.unpack (hash x :: Digest SHA224))
runHash Sha256 x = S.pack (B.unpack (hash x :: Digest SHA256))
runHash Sha384 x = S.pack (B.unpack (hash x :: Digest SHA384))
runHash Sha512 x = S.pack (B.unpack (hash x :: Digest SHA512))
showHash :: HashAlg -> String
showHash Sha224 = showX (224 :: Int)
showHash Sha256 = showX (256 :: Int)
showHash Sha384 = showX (384 :: Int)
showHash Sha512 = showX (512 :: Int)
generateHash :: MonadRandom m => m HashAlg
generateHash =
do x <- generateBetween 0 3
case x of
0 -> return Sha224
1 -> return Sha256
2 -> return Sha384
3 -> return Sha512
_ -> fail "Incompatible random number"

34
test-generator/gcd.hs Normal file
View File

@@ -0,0 +1,34 @@
import Numeric
data Set = Set { r :: Integer, s :: Integer, t :: Integer }
step :: Set -> Set -> Set
step old new = Set r' s' t'
where
quotient = r old `div` r new
r' = r old - (r new * quotient)
s' = s old - (s new * quotient)
t' = t old - (t new * quotient)
run :: Integer -> Integer -> IO Set
run self rhs = go (Set self 1 0) (Set rhs 0 1)
where
go old new | r new == 0 =
do putStrLn "------------------------------"
putStrLn ("res_r: " ++ showX (r old))
putStrLn ("res_s: " ++ showX (s old))
putStrLn ("res_t: " ++ showX (t old))
return old
| otherwise =
do putStrLn "------------------------------"
putStrLn ("old_r: " ++ showX (r old))
putStrLn ("old_s: " ++ showX (s old))
putStrLn ("old_t: " ++ showX (t old))
putStrLn ("new_r: " ++ showX (r new))
putStrLn ("new_s: " ++ showX (s new))
putStrLn ("new_t: " ++ showX (t new))
go new (step old new)
showX :: Integer -> String
showX x | x < 0 = "-" ++ showX (abs x)
| otherwise = showHex x ""

View File

@@ -0,0 +1,28 @@
cabal-version: >=1.10
-- Initial package description 'test-generator.cabal' generated by 'cabal
-- init'. For further documentation, see
-- http://haskell.org/cabal/users-guide/
name: test-generator
version: 0.1.0.0
synopsis: Test generation helper
-- description:
homepage: http://github.com/acw
-- bug-reports:
license: ISC
license-file: ../LICENSE
author: Adam Wick
maintainer: awick@uhsure.com
-- copyright:
category: Testing
build-type: Simple
extra-source-files: CHANGELOG.md
executable gen-tests
main-is: Main.hs
other-modules: Database, ECDSATesting, Math, RFC6979, Task, Utils
-- other-extensions:
build-depends: base >=4.11 && < 4.14, ascii-progress, bytestring, containers, cryptonite, directory, filepath, integer-gmp, memory, random
hs-source-dirs: .
default-language: Haskell2010
ghc-options: -Wall -O2 -threaded -rtsopts -with-rtsopts=-N

6006
testdata/ecc/add/P192.test vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/ecc/add/P224.test vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/ecc/add/P256.test vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/ecc/add/P384.test vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/ecc/add/P521.test vendored Normal file

File diff suppressed because it is too large Load Diff

8008
testdata/ecc/add_scale2/P192.test vendored Normal file

File diff suppressed because it is too large Load Diff

8008
testdata/ecc/add_scale2/P224.test vendored Normal file

File diff suppressed because it is too large Load Diff

8008
testdata/ecc/add_scale2/P256.test vendored Normal file

File diff suppressed because it is too large Load Diff

8008
testdata/ecc/add_scale2/P384.test vendored Normal file

File diff suppressed because it is too large Load Diff

8008
testdata/ecc/add_scale2/P521.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/double/P192.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/double/P224.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/double/P256.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/double/P384.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/double/P521.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/negate/P192.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/negate/P224.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/negate/P256.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/negate/P384.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/negate/P521.test vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/ecc/scale/P192.test vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/ecc/scale/P224.test vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/ecc/scale/P256.test vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/ecc/scale/P384.test vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/ecc/scale/P521.test vendored Normal file

File diff suppressed because it is too large Load Diff

9009
testdata/ecc/sign/P192.test vendored Normal file

File diff suppressed because it is too large Load Diff

9009
testdata/ecc/sign/P224.test vendored Normal file

File diff suppressed because it is too large Load Diff

9009
testdata/ecc/sign/P256.test vendored Normal file

File diff suppressed because it is too large Load Diff

9009
testdata/ecc/sign/P384.test vendored Normal file

File diff suppressed because it is too large Load Diff

9009
testdata/ecc/sign/P521.test vendored Normal file

File diff suppressed because it is too large Load Diff

7007
testdata/rfc6979/SHA224.test vendored Normal file

File diff suppressed because it is too large Load Diff

7007
testdata/rfc6979/SHA256.test vendored Normal file

File diff suppressed because it is too large Load Diff

7007
testdata/rfc6979/SHA384.test vendored Normal file

File diff suppressed because it is too large Load Diff

7007
testdata/rfc6979/SHA512.test vendored Normal file

File diff suppressed because it is too large Load Diff

BIN
testdata/x509/dsa2048-1.der vendored Normal file

Binary file not shown.

BIN
testdata/x509/dsa2048-2.der vendored Normal file

Binary file not shown.

BIN
testdata/x509/dsa3072-1.der vendored Normal file

Binary file not shown.

BIN
testdata/x509/dsa3072-2.der vendored Normal file

Binary file not shown.

BIN
testdata/x509/ec384-1.der vendored Normal file

Binary file not shown.

BIN
testdata/x509/ec384-2.der vendored Normal file

Binary file not shown.

BIN
testdata/x509/ec384-3.der vendored Normal file

Binary file not shown.

BIN
testdata/x509/rsa2048-1.der vendored Normal file

Binary file not shown.

BIN
testdata/x509/rsa2048-2.der vendored Normal file

Binary file not shown.

BIN
testdata/x509/rsa4096-1.der vendored Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More