Compare commits
68 Commits
better_rsa
...
sha
| Author | SHA1 | Date | |
|---|---|---|---|
| 82bb499be3 | |||
| 20c65b93bf | |||
| 7c45f898ab | |||
| c675aaa5f6 | |||
| 6d4c9c4f50 | |||
| a34d8dc88b | |||
| b59653de57 | |||
| 3eee154fe1 | |||
| 0b4d84b038 | |||
| 54687cb602 | |||
| 1bac2010b1 | |||
| 818b006521 | |||
| bae1c93c54 | |||
| ef3174f224 | |||
| 89c8705779 | |||
| 080c8f18e2 | |||
| 060b82b351 | |||
| ba2ceee725 | |||
| 4d2e43620a | |||
| c5850b4d01 | |||
| a19c1ee124 | |||
| 2145fb47fa | |||
| 2912c72a07 | |||
| 23a79300c8 | |||
| 0e6664f232 | |||
| 4ce8797da2 | |||
| 7f2b509640 | |||
| b0885722a8 | |||
| 83cdd8ef4c | |||
| 2f395721bc | |||
| 2b63dfa376 | |||
| fc09ff48a2 | |||
| c9f418feff | |||
| ac380d08af | |||
| 25746af626 | |||
| 16cf6172ce | |||
| d2bdbd37fe | |||
| e6e3789127 | |||
| 8bca480e47 | |||
| b42902e6ab | |||
| 44618c2e2f | |||
| 4c03ab6648 | |||
| 1b2d7db1e0 | |||
| 9cf0b587b2 | |||
| d459850c54 | |||
| 6c61e1c56c | |||
| aaa8dc3497 | |||
| ad484877cf | |||
| 1eba2d1709 | |||
| 29872fa47a | |||
| 031b4be14e | |||
| 8c87f945a1 | |||
| 6d2c803f2b | |||
| 8a7e604fbd | |||
| cfc06c3b56 | |||
| 40a5793089 | |||
| 026b321f7c | |||
| 887c90202a | |||
| 6613f85ff3 | |||
| 22b4fcbd94 | |||
| e4f67f0918 | |||
| 68ddc7096b | |||
| 54c5244bc5 | |||
| 06d3391748 | |||
| 3a0d08d572 | |||
| 1d1ca3d817 | |||
| 69cef498f2 | |||
| 47fae77a4f |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -22,4 +22,5 @@ Cargo.lock
|
|||||||
FlameGraph
|
FlameGraph
|
||||||
*.user_stacks
|
*.user_stacks
|
||||||
**/.ghc.environment.*
|
**/.ghc.environment.*
|
||||||
tests/rsa/dist*
|
|
||||||
|
test.ed25519
|
||||||
@@ -9,15 +9,12 @@ license-file = "LICENSE"
|
|||||||
repository = "https://github.com/acw/simple_crypto"
|
repository = "https://github.com/acw/simple_crypto"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "^1.2.7"
|
base64 = "^0.10.1"
|
||||||
|
byteorder = "^1.3.1"
|
||||||
chrono = "^0.4.6"
|
chrono = "^0.4.6"
|
||||||
cryptonum = { path = "cryptonum" }
|
cryptonum = { path = "cryptonum" }
|
||||||
digest = "^0.8.0"
|
|
||||||
hmac = "^0.7.0"
|
|
||||||
num = "^0.2.0"
|
num = "^0.2.0"
|
||||||
rand = "^0.6.0"
|
rand = "^0.6.5"
|
||||||
sha-1 = "^0.8.1"
|
|
||||||
sha2 = "^0.8.0"
|
|
||||||
simple_asn1 = "^0.2.0"
|
simple_asn1 = "^0.2.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
- Build RSA test cases from Haskell examples
|
|
||||||
- Build DSA test cases from Haskell examples
|
|
||||||
- Add negative test cases (RSA, DSA, ECDSA)
|
- Add negative test cases (RSA, DSA, ECDSA)
|
||||||
- Make Point::double_scalar_mult() not truly awful
|
- Make Point::double_scalar_mult() not truly awful
|
||||||
- Use std::Default instead of the bespoke default() in Point?
|
- Use std::Default instead of the bespoke default() in Point?
|
||||||
@@ -8,3 +6,6 @@
|
|||||||
- De-macro. Surely some of this stuff could be turned into trait invocations?
|
- De-macro. Surely some of this stuff could be turned into trait invocations?
|
||||||
- Test cases for key generation
|
- Test cases for key generation
|
||||||
- Better, timing-resistant ECC point math
|
- Better, timing-resistant ECC point math
|
||||||
|
- Make the x.509 library not terrible
|
||||||
|
- Ability to generate a SSH public key line / file
|
||||||
|
- Extend SSH examples with public key reading/writing
|
||||||
Submodule cryptonum updated: 037413ad15...666378b14b
@@ -1,7 +1,42 @@
|
|||||||
|
//! If you want to use this module to generate keys, which you really
|
||||||
|
//! really shouldn't, there are two ways to do so, depending on whether
|
||||||
|
//! you've previously agreed on a set of DSA parameters for this key
|
||||||
|
//! pair. If you haven't, you can generate the parameters using a good
|
||||||
|
//! random number generator.
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use simple_crypto::dsa::{DSAKeyPair,DSAParameters,L2048N256};
|
||||||
|
//! use simple_crypto::sha::SHA224;
|
||||||
|
//!
|
||||||
|
//! // Generate a set of DSA parameters, assuming you don't have
|
||||||
|
//! // them already
|
||||||
|
//! let mut rng = rand::rngs::OsRng::new().unwrap();
|
||||||
|
//! let params = L2048N256::generate(&mut rng);
|
||||||
|
//!
|
||||||
|
//! // Given those parameters, you can generate a key pair like so:
|
||||||
|
//! let kp = DSAKeyPair::<L2048N256>::generate(¶ms, &mut rng);
|
||||||
|
//! // Keeping in mind that you can re-use the parameters across multiple
|
||||||
|
//! // keys, and that their secrecy isn't paramout for the security of the
|
||||||
|
//! // algorithm.
|
||||||
|
//!
|
||||||
|
//! // Now that you have this key pair, you can sign and verify messages
|
||||||
|
//! // using it. For example, to sign the vector [0,1,2,3,4] with SHA224
|
||||||
|
//! // and then verify that signature, we would write:
|
||||||
|
//! let msg = vec![0,1,2,3,4];
|
||||||
|
//! let sig = kp.private.sign::<SHA224>(&msg);
|
||||||
|
//! assert!( kp.public.verify::<SHA224>(&msg, &sig) );
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
|
||||||
mod errors;
|
mod errors;
|
||||||
mod params;
|
mod params;
|
||||||
mod private;
|
mod private;
|
||||||
mod public;
|
mod public;
|
||||||
|
/// Support for RFC6979 signing, which provides a secure way to generate
|
||||||
|
/// signatures without the use of a random number generator. This is used
|
||||||
|
/// in DSA signing as well as in ECDSA signing, but appears here because
|
||||||
|
/// ... well, because it was written for DSA first, both historically
|
||||||
|
/// (I think) and by me.
|
||||||
pub mod rfc6979;
|
pub mod rfc6979;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
@@ -13,27 +48,41 @@ pub use self::public::*;
|
|||||||
use cryptonum::unsigned::*;
|
use cryptonum::unsigned::*;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand::distributions::Standard;
|
use rand::distributions::Standard;
|
||||||
|
use super::KeyPair;
|
||||||
|
|
||||||
pub struct DSAKeyPair<P,L,N>
|
/// A DSA key pair, for use in signing and signature verification. Note
|
||||||
|
/// that you probably shouldn't be using DSA any more; ECDSA or ED25519
|
||||||
|
/// are probably better options.
|
||||||
|
///
|
||||||
|
/// DSA key pairs are parameterized by their DSA parameters, so that
|
||||||
|
/// you can't accidentally use them in the wrong place.
|
||||||
|
pub struct DSAKeyPair<P: DSAParameters>
|
||||||
{
|
{
|
||||||
pub private: DSAPrivKey<P,N>,
|
pub private: DSAPrivateKey<P>,
|
||||||
pub public: DSAPubKey<P,L>
|
pub public: DSAPublicKey<P>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DSAKeyGeneration
|
impl<P: DSAParameters> KeyPair for DSAKeyPair<P>
|
||||||
{
|
{
|
||||||
type Params;
|
type Private = DSAPrivateKey<P>;
|
||||||
|
type Public = DSAPublicKey<P>;
|
||||||
|
|
||||||
fn generate<G: Rng>(params: &Self::Params, rng: &mut G) -> Self;
|
fn new(public: DSAPublicKey<P>, private: DSAPrivateKey<P>) -> DSAKeyPair<P>
|
||||||
|
{
|
||||||
|
DSAKeyPair{ private, public }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! generate_dsa_pair {
|
macro_rules! generate_dsa_pair {
|
||||||
($ptype: ident, $ltype: ident, $ntype: ident, $nbig: ident) => {
|
($ptype: ident, $ltype: ident, $ntype: ident, $nbig: ident) => {
|
||||||
impl DSAKeyGeneration for DSAKeyPair<$ptype,$ltype,$ntype>
|
impl DSAKeyPair<$ptype>
|
||||||
{
|
{
|
||||||
type Params = $ptype;
|
/// Generate a DSA key pair using the given parameters and random
|
||||||
|
/// number generator. Please make sure that the RNG you're using
|
||||||
fn generate<G: Rng>(params: &$ptype, rng: &mut G) -> Self
|
/// is suitable for key generators (look for the term "cryptographic"
|
||||||
|
/// or "crypto strong" in its documentation, or see if it matches
|
||||||
|
/// any of the NIST-suggested RNG algorithms).
|
||||||
|
pub fn generate<G: Rng>(params: &$ptype, rng: &mut G) -> Self
|
||||||
{
|
{
|
||||||
// 1. N = len(q); L = len(p);
|
// 1. N = len(q); L = len(p);
|
||||||
let n = $ptype::n_size();
|
let n = $ptype::n_size();
|
||||||
@@ -45,7 +94,7 @@ macro_rules! generate_dsa_pair {
|
|||||||
// strength of requested_security_strength or more. If an ERROR
|
// strength of requested_security_strength or more. If an ERROR
|
||||||
// indication is returned, then return an ERROR indication,
|
// indication is returned, then return an ERROR indication,
|
||||||
// Invalid_x, and Invalid_y.
|
// Invalid_x, and Invalid_y.
|
||||||
let returned_bits: Vec<u8> = rng.sample_iter(&Standard).take(n + 8).collect();
|
let returned_bits: Vec<u8> = rng.sample_iter(&Standard).take( (n + 64) / 8 ).collect();
|
||||||
// 5. Convert returned_bits to the (non-negative) integer c.
|
// 5. Convert returned_bits to the (non-negative) integer c.
|
||||||
let c = $nbig::from_bytes(&returned_bits);
|
let c = $nbig::from_bytes(&returned_bits);
|
||||||
// 6. x = (c mod (q-1)) + 1.
|
// 6. x = (c mod (q-1)) + 1.
|
||||||
@@ -55,8 +104,8 @@ macro_rules! generate_dsa_pair {
|
|||||||
// 7. y = g^x mod p
|
// 7. y = g^x mod p
|
||||||
let y = params.g.modexp(&$ltype::from(&x), ¶ms.p);
|
let y = params.g.modexp(&$ltype::from(&x), ¶ms.p);
|
||||||
// 8. Return SUCCESS, x, and y.
|
// 8. Return SUCCESS, x, and y.
|
||||||
let private = DSAPrivKey::new(params.clone(), x);
|
let private = DSAPrivateKey::<$ptype>::new(params.clone(), x);
|
||||||
let public = DSAPubKey::new(params.clone(), y);
|
let public = DSAPublicKey::<$ptype>::new(params.clone(), y);
|
||||||
DSAKeyPair { private, public }
|
DSAKeyPair { private, public }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,34 @@
|
|||||||
use cryptonum::unsigned::{CryptoNum,Decoder,Encoder,ModExp,PrimeGen};
|
use cryptonum::unsigned::{CryptoNum,Decoder,Encoder,ModExp,PrimeGen};
|
||||||
use cryptonum::unsigned::{U192,U256,U1024,U2048,U3072};
|
use cryptonum::unsigned::{U192,U256,U1024,U2048,U3072};
|
||||||
use digest::Digest;
|
use sha::{Hash,SHA256};
|
||||||
use sha2::Sha256;
|
|
||||||
use simple_asn1::{ToASN1,ASN1Block,ASN1Class,ASN1EncodeErr};
|
use simple_asn1::{ToASN1,ASN1Block,ASN1Class,ASN1EncodeErr};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use utils::TranslateNums;
|
use utils::TranslateNums;
|
||||||
|
|
||||||
|
/// A trait that describes what a set of DSA parameters must support in
|
||||||
|
/// order to be used by the rest of the system.
|
||||||
pub trait DSAParameters : ToASN1
|
pub trait DSAParameters : ToASN1
|
||||||
{
|
{
|
||||||
|
/// The fixed-width, unsigned type of values in L.
|
||||||
type L;
|
type L;
|
||||||
|
/// The fixed-width, unsigned type of values in N.
|
||||||
type N;
|
type N;
|
||||||
|
|
||||||
|
/// Given a `p`, `g`, and `q`, generate a new structure that includes
|
||||||
|
/// this information. Optionally, do any cross-checks needed.
|
||||||
fn new(p: Self::L, g: Self::L, q: Self::N) -> Self;
|
fn new(p: Self::L, g: Self::L, q: Self::N) -> Self;
|
||||||
|
/// Generate a new set of DSA parameters given the provided random
|
||||||
|
/// number generator. Just as with key generation, this should be a
|
||||||
|
/// cryptographically-strong random number generator. If it's not,
|
||||||
|
/// you may be writing compromisable code.
|
||||||
fn generate<G: Rng>(rng: &mut G) -> Self;
|
fn generate<G: Rng>(rng: &mut G) -> Self;
|
||||||
|
/// Return the size of values of N in bits.
|
||||||
fn n_size() -> usize;
|
fn n_size() -> usize;
|
||||||
|
/// Return the size of values of L in bits.
|
||||||
fn l_size() -> usize;
|
fn l_size() -> usize;
|
||||||
|
/// Return the size of `q` in this particular instance of the parameters.
|
||||||
|
/// (Should be the same as `n_size()`, and the default implementation
|
||||||
|
/// simply uses `n_size(), but included for convenience)
|
||||||
fn n_bits(&self) -> usize {
|
fn n_bits(&self) -> usize {
|
||||||
Self::n_size()
|
Self::n_size()
|
||||||
}
|
}
|
||||||
@@ -23,7 +36,8 @@ pub trait DSAParameters : ToASN1
|
|||||||
|
|
||||||
macro_rules! generate_parameters {
|
macro_rules! generate_parameters {
|
||||||
($name: ident, $ltype: ident, $ntype: ident, $l: expr, $n: expr) => {
|
($name: ident, $ltype: ident, $ntype: ident, $l: expr, $n: expr) => {
|
||||||
#[derive(Clone)]
|
/// DSA parameters to the given L and N, with the values given in bits.
|
||||||
|
#[derive(Clone,PartialEq)]
|
||||||
pub struct $name {
|
pub struct $name {
|
||||||
pub p: $ltype,
|
pub p: $ltype,
|
||||||
pub g: $ltype,
|
pub g: $ltype,
|
||||||
@@ -71,7 +85,7 @@ macro_rules! generate_parameters {
|
|||||||
|
|
||||||
impl $name
|
impl $name
|
||||||
{
|
{
|
||||||
fn generate_primes<G: Rng>(rng: &mut G) -> ($ltype,$ntype,U256,usize)
|
pub 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
|
// 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
|
// (since that's guaranteed to be >= N), and with the hash
|
||||||
@@ -105,10 +119,9 @@ macro_rules! generate_parameters {
|
|||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
let U = $ntype::from_bytes(&ubytes);
|
let U = $ntype::from_bytes(&ubytes);
|
||||||
// 7. q = 2^(N–1) + U + 1 – (U mod 2).
|
// 7. q = 2^(N–1) + U + 1 – (U mod 2).
|
||||||
let ulow = if U.is_even() { 0 } else { 1 };
|
let highbit = $ntype::from(1u64) << (N - 1);
|
||||||
let mut q = $ntype::from(1u64) << (N - 1);
|
let lowbit = $ntype::from(1u64);
|
||||||
q += U;
|
let q = U | highbit | lowbit;
|
||||||
q += $ntype::from(1u64 + ulow);
|
|
||||||
// 8. Test whether or not q is prime as specified in Appendix C.3.
|
// 8. Test whether or not q is prime as specified in Appendix C.3.
|
||||||
let q_is_prime = q.probably_prime(rng, 40);
|
let q_is_prime = q.probably_prime(rng, 40);
|
||||||
// 9. If q is not a prime, then go to step 5.
|
// 9. If q is not a prime, then go to step 5.
|
||||||
@@ -126,7 +139,7 @@ macro_rules! generate_parameters {
|
|||||||
for j in 0..n {
|
for j in 0..n {
|
||||||
let val = &domain_parameter_seed + U256::from(offset + j);
|
let val = &domain_parameter_seed + U256::from(offset + j);
|
||||||
let bytes = hash(&val, 32);
|
let bytes = hash(&val, 32);
|
||||||
assert_eq!(seedlen, bytes.len());
|
assert_eq!(seedlen, bytes.len() * 8);
|
||||||
V.push(bytes);
|
V.push(bytes);
|
||||||
}
|
}
|
||||||
// 11.2 W = V_0 + ( V_1 ∗ 2^outlen) + ... + ( V_(n–1) ∗ 2^(n –1) ∗ outlen) + ((V_n mod 2^b) ∗ 2^(n ∗ outlen).
|
// 11.2 W = V_0 + ( V_1 ∗ 2^outlen) + ... + ( V_(n–1) ∗ 2^(n –1) ∗ outlen) + ((V_n mod 2^b) ∗ 2^(n ∗ outlen).
|
||||||
@@ -208,5 +221,5 @@ fn hash<T>(x: &T, len: usize) -> Vec<u8>
|
|||||||
while base.len() < bytelen {
|
while base.len() < bytelen {
|
||||||
base.insert(0,0);
|
base.insert(0,0);
|
||||||
}
|
}
|
||||||
Sha256::digest(&base).as_slice().to_vec()
|
SHA256::hash(&base)
|
||||||
}
|
}
|
||||||
@@ -1,56 +1,36 @@
|
|||||||
use cryptonum::unsigned::*;
|
use cryptonum::unsigned::*;
|
||||||
use cryptonum::signed::ModInv;
|
use cryptonum::signed::ModInv;
|
||||||
use digest::{BlockInput,Digest,Input,FixedOutput,Reset};
|
|
||||||
use dsa::params::*;
|
use dsa::params::*;
|
||||||
use dsa::rfc6979::*;
|
use dsa::rfc6979::*;
|
||||||
use hmac::{Hmac,Mac};
|
use sha::Hash;
|
||||||
|
|
||||||
pub trait DSAPrivateKey {
|
/// A DSA private key, parameterized by its DSA parameters (so that you don't
|
||||||
type Params;
|
/// accidentally pass the wrong key to the wrong routine).
|
||||||
type L;
|
pub struct DSAPrivateKey<Params: DSAParameters>
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DSAPrivKey<Params,N>
|
|
||||||
{
|
{
|
||||||
pub(crate) params: Params,
|
pub(crate) params: Params,
|
||||||
pub(crate) x: N
|
pub(crate) x: Params::N
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A generic DSA private key enum, which masks which kind of DSA key (1024,
|
||||||
|
/// 2048 with the small `n`, 2048 with the normal `n`, or 3072) you're using.
|
||||||
pub enum DSAPrivate {
|
pub enum DSAPrivate {
|
||||||
DSA1024Private(DSAPrivKey<L1024N160,U192>),
|
DSA1024Private(DSAPrivateKey<L1024N160>),
|
||||||
DSA2048SmallPrivate(DSAPrivKey<L2048N224,U256>),
|
DSA2048SmallPrivate(DSAPrivateKey<L2048N224>),
|
||||||
DSA2048Private(DSAPrivKey<L2048N256,U256>),
|
DSA2048Private(DSAPrivateKey<L2048N256>),
|
||||||
DSA3072Private(DSAPrivKey<L3072N256,U256>)
|
DSA3072Private(DSAPrivateKey<L3072N256>)
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! privkey_impls {
|
macro_rules! privkey_impls {
|
||||||
($ptype: ident, $ltype: ident, $ntype: ident, $big: ident, $bigger: ident, $biggest: ident) => {
|
($ptype: ident, $ltype: ident, $ntype: ident, $big: ident, $bigger: ident, $biggest: ident) => {
|
||||||
impl DSAPrivateKey for DSAPrivKey<$ptype,$ntype>
|
impl DSAPrivateKey<$ptype>
|
||||||
{
|
{
|
||||||
type Params = $ptype;
|
pub fn new(params: $ptype, x: $ntype) -> DSAPrivateKey<$ptype>
|
||||||
type L = $ltype;
|
|
||||||
type N = $ntype;
|
|
||||||
|
|
||||||
fn new(params: $ptype, x: $ntype) -> DSAPrivKey<$ptype,$ntype>
|
|
||||||
{
|
{
|
||||||
DSAPrivKey{ params, x }
|
DSAPrivateKey{ params, x }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<$ntype>
|
pub fn sign<H: Hash + Clone>(&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
|
// This algorithm is per RFC 6979, which has a nice, relatively
|
||||||
// straightforward description of how to do DSA signing.
|
// straightforward description of how to do DSA signing.
|
||||||
@@ -63,7 +43,7 @@ macro_rules! privkey_impls {
|
|||||||
// As was noted in the description of bits2octets, the extra
|
// As was noted in the description of bits2octets, the extra
|
||||||
// modular reduction is no more than a conditional subtraction.
|
// modular reduction is no more than a conditional subtraction.
|
||||||
//
|
//
|
||||||
let h1 = <Hash>::digest(m);
|
let h1 = <H>::hash(m);
|
||||||
let n = $ptype::n_size();
|
let n = $ptype::n_size();
|
||||||
let h0: $ntype = bits2int(&h1, $ptype::n_size());
|
let h0: $ntype = bits2int(&h1, $ptype::n_size());
|
||||||
let q = &self.params.q;
|
let q = &self.params.q;
|
||||||
@@ -75,7 +55,7 @@ macro_rules! privkey_impls {
|
|||||||
// process used to generate k. In plain DSA or ECDSA, k should
|
// process used to generate k. In plain DSA or ECDSA, k should
|
||||||
// be selected through a random selection that chooses a value
|
// be selected through a random selection that chooses a value
|
||||||
// among the q-1 possible values with uniform probability.
|
// among the q-1 possible values with uniform probability.
|
||||||
for k in KIterator::<Hash,$ntype>::new(&h1, n, q, &self.x) {
|
for k in KIterator::<H,$ntype>::new(&h1, n, q, &self.x) {
|
||||||
// 3. A value r (modulo q) is computed from k and the key
|
// 3. A value r (modulo q) is computed from k and the key
|
||||||
// parameters:
|
// parameters:
|
||||||
// * For DSA:
|
// * For DSA:
|
||||||
@@ -127,7 +107,7 @@ macro_rules! generate_tests {
|
|||||||
use cryptonum::unsigned::Decoder;
|
use cryptonum::unsigned::Decoder;
|
||||||
use super::*;
|
use super::*;
|
||||||
use testing::run_test;
|
use testing::run_test;
|
||||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn verify() {
|
fn verify() {
|
||||||
@@ -155,12 +135,12 @@ macro_rules! generate_tests {
|
|||||||
let s = $nt::from_bytes(sbytes);
|
let s = $nt::from_bytes(sbytes);
|
||||||
|
|
||||||
let params = $params::new(p,g,q);
|
let params = $params::new(p,g,q);
|
||||||
let private = DSAPrivKey::<$params,$nt>::new(params, x);
|
let private = DSAPrivateKey::<$params>::new(params, x);
|
||||||
let sig = match h {
|
let sig = match h {
|
||||||
224 => private.sign::<Sha224>(mbytes),
|
224 => private.sign::<SHA224>(mbytes),
|
||||||
256 => private.sign::<Sha256>(mbytes),
|
256 => private.sign::<SHA256>(mbytes),
|
||||||
384 => private.sign::<Sha384>(mbytes),
|
384 => private.sign::<SHA384>(mbytes),
|
||||||
512 => private.sign::<Sha512>(mbytes),
|
512 => private.sign::<SHA512>(mbytes),
|
||||||
_ => panic!("Unexpected hash {}", h)
|
_ => panic!("Unexpected hash {}", h)
|
||||||
};
|
};
|
||||||
assert_eq!(r, sig.r);
|
assert_eq!(r, sig.r);
|
||||||
|
|||||||
@@ -1,52 +1,38 @@
|
|||||||
use cryptonum::unsigned::*;
|
use cryptonum::unsigned::*;
|
||||||
use cryptonum::signed::ModInv;
|
use cryptonum::signed::ModInv;
|
||||||
use digest::Digest;
|
|
||||||
use dsa::params::*;
|
use dsa::params::*;
|
||||||
use dsa::rfc6979::DSASignature;
|
use dsa::rfc6979::DSASignature;
|
||||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,ToASN1};
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,ToASN1};
|
||||||
|
use sha::Hash;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use utils::TranslateNums;
|
use utils::TranslateNums;
|
||||||
|
|
||||||
pub trait DSAPublicKey {
|
/// A DSA public key, parameterized by its DSA parameters (so that you don't
|
||||||
type Params : DSAParameters;
|
/// accidentally pass the wrong thing to the wrong function).
|
||||||
type L;
|
pub struct DSAPublicKey<Params: DSAParameters> {
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DSAPubKey<Params,L> {
|
|
||||||
pub(crate) params: Params,
|
pub(crate) params: Params,
|
||||||
pub(crate) y: L
|
pub(crate) y: Params::L
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An enumeration that hides exactly which parameters you're using. Use at
|
||||||
|
/// your own risk, as the types won't save you.
|
||||||
pub enum DSAPublic {
|
pub enum DSAPublic {
|
||||||
DSAPublicL1024N160(DSAPubKey<L1024N160,U1024>),
|
DSAPublicL1024N160(DSAPublicKey<L1024N160>),
|
||||||
DSAPublicL2048N224(DSAPubKey<L2048N224,U2048>),
|
DSAPublicL2048N224(DSAPublicKey<L2048N224>),
|
||||||
DSAPublicL2048N256(DSAPubKey<L2048N256,U2048>),
|
DSAPublicL2048N256(DSAPublicKey<L2048N256>),
|
||||||
DSAPublicL3072N256(DSAPubKey<L3072N256,U3072>)
|
DSAPublicL3072N256(DSAPublicKey<L3072N256>)
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! pubkey_impls {
|
macro_rules! pubkey_impls {
|
||||||
($ptype: ident, $ltype: ident, $ntype: ident, $dbl: ident, $bdbl: ident) => {
|
($ptype: ident, $ltype: ident, $ntype: ident, $dbl: ident, $bdbl: ident) => {
|
||||||
impl DSAPublicKey for DSAPubKey<$ptype,$ltype>
|
impl DSAPublicKey<$ptype>
|
||||||
{
|
{
|
||||||
type Params = $ptype;
|
pub fn new(params: $ptype, y: $ltype) -> DSAPublicKey<$ptype>
|
||||||
type L = $ltype;
|
|
||||||
type N = $ntype;
|
|
||||||
|
|
||||||
fn new(params: $ptype, y: $ltype) -> DSAPubKey<$ptype,$ltype>
|
|
||||||
{
|
{
|
||||||
DSAPubKey{ params, y }
|
DSAPublicKey{ params, y }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<$ntype>) -> bool
|
pub fn verify<H: Hash>(&self, m: &[u8], sig: &DSASignature<$ntype>) -> bool
|
||||||
where Hash: Digest
|
|
||||||
{
|
{
|
||||||
if sig.r >= self.params.q {
|
if sig.r >= self.params.q {
|
||||||
return false;
|
return false;
|
||||||
@@ -57,7 +43,7 @@ macro_rules! pubkey_impls {
|
|||||||
// w = (s')^-1 mod q;
|
// w = (s')^-1 mod q;
|
||||||
if let Some(w) = sig.s.modinv(&self.params.q) {
|
if let Some(w) = sig.s.modinv(&self.params.q) {
|
||||||
// z = the leftmost min(N, outlen) bits of Hash(M').
|
// z = the leftmost min(N, outlen) bits of Hash(M').
|
||||||
let mut digest_bytes = <Hash>::digest(m).to_vec();
|
let mut digest_bytes = <H>::hash(m);
|
||||||
let len = min(digest_bytes.len(), $ptype::n_size() / 8);
|
let len = min(digest_bytes.len(), $ptype::n_size() / 8);
|
||||||
digest_bytes.truncate(len);
|
digest_bytes.truncate(len);
|
||||||
let z = $ntype::from_bytes(&digest_bytes);
|
let z = $ntype::from_bytes(&digest_bytes);
|
||||||
@@ -80,7 +66,7 @@ macro_rules! pubkey_impls {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToASN1 for DSAPubKey<$ptype,$ltype> {
|
impl ToASN1 for DSAPublicKey<$ptype> {
|
||||||
type Error = ASN1EncodeErr;
|
type Error = ASN1EncodeErr;
|
||||||
|
|
||||||
fn to_asn1_class(&self, c: ASN1Class)
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
@@ -108,7 +94,7 @@ macro_rules! generate_tests {
|
|||||||
use cryptonum::unsigned::Decoder;
|
use cryptonum::unsigned::Decoder;
|
||||||
use super::*;
|
use super::*;
|
||||||
use testing::run_test;
|
use testing::run_test;
|
||||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn verify() {
|
fn verify() {
|
||||||
@@ -136,13 +122,13 @@ macro_rules! generate_tests {
|
|||||||
let s = $nt::from_bytes(sbytes);
|
let s = $nt::from_bytes(sbytes);
|
||||||
|
|
||||||
let params = $params::new(p,g,q);
|
let params = $params::new(p,g,q);
|
||||||
let public = DSAPubKey::<$params,$lt>::new(params, y);
|
let public = DSAPublicKey::<$params>::new(params, y);
|
||||||
let sig = DSASignature::<$nt>::new(r, s);
|
let sig = DSASignature::<$nt>::new(r, s);
|
||||||
match h {
|
match h {
|
||||||
224 => assert!(public.verify::<Sha224>(mbytes, &sig)),
|
224 => assert!(public.verify::<SHA224>(mbytes, &sig)),
|
||||||
256 => assert!(public.verify::<Sha256>(mbytes, &sig)),
|
256 => assert!(public.verify::<SHA256>(mbytes, &sig)),
|
||||||
384 => assert!(public.verify::<Sha384>(mbytes, &sig)),
|
384 => assert!(public.verify::<SHA384>(mbytes, &sig)),
|
||||||
512 => assert!(public.verify::<Sha512>(mbytes, &sig)),
|
512 => assert!(public.verify::<SHA512>(mbytes, &sig)),
|
||||||
_ => panic!("Unexpected hash {}", h)
|
_ => panic!("Unexpected hash {}", h)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use cryptonum::unsigned::{CryptoNum,Decoder,Encoder};
|
use cryptonum::unsigned::{CryptoNum,Decoder,Encoder};
|
||||||
use digest::{BlockInput,Digest,FixedOutput,Input,Reset};
|
use hmac::HMAC;
|
||||||
use digest::generic_array::ArrayLength;
|
use sha::Hash;
|
||||||
use hmac::{Hmac,Mac};
|
|
||||||
use num::BigInt;
|
use num::BigInt;
|
||||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr};
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr};
|
||||||
use simple_asn1::{FromASN1,ToASN1};
|
use simple_asn1::{FromASN1,ToASN1};
|
||||||
@@ -26,11 +25,10 @@ impl<N> DSASignature<N>
|
|||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub struct KIterator<H,N>
|
pub struct KIterator<H,N>
|
||||||
where
|
where
|
||||||
H: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
H: Hash + Clone,
|
||||||
N: Clone + Decoder + Encoder + PartialOrd + Shr<usize,Output=N>,
|
N: Clone + Decoder + Encoder + PartialOrd + Shr<usize,Output=N>,
|
||||||
Hmac<H>: Mac
|
|
||||||
{
|
{
|
||||||
hmac_k: Hmac<H>,
|
hmac_k: HMAC<H>,
|
||||||
V: Vec<u8>,
|
V: Vec<u8>,
|
||||||
q: N,
|
q: N,
|
||||||
qlen: usize
|
qlen: usize
|
||||||
@@ -38,9 +36,8 @@ pub struct KIterator<H,N>
|
|||||||
|
|
||||||
impl<H,N> KIterator<H,N>
|
impl<H,N> KIterator<H,N>
|
||||||
where
|
where
|
||||||
H: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
H: Hash + Clone,
|
||||||
N: Clone + Decoder + Encoder + PartialOrd + Shr<usize,Output=N> + Sub<Output=N>,
|
N: Clone + Decoder + Encoder + PartialOrd + Shr<usize,Output=N> + Sub<Output=N>,
|
||||||
Hmac<H>: Mac
|
|
||||||
{
|
{
|
||||||
pub fn new(h1: &[u8], qlen: usize, q: &N, x: &N) -> KIterator<H,N>
|
pub fn new(h1: &[u8], qlen: usize, q: &N, x: &N) -> KIterator<H,N>
|
||||||
{
|
{
|
||||||
@@ -95,11 +92,11 @@ impl<H,N> KIterator<H,N>
|
|||||||
input.push(0x00);
|
input.push(0x00);
|
||||||
input.extend_from_slice(&xbytes);
|
input.extend_from_slice(&xbytes);
|
||||||
input.extend_from_slice(&h1bytes);
|
input.extend_from_slice(&h1bytes);
|
||||||
K = hmac(&K, &input);
|
K = HMAC::<H>::hmac(&K, &input);
|
||||||
// e. Set:
|
// e. Set:
|
||||||
//
|
//
|
||||||
// V = HMAC_K(V)
|
// V = HMAC_K(V)
|
||||||
V = hmac(&K, &V);
|
V = HMAC::<H>::hmac(&K, &V);
|
||||||
// f. Set:
|
// f. Set:
|
||||||
//
|
//
|
||||||
// K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1))
|
// K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1))
|
||||||
@@ -110,14 +107,14 @@ impl<H,N> KIterator<H,N>
|
|||||||
input.push(0x01);
|
input.push(0x01);
|
||||||
input.extend_from_slice(&xbytes);
|
input.extend_from_slice(&xbytes);
|
||||||
input.extend_from_slice(&h1bytes);
|
input.extend_from_slice(&h1bytes);
|
||||||
K = hmac(&K, &input);
|
K = HMAC::<H>::hmac(&K, &input);
|
||||||
// g. Set:
|
// g. Set:
|
||||||
//
|
//
|
||||||
// V = HMAC_K(V)
|
// V = HMAC_K(V)
|
||||||
V = hmac(&K, &V);
|
V = HMAC::<H>::hmac(&K, &V);
|
||||||
// h is for later ...
|
// h is for later ...
|
||||||
KIterator {
|
KIterator {
|
||||||
hmac_k: Hmac::<H>::new_varkey(&K).unwrap(),
|
hmac_k: HMAC::<H>::new(&K),
|
||||||
V: V,
|
V: V,
|
||||||
q: q.clone(),
|
q: q.clone(),
|
||||||
qlen: qlen
|
qlen: qlen
|
||||||
@@ -127,9 +124,8 @@ impl<H,N> KIterator<H,N>
|
|||||||
|
|
||||||
impl<H,N> Iterator for KIterator<H,N>
|
impl<H,N> Iterator for KIterator<H,N>
|
||||||
where
|
where
|
||||||
H: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
H: Hash + Clone,
|
||||||
N: Clone + CryptoNum + Decoder + Encoder + PartialOrd + Shr<usize,Output=N>,
|
N: Clone + CryptoNum + Decoder + Encoder + PartialOrd + Shr<usize,Output=N>,
|
||||||
Hmac<H>: Mac
|
|
||||||
{
|
{
|
||||||
type Item = N;
|
type Item = N;
|
||||||
|
|
||||||
@@ -170,7 +166,7 @@ impl<H,N> Iterator for KIterator<H,N>
|
|||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
let K = runhmac(&self.hmac_k, &input);
|
let K = runhmac(&self.hmac_k, &input);
|
||||||
// V = HMAC_K(V)
|
// V = HMAC_K(V)
|
||||||
self.hmac_k = Hmac::<H>::new_varkey(&K).unwrap();
|
self.hmac_k = HMAC::<H>::new(&K);
|
||||||
self.V = runhmac(&self.hmac_k, &self.V);
|
self.V = runhmac(&self.hmac_k, &self.V);
|
||||||
//
|
//
|
||||||
// and loop (try to generate a new T, and so on).
|
// and loop (try to generate a new T, and so on).
|
||||||
@@ -224,26 +220,11 @@ fn int2octets<X>(x: &X, qlen_bits: usize) -> Vec<u8>
|
|||||||
base
|
base
|
||||||
}
|
}
|
||||||
|
|
||||||
fn runhmac<H>(base: &Hmac<H>, m: &[u8]) -> Vec<u8>
|
fn runhmac<H: Hash + Clone>(base: &HMAC<H>, m: &[u8]) -> Vec<u8>
|
||||||
where
|
|
||||||
H: Clone + BlockInput + Default + Input + FixedOutput + Reset,
|
|
||||||
Hmac<H>: Clone + Mac,
|
|
||||||
H::BlockSize : ArrayLength<u8>
|
|
||||||
{
|
{
|
||||||
let mut runner = base.clone();
|
let mut runner = base.clone();
|
||||||
runner.input(&m);
|
runner.update(&m);
|
||||||
runner.result().code().as_slice().to_vec()
|
runner.finalize()
|
||||||
}
|
|
||||||
|
|
||||||
fn hmac<H>(k: &[u8], m: &[u8]) -> Vec<u8>
|
|
||||||
where
|
|
||||||
H: BlockInput + Clone + Default + Input + FixedOutput + Reset,
|
|
||||||
Hmac<H>: Clone + Mac,
|
|
||||||
H::BlockSize : ArrayLength<u8>
|
|
||||||
{
|
|
||||||
let mut runner = Hmac::<H>::new_varkey(&k).unwrap();
|
|
||||||
runner.input(&m);
|
|
||||||
runner.result().code().as_slice().to_vec()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone,Debug,PartialEq)]
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
@@ -304,7 +285,7 @@ impl<N> ToASN1 for DSASignature<N>
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use cryptonum::unsigned::U192;
|
use cryptonum::unsigned::U192;
|
||||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||||
use super::*;
|
use super::*;
|
||||||
use testing::*;
|
use testing::*;
|
||||||
|
|
||||||
@@ -343,7 +324,7 @@ mod tests {
|
|||||||
fn k_gen_example() {
|
fn k_gen_example() {
|
||||||
let q = U192::from_bytes(&QBYTES);
|
let q = U192::from_bytes(&QBYTES);
|
||||||
let x = U192::from_bytes(&XBYTES);
|
let x = U192::from_bytes(&XBYTES);
|
||||||
let mut iter = KIterator::<Sha256,U192>::new(&H1, 163, &q, &x);
|
let mut iter = KIterator::<SHA256,U192>::new(&H1, 163, &q, &x);
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
None =>
|
None =>
|
||||||
assert!(false),
|
assert!(false),
|
||||||
@@ -428,9 +409,9 @@ mod tests {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
k_generator_tests!(kgen_sha224, Sha224, "SHA224");
|
k_generator_tests!(kgen_sha224, SHA224, "SHA224");
|
||||||
k_generator_tests!(kgen_sha256, Sha256, "SHA256");
|
k_generator_tests!(kgen_sha256, SHA256, "SHA256");
|
||||||
k_generator_tests!(kgen_sha384, Sha384, "SHA384");
|
k_generator_tests!(kgen_sha384, SHA384, "SHA384");
|
||||||
k_generator_tests!(kgen_sha512, Sha512, "SHA512");
|
k_generator_tests!(kgen_sha512, SHA512, "SHA512");
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
use cryptonum::unsigned::*;
|
use cryptonum::unsigned::*;
|
||||||
use digest::Digest;
|
use sha::{Hash,SHA1,SHA224,SHA256,SHA384,SHA512};
|
||||||
use sha1::Sha1;
|
|
||||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
|
||||||
use simple_asn1::{der_decode,der_encode};
|
use simple_asn1::{der_decode,der_encode};
|
||||||
use dsa::params::{DSAParameters,L1024N160,L2048N256};
|
use dsa::params::{DSAParameters,L1024N160,L2048N256};
|
||||||
use dsa::private::{DSAPrivateKey,DSAPrivKey};
|
use dsa::private::DSAPrivateKey;
|
||||||
use dsa::public::{DSAPublicKey,DSAPubKey};
|
use dsa::public::DSAPublicKey;
|
||||||
use dsa::rfc6979::KIterator;
|
use dsa::rfc6979::KIterator;
|
||||||
|
|
||||||
macro_rules! run_rfc6979_test {
|
macro_rules! run_rfc6979_test {
|
||||||
@@ -13,7 +11,7 @@ macro_rules! run_rfc6979_test {
|
|||||||
k $k: expr,
|
k $k: expr,
|
||||||
r $r: expr,
|
r $r: expr,
|
||||||
s $s: expr) => ({
|
s $s: expr) => ({
|
||||||
let h1 = <$hash>::digest(&$val);
|
let h1 = <$hash>::hash(&$val);
|
||||||
let rbytes = $r;
|
let rbytes = $r;
|
||||||
let sbytes = $s;
|
let sbytes = $s;
|
||||||
let r = $ntype::from_bytes(&rbytes);
|
let r = $ntype::from_bytes(&rbytes);
|
||||||
@@ -99,8 +97,8 @@ fn appendix_a21() {
|
|||||||
let params = L1024N160::new(p, g, q);
|
let params = L1024N160::new(p, g, q);
|
||||||
let x = U192::from_bytes(&xbytes);
|
let x = U192::from_bytes(&xbytes);
|
||||||
let y = U1024::from_bytes(&ybytes);
|
let y = U1024::from_bytes(&ybytes);
|
||||||
let private = DSAPrivKey::new(params.clone(), x);
|
let private = DSAPrivateKey::<L1024N160>::new(params.clone(), x);
|
||||||
let public = DSAPubKey::<L1024N160,U1024>::new(params.clone(), y);
|
let public = DSAPublicKey::<L1024N160>::new(params.clone(), y);
|
||||||
//
|
//
|
||||||
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
|
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
|
||||||
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
|
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
|
||||||
@@ -108,7 +106,7 @@ fn appendix_a21() {
|
|||||||
// k = 7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B
|
// k = 7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B
|
||||||
// r = 2E1A0C2562B2912CAAF89186FB0F42001585DA55
|
// r = 2E1A0C2562B2912CAAF89186FB0F42001585DA55
|
||||||
// s = 29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5
|
// s = 29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5
|
||||||
run_rfc6979_test!(Sha1, U192, sample, params, public, private,
|
run_rfc6979_test!(SHA1, U192, sample, params, public, private,
|
||||||
k vec![0x7B, 0xDB, 0x6B, 0x0F, 0xF7, 0x56, 0xE1, 0xBB,
|
k vec![0x7B, 0xDB, 0x6B, 0x0F, 0xF7, 0x56, 0xE1, 0xBB,
|
||||||
0x5D, 0x53, 0x58, 0x3E, 0xF9, 0x79, 0x08, 0x2F,
|
0x5D, 0x53, 0x58, 0x3E, 0xF9, 0x79, 0x08, 0x2F,
|
||||||
0x9A, 0xD5, 0xBD, 0x5B],
|
0x9A, 0xD5, 0xBD, 0x5B],
|
||||||
@@ -122,7 +120,7 @@ fn appendix_a21() {
|
|||||||
// k = 562097C06782D60C3037BA7BE104774344687649
|
// k = 562097C06782D60C3037BA7BE104774344687649
|
||||||
// r = 4BC3B686AEA70145856814A6F1BB53346F02101E
|
// r = 4BC3B686AEA70145856814A6F1BB53346F02101E
|
||||||
// s = 410697B92295D994D21EDD2F4ADA85566F6F94C1
|
// s = 410697B92295D994D21EDD2F4ADA85566F6F94C1
|
||||||
run_rfc6979_test!(Sha224, U192, sample, params, public, private,
|
run_rfc6979_test!(SHA224, U192, sample, params, public, private,
|
||||||
k vec![0x56, 0x20, 0x97, 0xC0, 0x67, 0x82, 0xD6, 0x0C,
|
k vec![0x56, 0x20, 0x97, 0xC0, 0x67, 0x82, 0xD6, 0x0C,
|
||||||
0x30, 0x37, 0xBA, 0x7B, 0xE1, 0x04, 0x77, 0x43,
|
0x30, 0x37, 0xBA, 0x7B, 0xE1, 0x04, 0x77, 0x43,
|
||||||
0x44, 0x68, 0x76, 0x49],
|
0x44, 0x68, 0x76, 0x49],
|
||||||
@@ -136,7 +134,7 @@ fn appendix_a21() {
|
|||||||
// k = 519BA0546D0C39202A7D34D7DFA5E760B318BCFB
|
// k = 519BA0546D0C39202A7D34D7DFA5E760B318BCFB
|
||||||
// r = 81F2F5850BE5BC123C43F71A3033E9384611C545
|
// r = 81F2F5850BE5BC123C43F71A3033E9384611C545
|
||||||
// s = 4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89
|
// s = 4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89
|
||||||
run_rfc6979_test!(Sha256, U192, sample, params, public, private,
|
run_rfc6979_test!(SHA256, U192, sample, params, public, private,
|
||||||
k vec![0x51, 0x9B, 0xA0, 0x54, 0x6D, 0x0C, 0x39, 0x20,
|
k vec![0x51, 0x9B, 0xA0, 0x54, 0x6D, 0x0C, 0x39, 0x20,
|
||||||
0x2A, 0x7D, 0x34, 0xD7, 0xDF, 0xA5, 0xE7, 0x60,
|
0x2A, 0x7D, 0x34, 0xD7, 0xDF, 0xA5, 0xE7, 0x60,
|
||||||
0xB3, 0x18, 0xBC, 0xFB],
|
0xB3, 0x18, 0xBC, 0xFB],
|
||||||
@@ -150,7 +148,7 @@ fn appendix_a21() {
|
|||||||
// k = 95897CD7BBB944AA932DBC579C1C09EB6FCFC595
|
// k = 95897CD7BBB944AA932DBC579C1C09EB6FCFC595
|
||||||
// r = 07F2108557EE0E3921BC1774F1CA9B410B4CE65A
|
// r = 07F2108557EE0E3921BC1774F1CA9B410B4CE65A
|
||||||
// s = 54DF70456C86FAC10FAB47C1949AB83F2C6F7595
|
// s = 54DF70456C86FAC10FAB47C1949AB83F2C6F7595
|
||||||
run_rfc6979_test!(Sha384, U192, sample, params, public, private,
|
run_rfc6979_test!(SHA384, U192, sample, params, public, private,
|
||||||
k vec![0x95, 0x89, 0x7C, 0xD7, 0xBB, 0xB9, 0x44, 0xAA,
|
k vec![0x95, 0x89, 0x7C, 0xD7, 0xBB, 0xB9, 0x44, 0xAA,
|
||||||
0x93, 0x2D, 0xBC, 0x57, 0x9C, 0x1C, 0x09, 0xEB,
|
0x93, 0x2D, 0xBC, 0x57, 0x9C, 0x1C, 0x09, 0xEB,
|
||||||
0x6F, 0xCF, 0xC5, 0x95],
|
0x6F, 0xCF, 0xC5, 0x95],
|
||||||
@@ -164,7 +162,7 @@ fn appendix_a21() {
|
|||||||
// k = 09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B
|
// k = 09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B
|
||||||
// r = 16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B
|
// r = 16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B
|
||||||
// s = 02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C
|
// s = 02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C
|
||||||
run_rfc6979_test!(Sha512, U192, sample, params, public, private,
|
run_rfc6979_test!(SHA512, U192, sample, params, public, private,
|
||||||
k vec![0x09, 0xEC, 0xE7, 0xCA, 0x27, 0xD0, 0xF5, 0xA4,
|
k vec![0x09, 0xEC, 0xE7, 0xCA, 0x27, 0xD0, 0xF5, 0xA4,
|
||||||
0xDD, 0x4E, 0x55, 0x6C, 0x9D, 0xF1, 0xD2, 0x1D,
|
0xDD, 0x4E, 0x55, 0x6C, 0x9D, 0xF1, 0xD2, 0x1D,
|
||||||
0x28, 0x10, 0x4F, 0x8B],
|
0x28, 0x10, 0x4F, 0x8B],
|
||||||
@@ -178,7 +176,7 @@ fn appendix_a21() {
|
|||||||
// k = 5C842DF4F9E344EE09F056838B42C7A17F4A6433
|
// k = 5C842DF4F9E344EE09F056838B42C7A17F4A6433
|
||||||
// r = 42AB2052FD43E123F0607F115052A67DCD9C5C77
|
// r = 42AB2052FD43E123F0607F115052A67DCD9C5C77
|
||||||
// s = 183916B0230D45B9931491D4C6B0BD2FB4AAF088
|
// s = 183916B0230D45B9931491D4C6B0BD2FB4AAF088
|
||||||
run_rfc6979_test!(Sha1, U192, test, params, public, private,
|
run_rfc6979_test!(SHA1, U192, test, params, public, private,
|
||||||
k vec![0x5C, 0x84, 0x2D, 0xF4, 0xF9, 0xE3, 0x44, 0xEE,
|
k vec![0x5C, 0x84, 0x2D, 0xF4, 0xF9, 0xE3, 0x44, 0xEE,
|
||||||
0x09, 0xF0, 0x56, 0x83, 0x8B, 0x42, 0xC7, 0xA1,
|
0x09, 0xF0, 0x56, 0x83, 0x8B, 0x42, 0xC7, 0xA1,
|
||||||
0x7F, 0x4A, 0x64, 0x33],
|
0x7F, 0x4A, 0x64, 0x33],
|
||||||
@@ -192,7 +190,7 @@ fn appendix_a21() {
|
|||||||
// k = 4598B8EFC1A53BC8AECD58D1ABBB0C0C71E67297
|
// k = 4598B8EFC1A53BC8AECD58D1ABBB0C0C71E67297
|
||||||
// r = 6868E9964E36C1689F6037F91F28D5F2C30610F2
|
// r = 6868E9964E36C1689F6037F91F28D5F2C30610F2
|
||||||
// s = 49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F
|
// s = 49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F
|
||||||
run_rfc6979_test!(Sha224, U192, test, params, public, private,
|
run_rfc6979_test!(SHA224, U192, test, params, public, private,
|
||||||
k vec![0x45, 0x98, 0xB8, 0xEF, 0xC1, 0xA5, 0x3B, 0xC8,
|
k vec![0x45, 0x98, 0xB8, 0xEF, 0xC1, 0xA5, 0x3B, 0xC8,
|
||||||
0xAE, 0xCD, 0x58, 0xD1, 0xAB, 0xBB, 0x0C, 0x0C,
|
0xAE, 0xCD, 0x58, 0xD1, 0xAB, 0xBB, 0x0C, 0x0C,
|
||||||
0x71, 0xE6, 0x72, 0x97],
|
0x71, 0xE6, 0x72, 0x97],
|
||||||
@@ -206,7 +204,7 @@ fn appendix_a21() {
|
|||||||
// k = 5A67592E8128E03A417B0484410FB72C0B630E1A
|
// k = 5A67592E8128E03A417B0484410FB72C0B630E1A
|
||||||
// r = 22518C127299B0F6FDC9872B282B9E70D0790812
|
// r = 22518C127299B0F6FDC9872B282B9E70D0790812
|
||||||
// s = 6837EC18F150D55DE95B5E29BE7AF5D01E4FE160
|
// s = 6837EC18F150D55DE95B5E29BE7AF5D01E4FE160
|
||||||
run_rfc6979_test!(Sha256, U192, test, params, public, private,
|
run_rfc6979_test!(SHA256, U192, test, params, public, private,
|
||||||
k vec![0x5A, 0x67, 0x59, 0x2E, 0x81, 0x28, 0xE0, 0x3A,
|
k vec![0x5A, 0x67, 0x59, 0x2E, 0x81, 0x28, 0xE0, 0x3A,
|
||||||
0x41, 0x7B, 0x04, 0x84, 0x41, 0x0F, 0xB7, 0x2C,
|
0x41, 0x7B, 0x04, 0x84, 0x41, 0x0F, 0xB7, 0x2C,
|
||||||
0x0B, 0x63, 0x0E, 0x1A],
|
0x0B, 0x63, 0x0E, 0x1A],
|
||||||
@@ -220,7 +218,7 @@ fn appendix_a21() {
|
|||||||
// k = 220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89
|
// k = 220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89
|
||||||
// r = 854CF929B58D73C3CBFDC421E8D5430CD6DB5E66
|
// r = 854CF929B58D73C3CBFDC421E8D5430CD6DB5E66
|
||||||
// s = 91D0E0F53E22F898D158380676A871A157CDA622
|
// s = 91D0E0F53E22F898D158380676A871A157CDA622
|
||||||
run_rfc6979_test!(Sha384, U192, test, params, public, private,
|
run_rfc6979_test!(SHA384, U192, test, params, public, private,
|
||||||
k vec![0x22, 0x01, 0x56, 0xB7, 0x61, 0xF6, 0xCA, 0x5E,
|
k vec![0x22, 0x01, 0x56, 0xB7, 0x61, 0xF6, 0xCA, 0x5E,
|
||||||
0x6C, 0x9F, 0x1B, 0x9C, 0xF9, 0xC2, 0x4B, 0xE2,
|
0x6C, 0x9F, 0x1B, 0x9C, 0xF9, 0xC2, 0x4B, 0xE2,
|
||||||
0x5F, 0x98, 0xCD, 0x89],
|
0x5F, 0x98, 0xCD, 0x89],
|
||||||
@@ -234,7 +232,7 @@ fn appendix_a21() {
|
|||||||
// k = 65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C
|
// k = 65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C
|
||||||
// r = 8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0
|
// r = 8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0
|
||||||
// s = 7C670C7AD72B6C050C109E1790008097125433E8
|
// s = 7C670C7AD72B6C050C109E1790008097125433E8
|
||||||
run_rfc6979_test!(Sha512, U192, test, params, public, private,
|
run_rfc6979_test!(SHA512, U192, test, params, public, private,
|
||||||
k vec![0x65, 0xD2, 0xC2, 0xEE, 0xB1, 0x75, 0xE3, 0x70,
|
k vec![0x65, 0xD2, 0xC2, 0xEE, 0xB1, 0x75, 0xE3, 0x70,
|
||||||
0xF2, 0x8C, 0x75, 0xBF, 0xCD, 0xC0, 0x28, 0xD2,
|
0xF2, 0x8C, 0x75, 0xBF, 0xCD, 0xC0, 0x28, 0xD2,
|
||||||
0x2C, 0x7D, 0xBE, 0x9C],
|
0x2C, 0x7D, 0xBE, 0x9C],
|
||||||
@@ -359,8 +357,8 @@ fn appendix_a22() {
|
|||||||
let params = L2048N256::new(p, g, q);
|
let params = L2048N256::new(p, g, q);
|
||||||
let x = U256::from_bytes(&xbytes);
|
let x = U256::from_bytes(&xbytes);
|
||||||
let y = U2048::from_bytes(&ybytes);
|
let y = U2048::from_bytes(&ybytes);
|
||||||
let private = DSAPrivKey::<L2048N256,U256>::new(params.clone(), x);
|
let private = DSAPrivateKey::<L2048N256>::new(params.clone(), x);
|
||||||
let public = DSAPubKey::<L2048N256,U2048>::new(params.clone(), y);
|
let public = DSAPublicKey::<L2048N256>::new(params.clone(), y);
|
||||||
//
|
//
|
||||||
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
|
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
|
||||||
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
|
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
|
||||||
@@ -368,7 +366,7 @@ fn appendix_a22() {
|
|||||||
// k = 888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E
|
// k = 888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E
|
||||||
// r = 3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A
|
// r = 3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A
|
||||||
// s = D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF
|
// s = D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF
|
||||||
run_rfc6979_test!(Sha1, U256, sample, params, public, private,
|
run_rfc6979_test!(SHA1, U256, sample, params, public, private,
|
||||||
k vec![0x88,0x8F,0xA6,0xF7,0x73,0x8A,0x41,0xBD,
|
k vec![0x88,0x8F,0xA6,0xF7,0x73,0x8A,0x41,0xBD,
|
||||||
0xC9,0x84,0x64,0x66,0xAB,0xDB,0x81,0x74,
|
0xC9,0x84,0x64,0x66,0xAB,0xDB,0x81,0x74,
|
||||||
0xC0,0x33,0x82,0x50,0xAE,0x50,0xCE,0x95,
|
0xC0,0x33,0x82,0x50,0xAE,0x50,0xCE,0x95,
|
||||||
@@ -385,7 +383,7 @@ fn appendix_a22() {
|
|||||||
// k = BC372967702082E1AA4FCE892209F71AE4AD25A6DFD869334E6F153BD0C4D806
|
// k = BC372967702082E1AA4FCE892209F71AE4AD25A6DFD869334E6F153BD0C4D806
|
||||||
// r = DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C
|
// r = DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C
|
||||||
// s = A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC
|
// s = A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC
|
||||||
run_rfc6979_test!(Sha224, U256, sample, params, public, private,
|
run_rfc6979_test!(SHA224, U256, sample, params, public, private,
|
||||||
k vec![0xBC,0x37,0x29,0x67,0x70,0x20,0x82,0xE1,
|
k vec![0xBC,0x37,0x29,0x67,0x70,0x20,0x82,0xE1,
|
||||||
0xAA,0x4F,0xCE,0x89,0x22,0x09,0xF7,0x1A,
|
0xAA,0x4F,0xCE,0x89,0x22,0x09,0xF7,0x1A,
|
||||||
0xE4,0xAD,0x25,0xA6,0xDF,0xD8,0x69,0x33,
|
0xE4,0xAD,0x25,0xA6,0xDF,0xD8,0x69,0x33,
|
||||||
@@ -402,7 +400,7 @@ fn appendix_a22() {
|
|||||||
// k = 8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52
|
// k = 8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52
|
||||||
// r = EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809
|
// r = EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809
|
||||||
// s = 7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53
|
// s = 7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53
|
||||||
run_rfc6979_test!(Sha256, U256, sample, params, public, private,
|
run_rfc6979_test!(SHA256, U256, sample, params, public, private,
|
||||||
k vec![0x89,0x26,0xA2,0x7C,0x40,0x48,0x42,0x16,
|
k vec![0x89,0x26,0xA2,0x7C,0x40,0x48,0x42,0x16,
|
||||||
0xF0,0x52,0xF4,0x42,0x7C,0xFD,0x56,0x47,
|
0xF0,0x52,0xF4,0x42,0x7C,0xFD,0x56,0x47,
|
||||||
0x33,0x8B,0x7B,0x39,0x39,0xBC,0x65,0x73,
|
0x33,0x8B,0x7B,0x39,0x39,0xBC,0x65,0x73,
|
||||||
@@ -419,7 +417,7 @@ fn appendix_a22() {
|
|||||||
// k = C345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920
|
// k = C345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920
|
||||||
// r = B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B
|
// r = B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B
|
||||||
// s = 19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B
|
// s = 19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B
|
||||||
run_rfc6979_test!(Sha384, U256, sample, params, public, private,
|
run_rfc6979_test!(SHA384, U256, sample, params, public, private,
|
||||||
k vec![0xC3,0x45,0xD5,0xAB,0x3D,0xA0,0xA5,0xBC,
|
k vec![0xC3,0x45,0xD5,0xAB,0x3D,0xA0,0xA5,0xBC,
|
||||||
0xB7,0xEC,0x8F,0x8F,0xB7,0xA7,0xE9,0x60,
|
0xB7,0xEC,0x8F,0x8F,0xB7,0xA7,0xE9,0x60,
|
||||||
0x69,0xE0,0x3B,0x20,0x63,0x71,0xEF,0x7D,
|
0x69,0xE0,0x3B,0x20,0x63,0x71,0xEF,0x7D,
|
||||||
@@ -436,7 +434,7 @@ fn appendix_a22() {
|
|||||||
// k = 5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC
|
// k = 5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC
|
||||||
// r = 2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E
|
// r = 2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E
|
||||||
// s = D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351
|
// s = D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351
|
||||||
run_rfc6979_test!(Sha512, U256, sample, params, public, private,
|
run_rfc6979_test!(SHA512, U256, sample, params, public, private,
|
||||||
k vec![0x5A,0x12,0x99,0x44,0x31,0x78,0x54,0x85,
|
k vec![0x5A,0x12,0x99,0x44,0x31,0x78,0x54,0x85,
|
||||||
0xB3,0xF5,0xF0,0x67,0x22,0x15,0x17,0x79,
|
0xB3,0xF5,0xF0,0x67,0x22,0x15,0x17,0x79,
|
||||||
0x1B,0x85,0xA5,0x97,0xB7,0xA9,0x43,0x69,
|
0x1B,0x85,0xA5,0x97,0xB7,0xA9,0x43,0x69,
|
||||||
@@ -453,7 +451,7 @@ fn appendix_a22() {
|
|||||||
// k = 6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F
|
// k = 6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F
|
||||||
// r = C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0
|
// r = C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0
|
||||||
// s = 414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA
|
// s = 414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA
|
||||||
run_rfc6979_test!(Sha1, U256, test, params, public, private,
|
run_rfc6979_test!(SHA1, U256, test, params, public, private,
|
||||||
k vec![0x6E,0xEA,0x48,0x6F,0x9D,0x41,0xA0,0x37,
|
k vec![0x6E,0xEA,0x48,0x6F,0x9D,0x41,0xA0,0x37,
|
||||||
0xB2,0xC6,0x40,0xBC,0x56,0x45,0x69,0x4F,
|
0xB2,0xC6,0x40,0xBC,0x56,0x45,0x69,0x4F,
|
||||||
0xF8,0xFF,0x4B,0x98,0xD0,0x66,0xA2,0x5F,
|
0xF8,0xFF,0x4B,0x98,0xD0,0x66,0xA2,0x5F,
|
||||||
@@ -470,7 +468,7 @@ fn appendix_a22() {
|
|||||||
// k = 06BD4C05ED74719106223BE33F2D95DA6B3B541DAD7BFBD7AC508213B6DA6670
|
// k = 06BD4C05ED74719106223BE33F2D95DA6B3B541DAD7BFBD7AC508213B6DA6670
|
||||||
// r = 272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3
|
// r = 272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3
|
||||||
// s = E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806
|
// s = E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806
|
||||||
run_rfc6979_test!(Sha224, U256, test, params, public, private,
|
run_rfc6979_test!(SHA224, U256, test, params, public, private,
|
||||||
k vec![0x06,0xBD,0x4C,0x05,0xED,0x74,0x71,0x91,
|
k vec![0x06,0xBD,0x4C,0x05,0xED,0x74,0x71,0x91,
|
||||||
0x06,0x22,0x3B,0xE3,0x3F,0x2D,0x95,0xDA,
|
0x06,0x22,0x3B,0xE3,0x3F,0x2D,0x95,0xDA,
|
||||||
0x6B,0x3B,0x54,0x1D,0xAD,0x7B,0xFB,0xD7,
|
0x6B,0x3B,0x54,0x1D,0xAD,0x7B,0xFB,0xD7,
|
||||||
@@ -487,7 +485,7 @@ fn appendix_a22() {
|
|||||||
// k = 1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7
|
// k = 1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7
|
||||||
// r = 8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0
|
// r = 8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0
|
||||||
// s = 7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E
|
// s = 7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E
|
||||||
run_rfc6979_test!(Sha256, U256, test, params, public, private,
|
run_rfc6979_test!(SHA256, U256, test, params, public, private,
|
||||||
k vec![0x1D,0x6C,0xE6,0xDD,0xA1,0xC5,0xD3,0x73,
|
k vec![0x1D,0x6C,0xE6,0xDD,0xA1,0xC5,0xD3,0x73,
|
||||||
0x07,0x83,0x9C,0xD0,0x3A,0xB0,0xA5,0xCB,
|
0x07,0x83,0x9C,0xD0,0x3A,0xB0,0xA5,0xCB,
|
||||||
0xB1,0x8E,0x60,0xD8,0x00,0x93,0x7D,0x67,
|
0xB1,0x8E,0x60,0xD8,0x00,0x93,0x7D,0x67,
|
||||||
@@ -504,7 +502,7 @@ fn appendix_a22() {
|
|||||||
// k = 206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C
|
// k = 206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C
|
||||||
// r = 239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE
|
// r = 239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE
|
||||||
// s = 6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961
|
// s = 6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961
|
||||||
run_rfc6979_test!(Sha384, U256, test, params, public, private,
|
run_rfc6979_test!(SHA384, U256, test, params, public, private,
|
||||||
k vec![0x20,0x6E,0x61,0xF7,0x3D,0xBE,0x1B,0x2D,
|
k vec![0x20,0x6E,0x61,0xF7,0x3D,0xBE,0x1B,0x2D,
|
||||||
0xC8,0xBE,0x73,0x6B,0x22,0xB0,0x79,0xE9,
|
0xC8,0xBE,0x73,0x6B,0x22,0xB0,0x79,0xE9,
|
||||||
0xDA,0xCD,0x97,0x4D,0xB0,0x0E,0xEB,0xBC,
|
0xDA,0xCD,0x97,0x4D,0xB0,0x0E,0xEB,0xBC,
|
||||||
@@ -521,7 +519,7 @@ fn appendix_a22() {
|
|||||||
// k = AFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA
|
// k = AFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA
|
||||||
// r = 89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307
|
// r = 89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307
|
||||||
// s = C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1
|
// s = C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1
|
||||||
run_rfc6979_test!(Sha512, U256, test, params, public, private,
|
run_rfc6979_test!(SHA512, U256, test, params, public, private,
|
||||||
k vec![0xAF,0xF1,0x65,0x1E,0x4C,0xD6,0x03,0x6D,
|
k vec![0xAF,0xF1,0x65,0x1E,0x4C,0xD6,0x03,0x6D,
|
||||||
0x57,0xAA,0x8B,0x2A,0x05,0xCC,0xF1,0xA9,
|
0x57,0xAA,0x8B,0x2A,0x05,0xCC,0xF1,0xA9,
|
||||||
0xD5,0xA4,0x01,0x66,0x34,0x0E,0xCB,0xBD,
|
0xD5,0xA4,0x01,0x66,0x34,0x0E,0xCB,0xBD,
|
||||||
|
|||||||
@@ -1,28 +1,54 @@
|
|||||||
use cryptonum::signed::{I192,I256,I384,I576};
|
use cryptonum::signed::{I192,I256,I384,I576};
|
||||||
use cryptonum::unsigned::{Decoder};
|
use cryptonum::unsigned::{Decoder};
|
||||||
use cryptonum::unsigned::{U192,U256,U384,U576};
|
use cryptonum::unsigned::{U192,U256,U384,U576};
|
||||||
|
use ecdsa::point::Point;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
/// Elliptic curves must implement this trait in order to work with the rest
|
||||||
|
/// of the ECDSA system. I've included instances for the core NIST curves
|
||||||
|
/// used in most systems, but this could be extended without issues.
|
||||||
|
/// (Eventually the curves defined here should actually be extended in
|
||||||
|
/// interesting ways to make the math faster, but we haven't gotten there
|
||||||
|
/// yet.)
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub trait EllipticCurve {
|
pub trait EllipticCurve {
|
||||||
|
/// The unsigned numeric type that fits constants for this curve.
|
||||||
type Unsigned : Clone;
|
type Unsigned : Clone;
|
||||||
type Signed : Clone;
|
/// The signed numeric type that fits constants for this curve.
|
||||||
|
type Signed : Clone + Debug + PartialEq;
|
||||||
|
/// The type of a point on the curve
|
||||||
|
type Point;
|
||||||
|
|
||||||
|
/// The size of the curve in bits.
|
||||||
fn size() -> usize;
|
fn size() -> usize;
|
||||||
|
/// The `p` value for the curve.
|
||||||
fn p() -> Self::Unsigned;
|
fn p() -> Self::Unsigned;
|
||||||
|
/// The `p` value for the curve.
|
||||||
fn n() -> Self::Unsigned;
|
fn n() -> Self::Unsigned;
|
||||||
|
/// The seed value for the curve.
|
||||||
fn SEED() -> Self::Unsigned;
|
fn SEED() -> Self::Unsigned;
|
||||||
|
/// The `c` value for the curve.
|
||||||
fn c() -> Self::Unsigned;
|
fn c() -> Self::Unsigned;
|
||||||
|
/// The `a` value for the curve.
|
||||||
fn a() -> Self::Unsigned;
|
fn a() -> Self::Unsigned;
|
||||||
|
/// The `b` value for the curve.
|
||||||
fn b() -> Self::Unsigned;
|
fn b() -> Self::Unsigned;
|
||||||
|
/// The `x` coordinate of the base point for the curve.
|
||||||
fn Gx() -> Self::Signed;
|
fn Gx() -> Self::Signed;
|
||||||
|
/// The `y` coordinate of the base point for the curve.
|
||||||
fn Gy() -> Self::Signed;
|
fn Gy() -> Self::Signed;
|
||||||
|
/// Generate a point for the curve given the provided values.
|
||||||
|
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum P192 {}
|
/// NIST curve P-192 (FIPS 186-4, page 101-102), a.k.a. secp192r1 from RFC5480
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct P192 {}
|
||||||
|
|
||||||
impl EllipticCurve for P192 {
|
impl EllipticCurve for P192 {
|
||||||
type Unsigned = U192;
|
type Unsigned = U192;
|
||||||
type Signed = I192;
|
type Signed = I192;
|
||||||
|
type Point = Point<P192>;
|
||||||
|
|
||||||
fn size() -> usize {
|
fn size() -> usize {
|
||||||
192
|
192
|
||||||
@@ -59,13 +85,20 @@ impl EllipticCurve for P192 {
|
|||||||
fn Gy() -> I192 {
|
fn Gy() -> I192 {
|
||||||
I192::from(U192::from([0x73f977a11e794811, 0x631011ed6b24cdd5, 0x07192b95ffc8da78]))
|
I192::from(U192::from([0x73f977a11e794811, 0x631011ed6b24cdd5, 0x07192b95ffc8da78]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
|
||||||
|
Point::<P192>{ x: I192::from(x), y: I192::from(y) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum P224 {}
|
/// NIST curve P-224 (FIPS 186-4, page 102), a.k.a. secp224r1 from RFC5480
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct P224 {}
|
||||||
|
|
||||||
impl EllipticCurve for P224 {
|
impl EllipticCurve for P224 {
|
||||||
type Unsigned = U256;
|
type Unsigned = U256;
|
||||||
type Signed = I256;
|
type Signed = I256;
|
||||||
|
type Point = Point<P224>;
|
||||||
|
|
||||||
fn size() -> usize {
|
fn size() -> usize {
|
||||||
224
|
224
|
||||||
@@ -141,13 +174,20 @@ impl EllipticCurve for P224 {
|
|||||||
0x85, 0x00, 0x7e, 0x34
|
0x85, 0x00, 0x7e, 0x34
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
|
||||||
|
Point::<P224>{ x: I256::from(x), y: I256::from(y) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum P256 {}
|
/// NIST curve P-256 (FIPS 186-4, page 102-103), a.k.a. secp256r1 from RFC5480
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct P256 {}
|
||||||
|
|
||||||
impl EllipticCurve for P256 {
|
impl EllipticCurve for P256 {
|
||||||
type Signed = I256;
|
type Signed = I256;
|
||||||
type Unsigned = U256;
|
type Unsigned = U256;
|
||||||
|
type Point = Point<P256>;
|
||||||
|
|
||||||
fn size() -> usize {
|
fn size() -> usize {
|
||||||
256
|
256
|
||||||
@@ -224,13 +264,20 @@ impl EllipticCurve for P256 {
|
|||||||
0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5
|
0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
|
||||||
|
Point::<P256>{ x: I256::from(x), y: I256::from(y) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum P384 {}
|
/// NIST curve P-384 (FIPS 186-4, page 103-104), a.k.a. secp384r1 from RFC5480
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct P384 {}
|
||||||
|
|
||||||
impl EllipticCurve for P384 {
|
impl EllipticCurve for P384 {
|
||||||
type Signed = I384;
|
type Signed = I384;
|
||||||
type Unsigned = U384;
|
type Unsigned = U384;
|
||||||
|
type Point = Point<P384>;
|
||||||
|
|
||||||
fn size() -> usize {
|
fn size() -> usize {
|
||||||
384
|
384
|
||||||
@@ -320,13 +367,20 @@ impl EllipticCurve for P384 {
|
|||||||
0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f
|
0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
|
||||||
|
Point::<P384>{ x: I384::from(x), y: I384::from(y) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum P521 {}
|
/// NIST curve P-521 (FIPS 186-4, page 104), a.k.a. secp521r1 from RFC5480
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct P521 {}
|
||||||
|
|
||||||
impl EllipticCurve for P521 {
|
impl EllipticCurve for P521 {
|
||||||
type Signed = I576;
|
type Signed = I576;
|
||||||
type Unsigned = U576;
|
type Unsigned = U576;
|
||||||
|
type Point = Point<P521>;
|
||||||
|
|
||||||
fn size() -> usize {
|
fn size() -> usize {
|
||||||
521
|
521
|
||||||
@@ -437,4 +491,8 @@ impl EllipticCurve for P521 {
|
|||||||
0x66, 0x50
|
0x66, 0x50
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
|
||||||
|
Point::<P521>{ x: I576::from(x), y: I576::from(y) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,93 @@
|
|||||||
pub mod curve;
|
//! The generation and use of ECDSA keys is pretty straightforward, compared
|
||||||
pub mod point;
|
//! to DSA and RSA. You should be able to find what you want to do in the
|
||||||
pub mod private;
|
//! following code snippet, as an example:
|
||||||
pub mod public;
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use simple_crypto::ecdsa::{ECDSAKeyPair,P384};
|
||||||
|
//! use simple_crypto::sha::SHA256;
|
||||||
|
//!
|
||||||
|
//! // Generate a new ECDSA key for curve P384 (this is a good choice, by
|
||||||
|
//! // the way, if you're wondering which curve to use).
|
||||||
|
//! let mut rng = rand::rngs::OsRng::new().unwrap();
|
||||||
|
//! let kp = ECDSAKeyPair::<P384>::generate(&mut rng);
|
||||||
|
//!
|
||||||
|
//! // Now that you have this key pair, you can sign and verify messages
|
||||||
|
//! // using it. For example, to sign the vector [0,1,2,3,4] with SHA256
|
||||||
|
//! // and then verify that signature, we would write:
|
||||||
|
//! let msg = vec![0,1,2,3,4];
|
||||||
|
//! let sig = kp.private.sign::<SHA256>(&msg);
|
||||||
|
//! assert!( kp.public.verify::<SHA256>(&msg, &sig) );
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
mod curve;
|
||||||
|
pub(crate) mod point;
|
||||||
|
mod private;
|
||||||
|
mod public;
|
||||||
|
|
||||||
use cryptonum::signed::{I192,I256,I384,I576};
|
use cryptonum::signed::{I192,I256,I384,I576};
|
||||||
use cryptonum::unsigned::{CryptoNum,Decoder};
|
use cryptonum::unsigned::{CryptoNum,Decoder};
|
||||||
use cryptonum::unsigned::{U192,U256,U384,U576};
|
use cryptonum::unsigned::{U192,U256,U384,U576};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand::distributions::Standard;
|
use rand::distributions::Standard;
|
||||||
use self::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
pub use self::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
||||||
use self::point::{ECCPoint,Point};
|
use self::point::{ECCPoint,Point};
|
||||||
pub use self::private::{ECCPrivateKey,ECCPrivate};
|
pub use self::private::{ECDSAPrivate,ECCPrivateKey};
|
||||||
pub use self::public::{ECCPublicKey,ECDSAPublic,ECCPubKey};
|
pub use self::public::{ECDSAPublic,ECCPublicKey};
|
||||||
pub use self::public::{ECDSADecodeErr,ECDSAEncodeErr};
|
pub use self::public::{ECDSADecodeErr,ECDSAEncodeErr};
|
||||||
|
use super::KeyPair;
|
||||||
|
|
||||||
pub trait ECDSAKeyPair<Public,Private> {
|
/// An ECDSA key pair for the given curve.
|
||||||
fn generate<G: Rng>(g: &mut G) -> (Public, Private);
|
pub struct ECDSAKeyPair<Curve: EllipticCurve> {
|
||||||
|
pub public: ECCPublicKey<Curve>,
|
||||||
|
pub private: ECCPrivateKey<Curve>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A generic ECDSA key pair that implements one of our known curves, for cases
|
||||||
|
/// when you're not sure which one you're going to have.
|
||||||
|
pub enum ECDSAPair {
|
||||||
|
P192(ECCPublicKey<P192>,ECCPrivateKey<P192>),
|
||||||
|
P224(ECCPublicKey<P224>,ECCPrivateKey<P224>),
|
||||||
|
P256(ECCPublicKey<P256>,ECCPrivateKey<P256>),
|
||||||
|
P384(ECCPublicKey<P384>,ECCPrivateKey<P384>),
|
||||||
|
P521(ECCPublicKey<P521>,ECCPrivateKey<P521>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyPair for ECDSAPair {
|
||||||
|
type Public = ECDSAPublic;
|
||||||
|
type Private = ECDSAPrivate;
|
||||||
|
|
||||||
|
fn new(pu: ECDSAPublic, pr: ECDSAPrivate) -> ECDSAPair
|
||||||
|
{
|
||||||
|
match (pu, pr) {
|
||||||
|
(ECDSAPublic::P192(pbl),ECDSAPrivate::P192(prv)) => ECDSAPair::P192(pbl,prv),
|
||||||
|
(ECDSAPublic::P224(pbl),ECDSAPrivate::P224(prv)) => ECDSAPair::P224(pbl,prv),
|
||||||
|
(ECDSAPublic::P256(pbl),ECDSAPrivate::P256(prv)) => ECDSAPair::P256(pbl,prv),
|
||||||
|
(ECDSAPublic::P384(pbl),ECDSAPrivate::P384(prv)) => ECDSAPair::P384(pbl,prv),
|
||||||
|
(ECDSAPublic::P521(pbl),ECDSAPrivate::P521(prv)) => ECDSAPair::P521(pbl,prv),
|
||||||
|
_ =>
|
||||||
|
panic!("Non-matching public/private pairs in ECDSAPair::new()")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! generate_impl {
|
macro_rules! generate_impl {
|
||||||
($curve: ident, $un: ident, $si: ident) => {
|
($curve: ident, $un: ident, $si: ident) => {
|
||||||
impl ECDSAKeyPair<ECCPubKey<$curve>,ECCPrivate<$curve>> for $curve {
|
impl KeyPair for ECDSAKeyPair<$curve> {
|
||||||
fn generate<G: Rng>(rng: &mut G) -> (ECCPubKey<$curve>, ECCPrivate<$curve>)
|
type Public = ECCPublicKey<$curve>;
|
||||||
|
type Private = ECCPrivateKey<$curve>;
|
||||||
|
|
||||||
|
fn new(public: ECCPublicKey<$curve>, private: ECCPrivateKey<$curve>) -> ECDSAKeyPair<$curve>
|
||||||
|
{
|
||||||
|
ECDSAKeyPair{ public, private }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ECDSAKeyPair<$curve> {
|
||||||
|
/// Generate a fresh ECDSA key pair for this curve, given the
|
||||||
|
/// provided random number generator. THIS MUST BE A CRYPTO
|
||||||
|
/// STRONG RNG. If it's not, then you're going to generate weak
|
||||||
|
/// keys and the crypto gremlins will get you.
|
||||||
|
pub fn generate<G: Rng>(rng: &mut G) -> ECDSAKeyPair<$curve>
|
||||||
{
|
{
|
||||||
loop {
|
loop {
|
||||||
let size = ($curve::size() + 7) / 8;
|
let size = ($curve::size() + 7) / 8;
|
||||||
@@ -38,9 +104,10 @@ macro_rules! generate_impl {
|
|||||||
|
|
||||||
let d = $si::from(&proposed_d);
|
let d = $si::from(&proposed_d);
|
||||||
let public_point = Point::<$curve>::default().scale(&d);
|
let public_point = Point::<$curve>::default().scale(&d);
|
||||||
let public = ECCPubKey::<$curve>::new(public_point);
|
let public = ECCPublicKey::<$curve>::new(public_point);
|
||||||
let private = ECCPrivate::<$curve>::new(proposed_d);
|
let private = ECCPrivateKey::<$curve>::new(proposed_d);
|
||||||
return (public, private);
|
|
||||||
|
return ECDSAKeyPair{ public, private };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ pub trait ECCPoint : Sized {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
pub struct Point<T: EllipticCurve>
|
pub struct Point<T: EllipticCurve>
|
||||||
{
|
{
|
||||||
pub x: T::Signed,
|
pub x: T::Signed,
|
||||||
|
|||||||
@@ -1,41 +1,47 @@
|
|||||||
use cryptonum::signed::*;
|
use cryptonum::signed::*;
|
||||||
use cryptonum::unsigned::*;
|
use cryptonum::unsigned::*;
|
||||||
use digest::{BlockInput,Digest,Input,FixedOutput,Reset};
|
|
||||||
use dsa::rfc6979::{DSASignature,KIterator,bits2int};
|
use dsa::rfc6979::{DSASignature,KIterator,bits2int};
|
||||||
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
||||||
use ecdsa::point::{ECCPoint,Point};
|
use ecdsa::point::{ECCPoint,Point};
|
||||||
use hmac::{Hmac,Mac};
|
use sha::Hash;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
pub struct ECCPrivate<Curve: EllipticCurve> {
|
/// A private key for the given curve.
|
||||||
d: Curve::Unsigned
|
#[derive(PartialEq)]
|
||||||
|
pub struct ECCPrivateKey<Curve: EllipticCurve> {
|
||||||
|
pub(crate) d: Curve::Unsigned
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ECCPrivateKey {
|
impl<Curve: EllipticCurve> fmt::Debug for ECCPrivateKey<Curve> {
|
||||||
type Unsigned;
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error>
|
||||||
|
{
|
||||||
|
f.write_str("<ECCPrivateKey>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn new(d: Self::Unsigned) -> Self;
|
/// A generic private key.
|
||||||
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<Self::Unsigned>
|
pub enum ECDSAPrivate {
|
||||||
where
|
P192(ECCPrivateKey<P192>),
|
||||||
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
P224(ECCPrivateKey<P224>),
|
||||||
Hmac<Hash>: Mac;
|
P256(ECCPrivateKey<P256>),
|
||||||
|
P384(ECCPrivateKey<P384>),
|
||||||
|
P521(ECCPrivateKey<P521>),
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! generate_privates
|
macro_rules! generate_privates
|
||||||
{
|
{
|
||||||
($curve: ident, $base: ident, $sig: ident, $dbl: ident, $quad: ident) => {
|
($curve: ident, $base: ident, $sig: ident, $dbl: ident, $quad: ident) => {
|
||||||
impl ECCPrivateKey for ECCPrivate<$curve>
|
impl ECCPrivateKey<$curve>
|
||||||
{
|
{
|
||||||
type Unsigned = $base;
|
/// Generate a new private key using the given private scalar.
|
||||||
|
pub fn new(d: $base) -> ECCPrivateKey<$curve>
|
||||||
fn new(d: $base) -> ECCPrivate<$curve>
|
|
||||||
{
|
{
|
||||||
ECCPrivate{ d }
|
ECCPrivateKey{ d }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<$base>
|
/// Sign the given message with the current key, using the hash provided
|
||||||
where
|
/// in the type.
|
||||||
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
pub fn sign<H: Hash + Clone>(&self, m: &[u8]) -> DSASignature<$base>
|
||||||
Hmac<Hash>: Mac
|
|
||||||
{
|
{
|
||||||
// This algorithm is per RFC 6979, which has a nice, relatively
|
// This algorithm is per RFC 6979, which has a nice, relatively
|
||||||
// straightforward description of how to do DSA signing.
|
// straightforward description of how to do DSA signing.
|
||||||
@@ -48,7 +54,7 @@ macro_rules! generate_privates
|
|||||||
// As was noted in the description of bits2octets, the extra
|
// As was noted in the description of bits2octets, the extra
|
||||||
// modular reduction is no more than a conditional subtraction.
|
// modular reduction is no more than a conditional subtraction.
|
||||||
//
|
//
|
||||||
let h1 = <Hash>::digest(m);
|
let h1 = <H>::hash(m);
|
||||||
let size = <$curve>::size();
|
let size = <$curve>::size();
|
||||||
let h0: $base = bits2int(&h1, size);
|
let h0: $base = bits2int(&h1, size);
|
||||||
let n = <$curve>::n();
|
let n = <$curve>::n();
|
||||||
@@ -60,7 +66,7 @@ macro_rules! generate_privates
|
|||||||
// process used to generate k. In plain DSA or ECDSA, k should
|
// process used to generate k. In plain DSA or ECDSA, k should
|
||||||
// be selected through a random selection that chooses a value
|
// be selected through a random selection that chooses a value
|
||||||
// among the q-1 possible values with uniform probability.
|
// among the q-1 possible values with uniform probability.
|
||||||
for k in KIterator::<Hash,$base>::new(&h1, size, &n, &self.d) {
|
for k in KIterator::<H,$base>::new(&h1, size, &n, &self.d) {
|
||||||
// 3. A value r (modulo q) is computed from k and the key
|
// 3. A value r (modulo q) is computed from k and the key
|
||||||
// parameters:
|
// parameters:
|
||||||
// * For DSA ...
|
// * For DSA ...
|
||||||
@@ -108,7 +114,7 @@ generate_privates!(P521, U576, I576, U1152, U2304);
|
|||||||
/************* TESTING ********************************************************/
|
/************* TESTING ********************************************************/
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use testing::*;
|
use testing::*;
|
||||||
|
|
||||||
@@ -136,12 +142,12 @@ macro_rules! sign_test_body
|
|||||||
let r = $base::from_bytes(rbytes);
|
let r = $base::from_bytes(rbytes);
|
||||||
let s = $base::from_bytes(sbytes);
|
let s = $base::from_bytes(sbytes);
|
||||||
|
|
||||||
let private = ECCPrivate::<$curve>::new(d);
|
let private = ECCPrivateKey::<$curve>::new(d);
|
||||||
let sig = match usize::from(h) {
|
let sig = match usize::from(h) {
|
||||||
224 => private.sign::<Sha224>(mbytes),
|
224 => private.sign::<SHA224>(mbytes),
|
||||||
256 => private.sign::<Sha256>(mbytes),
|
256 => private.sign::<SHA256>(mbytes),
|
||||||
384 => private.sign::<Sha384>(mbytes),
|
384 => private.sign::<SHA384>(mbytes),
|
||||||
512 => private.sign::<Sha512>(mbytes),
|
512 => private.sign::<SHA512>(mbytes),
|
||||||
x => panic!("Unknown hash algorithm {}", x)
|
x => panic!("Unknown hash algorithm {}", x)
|
||||||
};
|
};
|
||||||
assert_eq!(r, sig.r, "r signature check");
|
assert_eq!(r, sig.r, "r signature check");
|
||||||
|
|||||||
@@ -1,36 +1,30 @@
|
|||||||
use cryptonum::signed::*;
|
use cryptonum::signed::*;
|
||||||
use cryptonum::unsigned::*;
|
use cryptonum::unsigned::*;
|
||||||
use digest::{BlockInput,Digest,Input,FixedOutput,Reset};
|
|
||||||
use dsa::rfc6979::DSASignature;
|
use dsa::rfc6979::DSASignature;
|
||||||
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
||||||
use ecdsa::point::{ECCPoint,Point};
|
use ecdsa::point::{ECCPoint,Point};
|
||||||
use hmac::{Hmac,Mac};
|
use sha::Hash;
|
||||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,FromASN1,ToASN1};
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,FromASN1,ToASN1};
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
|
||||||
pub struct ECCPubKey<Curve: EllipticCurve> {
|
/// An ECDSA public key for the given curve.
|
||||||
q: Point<Curve>
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct ECCPublicKey<Curve: EllipticCurve> {
|
||||||
|
pub(crate) q: Point<Curve>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A generic ECDSA public key, when you're not sure which curve you're
|
||||||
|
/// going to get.
|
||||||
pub enum ECDSAPublic {
|
pub enum ECDSAPublic {
|
||||||
ECCPublicP192(ECCPubKey<P192>),
|
P192(ECCPublicKey<P192>),
|
||||||
ECCPublicP224(ECCPubKey<P224>),
|
P224(ECCPublicKey<P224>),
|
||||||
ECCPublicP256(ECCPubKey<P256>),
|
P256(ECCPublicKey<P256>),
|
||||||
ECCPublicP384(ECCPubKey<P384>),
|
P384(ECCPublicKey<P384>),
|
||||||
ECCPublicP521(ECCPubKey<P521>),
|
P521(ECCPublicKey<P521>),
|
||||||
}
|
|
||||||
|
|
||||||
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: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
|
||||||
Hmac<Hash>: Mac;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An error that can occur when encoding an ECDSA public key as an ASN.1
|
||||||
|
/// object.
|
||||||
pub enum ECDSAEncodeErr {
|
pub enum ECDSAEncodeErr {
|
||||||
ASN1EncodeErr(ASN1EncodeErr),
|
ASN1EncodeErr(ASN1EncodeErr),
|
||||||
XValueNegative, YValueNegative
|
XValueNegative, YValueNegative
|
||||||
@@ -42,6 +36,8 @@ impl From<ASN1EncodeErr> for ECDSAEncodeErr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An error that can occur when decoding an ECDSA public key from an
|
||||||
|
/// ASN.1 blob.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ECDSADecodeErr {
|
pub enum ECDSADecodeErr {
|
||||||
ASN1DecodeErr(ASN1DecodeErr),
|
ASN1DecodeErr(ASN1DecodeErr),
|
||||||
@@ -58,20 +54,17 @@ impl From<ASN1DecodeErr> for ECDSADecodeErr {
|
|||||||
|
|
||||||
macro_rules! public_impl {
|
macro_rules! public_impl {
|
||||||
($curve: ident, $un: ident, $si: ident) => {
|
($curve: ident, $un: ident, $si: ident) => {
|
||||||
impl ECCPublicKey for ECCPubKey<$curve>
|
impl ECCPublicKey<$curve>
|
||||||
{
|
{
|
||||||
type Curve = $curve;
|
/// Generate a new public key object from the given public point.
|
||||||
type Unsigned = $un;
|
pub fn new(q: Point<$curve>) -> ECCPublicKey<$curve>
|
||||||
|
|
||||||
fn new(q: Point<$curve>) -> ECCPubKey<$curve>
|
|
||||||
{
|
{
|
||||||
ECCPubKey{ q }
|
ECCPublicKey{ q }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<Self::Unsigned>) -> bool
|
/// Returns true if the given message matches the given signature,
|
||||||
where
|
/// assuming the provided hash function.
|
||||||
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
pub fn verify<H: Hash>(&self, m: &[u8], sig: &DSASignature<$un>) -> bool
|
||||||
Hmac<Hash>: Mac
|
|
||||||
{
|
{
|
||||||
let n = <$curve>::n();
|
let n = <$curve>::n();
|
||||||
|
|
||||||
@@ -84,7 +77,7 @@ macro_rules! public_impl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// e = the leftmost min(N, outlen) bits of Hash(M').
|
// e = the leftmost min(N, outlen) bits of Hash(M').
|
||||||
let mut digest_bytes = <Hash>::digest(m).to_vec();
|
let mut digest_bytes = <H>::hash(m);
|
||||||
let len = min(digest_bytes.len(), $curve::size() / 8);
|
let len = min(digest_bytes.len(), $curve::size() / 8);
|
||||||
digest_bytes.truncate(len);
|
digest_bytes.truncate(len);
|
||||||
|
|
||||||
@@ -103,7 +96,7 @@ macro_rules! public_impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToASN1 for ECCPubKey<$curve> {
|
impl ToASN1 for ECCPublicKey<$curve> {
|
||||||
type Error = ECDSAEncodeErr;
|
type Error = ECDSAEncodeErr;
|
||||||
|
|
||||||
fn to_asn1_class(&self, c: ASN1Class) -> Result<Vec<ASN1Block>,ECDSAEncodeErr>
|
fn to_asn1_class(&self, c: ASN1Class) -> Result<Vec<ASN1Block>,ECDSAEncodeErr>
|
||||||
@@ -136,10 +129,10 @@ macro_rules! public_impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromASN1 for ECCPubKey<$curve> {
|
impl FromASN1 for ECCPublicKey<$curve> {
|
||||||
type Error = ECDSADecodeErr;
|
type Error = ECDSADecodeErr;
|
||||||
|
|
||||||
fn from_asn1(bs: &[ASN1Block]) -> Result<(ECCPubKey<$curve>,&[ASN1Block]),ECDSADecodeErr>
|
fn from_asn1(bs: &[ASN1Block]) -> Result<(ECCPublicKey<$curve>,&[ASN1Block]),ECDSADecodeErr>
|
||||||
{
|
{
|
||||||
let (x, rest) = bs.split_first().ok_or(ECDSADecodeErr::NoKeyFound)?;
|
let (x, rest) = bs.split_first().ok_or(ECDSADecodeErr::NoKeyFound)?;
|
||||||
if let ASN1Block::BitString(_, _, _, target) = x {
|
if let ASN1Block::BitString(_, _, _, target) = x {
|
||||||
@@ -155,7 +148,7 @@ macro_rules! public_impl {
|
|||||||
let x = $un::from_bytes(xbstr);
|
let x = $un::from_bytes(xbstr);
|
||||||
let y = $un::from_bytes(ybstr);
|
let y = $un::from_bytes(ybstr);
|
||||||
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
|
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
|
||||||
let res = ECCPubKey::<$curve>::new(point);
|
let res = ECCPublicKey::<$curve>::new(point);
|
||||||
Ok((res, rest))
|
Ok((res, rest))
|
||||||
} else {
|
} else {
|
||||||
Err(ECDSADecodeErr::InvalidKeyFormat)
|
Err(ECDSADecodeErr::InvalidKeyFormat)
|
||||||
@@ -172,7 +165,7 @@ public_impl!(P384, U384, I384);
|
|||||||
public_impl!(P521, U576, I576);
|
public_impl!(P521, U576, I576);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use testing::*;
|
use testing::*;
|
||||||
|
|
||||||
@@ -201,13 +194,13 @@ macro_rules! verify_test_body
|
|||||||
let s = $un::from_bytes(sbytes);
|
let s = $un::from_bytes(sbytes);
|
||||||
|
|
||||||
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
|
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
|
||||||
let public = ECCPubKey::<$curve>::new(point);
|
let public = ECCPublicKey::<$curve>::new(point);
|
||||||
let sig = DSASignature::new(r, s);
|
let sig = DSASignature::new(r, s);
|
||||||
match usize::from(h) {
|
match usize::from(h) {
|
||||||
224 => assert!(public.verify::<Sha224>(mbytes, &sig)),
|
224 => assert!(public.verify::<SHA224>(mbytes, &sig)),
|
||||||
256 => assert!(public.verify::<Sha256>(mbytes, &sig)),
|
256 => assert!(public.verify::<SHA256>(mbytes, &sig)),
|
||||||
384 => assert!(public.verify::<Sha384>(mbytes, &sig)),
|
384 => assert!(public.verify::<SHA384>(mbytes, &sig)),
|
||||||
512 => assert!(public.verify::<Sha512>(mbytes, &sig)),
|
512 => assert!(public.verify::<SHA512>(mbytes, &sig)),
|
||||||
x => panic!("Unknown hash algorithm {}", x)
|
x => panic!("Unknown hash algorithm {}", x)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
1500
src/ed25519/constants.rs
Normal file
1500
src/ed25519/constants.rs
Normal file
File diff suppressed because it is too large
Load Diff
1090
src/ed25519/fe.rs
Normal file
1090
src/ed25519/fe.rs
Normal file
File diff suppressed because it is too large
Load Diff
33
src/ed25519/loads.rs
Normal file
33
src/ed25519/loads.rs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
use cryptonum::unsigned::{Decoder,U192};
|
||||||
|
#[cfg(test)]
|
||||||
|
use testing::run_test;
|
||||||
|
|
||||||
|
pub fn load3(x: &[u8]) -> u64
|
||||||
|
{
|
||||||
|
(x[0] as u64) | ((x[1] as u64) << 8) | ((x[2] as u64) << 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load4(x: &[u8]) -> u64
|
||||||
|
{
|
||||||
|
(x[0] as u64) | ((x[1] as u64) << 8) |
|
||||||
|
((x[2] as u64) << 16) | ((x[3] as u64) << 24)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn loads() {
|
||||||
|
let fname = "testdata/ed25519/load.test";
|
||||||
|
run_test(fname.to_string(), 3, |case| {
|
||||||
|
let (negx, xbytes) = case.get("x").unwrap();
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
|
||||||
|
assert!(!negx && !nega && !negb);
|
||||||
|
let res3 = u64::from(U192::from_bytes(abytes));
|
||||||
|
let res4 = u64::from(U192::from_bytes(bbytes));
|
||||||
|
assert_eq!(res3, load3(&xbytes), "load3");
|
||||||
|
assert_eq!(res4, load4(&xbytes), "load4");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
267
src/ed25519/mod.rs
Normal file
267
src/ed25519/mod.rs
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
//! The generation and use of ED25519 keys is the most straightforward
|
||||||
|
//! of all the asymmetric crypto schemes, because you basically get no
|
||||||
|
//! choices. There's just one key size, and you're going to use the
|
||||||
|
//! built-in hash (which is a good one, if you were worried). So if
|
||||||
|
//! you're not sure, this is a pretty good choice.
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use simple_crypto::ed25519::ED25519KeyPair;
|
||||||
|
//!
|
||||||
|
//! // Generate a new ED25519 key
|
||||||
|
//! let mut rng = rand::rngs::OsRng::new().unwrap();
|
||||||
|
//! let kp = ED25519KeyPair::generate(&mut rng);
|
||||||
|
//!
|
||||||
|
//! // Now that you have this key pair, you can sign and verify messages
|
||||||
|
//! // using it. For example, to sign the vector [0,1,2,3,4] and then
|
||||||
|
//! // verify that signature, we would write:
|
||||||
|
//! let msg = vec![0,1,2,3,4];
|
||||||
|
//! let sig = kp.private.sign(&msg);
|
||||||
|
//! assert!( kp.public.verify(&msg, &sig) );
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
mod constants;
|
||||||
|
mod fe;
|
||||||
|
mod loads;
|
||||||
|
mod point;
|
||||||
|
mod scalars;
|
||||||
|
|
||||||
|
use rand::Rng;
|
||||||
|
use sha::{Hash,SHA512};
|
||||||
|
use self::scalars::{curve25519_scalar_mask,x25519_sc_muladd,x25519_sc_reduce};
|
||||||
|
use self::point::{Point,Point2};
|
||||||
|
#[cfg(test)]
|
||||||
|
use testing::run_test;
|
||||||
|
#[cfg(test)]
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use super::KeyPair;
|
||||||
|
|
||||||
|
/// An ED25519 key pair
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct ED25519KeyPair
|
||||||
|
{
|
||||||
|
pub public: ED25519Public,
|
||||||
|
pub private: ED25519Private
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyPair for ED25519KeyPair
|
||||||
|
{
|
||||||
|
type Public = ED25519Public;
|
||||||
|
type Private = ED25519Private;
|
||||||
|
|
||||||
|
fn new(pbl: ED25519Public, prv: ED25519Private) -> ED25519KeyPair
|
||||||
|
{
|
||||||
|
ED25519KeyPair {
|
||||||
|
public: pbl,
|
||||||
|
private: prv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ED25519KeyPair
|
||||||
|
{
|
||||||
|
/// Generate a random ED25519 key pair, using the given random number
|
||||||
|
/// generator. You really need to use a good, cryptographically-strong
|
||||||
|
/// RNG if you want good keys.
|
||||||
|
pub fn generate<G: Rng>(rng: &mut G) -> ED25519KeyPair
|
||||||
|
{
|
||||||
|
let mut seed = [0; 32];
|
||||||
|
rng.fill_bytes(&mut seed);
|
||||||
|
let private = ED25519Private::from_seed(&seed);
|
||||||
|
let public = ED25519Public::from(&private);
|
||||||
|
ED25519KeyPair::new(public, private)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate the ED25519 key pair defined by the given seed value.
|
||||||
|
/// This should be a block of 32 bytes.
|
||||||
|
pub fn from_seed(seed: &[u8]) -> ED25519KeyPair
|
||||||
|
{
|
||||||
|
let private = ED25519Private::from_seed(seed);
|
||||||
|
let public = ED25519Public::from(&private);
|
||||||
|
ED25519KeyPair{ public, private }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An ED25519 private key.
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct ED25519Private
|
||||||
|
{
|
||||||
|
seed: [u8; 32],
|
||||||
|
private: [u8; 32],
|
||||||
|
prefix: [u8; 32],
|
||||||
|
public: [u8; 32]
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ED25519Private {
|
||||||
|
/// Generate the ED25519 private key defined by the given 32 byte seed
|
||||||
|
/// value.
|
||||||
|
pub fn from_seed(seed: &[u8]) -> ED25519Private {
|
||||||
|
let mut result = ED25519Private {
|
||||||
|
seed: [0; 32],
|
||||||
|
private: [0; 32],
|
||||||
|
prefix: [0; 32],
|
||||||
|
public: [0; 32]
|
||||||
|
};
|
||||||
|
result.seed.copy_from_slice(seed);
|
||||||
|
let mut expanded = SHA512::hash(seed);
|
||||||
|
let (private, prefix) = expanded.split_at_mut(32);
|
||||||
|
result.private.copy_from_slice(private);
|
||||||
|
result.prefix.copy_from_slice(prefix);
|
||||||
|
curve25519_scalar_mask(&mut result.private);
|
||||||
|
let a = Point::scalarmult_base(&result.private);
|
||||||
|
result.public.copy_from_slice(&a.encode());
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign the given message, returning the signature. Unlike most other
|
||||||
|
/// public/private schemes, you don't get a choice on the hash used to
|
||||||
|
/// compute this signature. (On the bright side, it's SHA2-512.)
|
||||||
|
pub fn sign(&self, msg: &[u8]) -> Vec<u8>
|
||||||
|
{
|
||||||
|
let mut signature_s = [0u8; 32];
|
||||||
|
|
||||||
|
let mut ctx = SHA512::new();
|
||||||
|
ctx.update(&self.prefix);
|
||||||
|
ctx.update(&msg);
|
||||||
|
let nonce = digest_scalar(&ctx.finalize());
|
||||||
|
let r = Point::scalarmult_base(&nonce);
|
||||||
|
let signature_r = r.encode();
|
||||||
|
let hram_digest = eddsa_digest(&signature_r, &self.public, &msg);
|
||||||
|
let hram = digest_scalar(&hram_digest);
|
||||||
|
x25519_sc_muladd(&mut signature_s, &hram, &self.private, &nonce);
|
||||||
|
let mut result = Vec::with_capacity(64);
|
||||||
|
result.extend_from_slice(&signature_r);
|
||||||
|
result.extend_from_slice(&signature_s);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Covert the given private key into its byte representation. This is
|
||||||
|
/// guaranteed to be exactly 32 bytes.
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
self.seed.to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An ED25519 Public key
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct ED25519Public
|
||||||
|
{
|
||||||
|
bytes: [u8; 32],
|
||||||
|
point: Point
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a ED25519Private> for ED25519Public
|
||||||
|
{
|
||||||
|
fn from(x: &ED25519Private) -> ED25519Public
|
||||||
|
{
|
||||||
|
ED25519Public::new(&x.public).expect("Broke converting private ED25519 to public. (?!)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The kinds of errors you can get when you try to generate a public key from,
|
||||||
|
/// for example, an unknown block of bytes.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ED25519PublicImportError
|
||||||
|
{
|
||||||
|
WrongNumberOfBytes(usize),
|
||||||
|
InvalidPublicPoint
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ED25519Public {
|
||||||
|
/// Generate an ED25519 public key given the provided (32 byte) bytes. This
|
||||||
|
/// can return errors if the value isn't a reasonable representation of an
|
||||||
|
/// ED25519 point.
|
||||||
|
pub fn new(bytes: &[u8]) -> Result<ED25519Public,ED25519PublicImportError>
|
||||||
|
{
|
||||||
|
if bytes.len() != 32 {
|
||||||
|
return Err(ED25519PublicImportError::WrongNumberOfBytes(bytes.len()));
|
||||||
|
}
|
||||||
|
match Point::from_bytes(&bytes) {
|
||||||
|
None =>
|
||||||
|
Err(ED25519PublicImportError::InvalidPublicPoint),
|
||||||
|
Some(a) => {
|
||||||
|
let mut res = ED25519Public{ bytes: [0; 32], point: a };
|
||||||
|
res.bytes.copy_from_slice(&bytes);
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify that the given signature matches the given message.
|
||||||
|
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool
|
||||||
|
{
|
||||||
|
assert_eq!(sig.len(), 64);
|
||||||
|
|
||||||
|
let signature_r = &sig[..32];
|
||||||
|
let signature_s = &sig[32..];
|
||||||
|
|
||||||
|
if signature_s[31] & 0b11100000 != 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ainv = self.point.invert();
|
||||||
|
let h_digest = eddsa_digest(signature_r, &self.bytes, msg);
|
||||||
|
let h = digest_scalar(&h_digest);
|
||||||
|
let r = Point2::double_scalarmult_vartime(&h, &ainv, &signature_s);
|
||||||
|
let r_check = r.encode();
|
||||||
|
signature_r.to_vec() == r_check
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Turn the ED25519 into its byte representation. This will always be a
|
||||||
|
/// 32 byte block.
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
self.bytes.to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eddsa_digest(signature_r: &[u8], public_key: &[u8], msg: &[u8]) -> Vec<u8>
|
||||||
|
{
|
||||||
|
let mut ctx = SHA512::new();
|
||||||
|
ctx.update(signature_r);
|
||||||
|
ctx.update(public_key);
|
||||||
|
ctx.update(msg);
|
||||||
|
ctx.finalize()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn digest_scalar(digest: &[u8]) -> Vec<u8> {
|
||||||
|
assert_eq!(digest.len(), 512/8);
|
||||||
|
let mut copy = [0; 512/8];
|
||||||
|
copy.copy_from_slice(digest);
|
||||||
|
x25519_sc_reduce(&mut copy);
|
||||||
|
copy[..32].to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn run_signing_testcase(case: HashMap<String,(bool,Vec<u8>)>)
|
||||||
|
{
|
||||||
|
let (negr, rbytes) = case.get("r").unwrap();
|
||||||
|
let (negu, ubytes) = case.get("u").unwrap();
|
||||||
|
let (negm, mbytes) = case.get("m").unwrap();
|
||||||
|
let (negs, sbytes) = case.get("s").unwrap();
|
||||||
|
|
||||||
|
assert!(!negr && !negu && !negm && !negs);
|
||||||
|
let keypair = ED25519KeyPair::from_seed(rbytes);
|
||||||
|
assert_eq!(ubytes, &keypair.public.bytes.to_vec());
|
||||||
|
let mut privpub = Vec::new();
|
||||||
|
privpub.append(&mut rbytes.clone());
|
||||||
|
privpub.append(&mut ubytes.clone());
|
||||||
|
let sig = keypair.private.sign(&mbytes);
|
||||||
|
assert_eq!(sig.len(), sbytes.len());
|
||||||
|
assert!(sig.iter().eq(sbytes.iter()));
|
||||||
|
assert!(keypair.public.verify(&mbytes, &sig));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn rfc8072() {
|
||||||
|
let fname = "testdata/ed25519/rfc8032.test";
|
||||||
|
run_test(fname.to_string(), 4, run_signing_testcase);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn signing() {
|
||||||
|
let fname = "testdata/ed25519/sign.test";
|
||||||
|
run_test(fname.to_string(), 4, run_signing_testcase);
|
||||||
|
}
|
||||||
733
src/ed25519/point.rs
Normal file
733
src/ed25519/point.rs
Normal file
@@ -0,0 +1,733 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
use testing::run_test;
|
||||||
|
|
||||||
|
use ed25519::fe::*;
|
||||||
|
use ed25519::constants::*;
|
||||||
|
use std::ops::*;
|
||||||
|
|
||||||
|
// This is ge_p3 in the original source code
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct Point {
|
||||||
|
pub x: FieldElement,
|
||||||
|
pub y: FieldElement,
|
||||||
|
pub z: FieldElement,
|
||||||
|
pub t: FieldElement
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Point {
|
||||||
|
fn zero() -> Point
|
||||||
|
{
|
||||||
|
Point {
|
||||||
|
x: FieldElement::zero(),
|
||||||
|
y: FieldElement::one(),
|
||||||
|
z: FieldElement::one(),
|
||||||
|
t: FieldElement::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn load_test_value(xs: &[u8]) -> Point {
|
||||||
|
assert!(xs.len() == 160);
|
||||||
|
Point {
|
||||||
|
x: test_from_bytes(&xs[0..40]),
|
||||||
|
y: test_from_bytes(&xs[40..80]),
|
||||||
|
z: test_from_bytes(&xs[80..120]),
|
||||||
|
t: test_from_bytes(&xs[120..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert 32 bytes into an ED25519 point. This routine is not
|
||||||
|
/// statically timed, so don't use it if that's important to you.
|
||||||
|
pub fn from_bytes(s: &[u8]) -> Option<Point>
|
||||||
|
{
|
||||||
|
let hy = FieldElement::from_bytes(s);
|
||||||
|
let hz = FieldElement::one();
|
||||||
|
let mut u = hy.square();
|
||||||
|
let mut v = &u * &D;
|
||||||
|
u = &u - &hz; /* u = y^2-1 */
|
||||||
|
v += &hz;
|
||||||
|
|
||||||
|
let mut v3 = v.square();
|
||||||
|
v3 *= &v; /* v3 = v^3 */
|
||||||
|
let mut hx = v3.square();
|
||||||
|
hx *= &v;
|
||||||
|
hx *= &u; /* x = uv^7 */
|
||||||
|
hx = hx.pow22523(); /* x = (uv^7)^((q-5)/8) */
|
||||||
|
hx *= &v3;
|
||||||
|
hx *= &u; /* x = uv^3(uv^7)^((q-5)/8) */
|
||||||
|
|
||||||
|
let mut vxx = hx.square();
|
||||||
|
vxx *= &v;
|
||||||
|
let mut check = &vxx - &u; /* vx^2-u */
|
||||||
|
if check.isnonzero() {
|
||||||
|
check = &vxx + &u;
|
||||||
|
if check.isnonzero() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
hx *= &SQRTM1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if hx.isnegative() != ((s[31] >> 7) == 1) {
|
||||||
|
hx = -&hx;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ht = &hx * &hy;
|
||||||
|
return Some(Point{ x: hx, y: hy, z: hz, t: ht });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode(&self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
into_encoded_point(&self.x, &self.y, &self.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invert(&self) -> Point
|
||||||
|
{
|
||||||
|
Point {
|
||||||
|
x: -&self.x,
|
||||||
|
y: self.y.clone(),
|
||||||
|
z: self.z.clone(),
|
||||||
|
t: -&self.t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const D: FieldElement = FieldElement {
|
||||||
|
value: [-10913610, 13857413, -15372611, 6949391, 114729,
|
||||||
|
-8787816, -6275908, -3247719, -18696448, -12055116]
|
||||||
|
};
|
||||||
|
|
||||||
|
const SQRTM1: FieldElement = FieldElement {
|
||||||
|
value: [-32595792, -7943725, 9377950, 3500415, 12389472,
|
||||||
|
-272473, -25146209, -2005654, 326686, 11406482]
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn from_bytes_vartime() {
|
||||||
|
let fname = "testdata/ed25519/fbv.test";
|
||||||
|
run_test(fname.to_string(), 3, |case| {
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
let (negc, cbytes) = case.get("c").unwrap();
|
||||||
|
|
||||||
|
assert!(!nega && !negb && !negc);
|
||||||
|
let target = Point::load_test_value(&cbytes);
|
||||||
|
let mine = Point::from_bytes(&abytes);
|
||||||
|
if bbytes.len() < cbytes.len() {
|
||||||
|
assert!(mine.is_none());
|
||||||
|
} else {
|
||||||
|
assert_eq!(target, mine.unwrap());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct Point2 {
|
||||||
|
pub x: FieldElement,
|
||||||
|
pub y: FieldElement,
|
||||||
|
pub z: FieldElement,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Point2 {
|
||||||
|
pub fn zero() -> Point2
|
||||||
|
{
|
||||||
|
Point2 {
|
||||||
|
x: FieldElement::zero(),
|
||||||
|
y: FieldElement::one(),
|
||||||
|
z: FieldElement::one()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn load_test_value(xs: &[u8]) -> Point2 {
|
||||||
|
assert!(xs.len() == 120);
|
||||||
|
Point2 {
|
||||||
|
x: test_from_bytes(&xs[0..40]),
|
||||||
|
y: test_from_bytes(&xs[40..80]),
|
||||||
|
z: test_from_bytes(&xs[80..120]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode(&self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
into_encoded_point(&self.x, &self.y, &self.z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a Point> for Point2 {
|
||||||
|
fn from(p: &Point) -> Point2 {
|
||||||
|
Point2 {
|
||||||
|
x: p.x.clone(),
|
||||||
|
y: p.y.clone(),
|
||||||
|
z: p.z.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct PointP1P1 {
|
||||||
|
x: FieldElement,
|
||||||
|
y: FieldElement,
|
||||||
|
z: FieldElement,
|
||||||
|
t: FieldElement
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PointP1P1 {
|
||||||
|
#[cfg(test)]
|
||||||
|
fn load_test_value(xs: &[u8]) -> PointP1P1 {
|
||||||
|
assert!(xs.len() == 160);
|
||||||
|
PointP1P1 {
|
||||||
|
x: test_from_bytes(&xs[0..40]),
|
||||||
|
y: test_from_bytes(&xs[40..80]),
|
||||||
|
z: test_from_bytes(&xs[80..120]),
|
||||||
|
t: test_from_bytes(&xs[120..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
struct Cached {
|
||||||
|
yplusx: FieldElement,
|
||||||
|
yminusx: FieldElement,
|
||||||
|
z: FieldElement,
|
||||||
|
t2d: FieldElement
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cached
|
||||||
|
{
|
||||||
|
fn new() -> Cached
|
||||||
|
{
|
||||||
|
Cached {
|
||||||
|
yplusx: FieldElement::new(),
|
||||||
|
yminusx: FieldElement::new(),
|
||||||
|
z: FieldElement::new(),
|
||||||
|
t2d: FieldElement::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn load_test_value(xs: &[u8]) -> Cached {
|
||||||
|
assert!(xs.len() == 160);
|
||||||
|
Cached {
|
||||||
|
yplusx: test_from_bytes(&xs[0..40]),
|
||||||
|
yminusx: test_from_bytes(&xs[40..80]),
|
||||||
|
z: test_from_bytes(&xs[80..120]),
|
||||||
|
t2d: test_from_bytes(&xs[120..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const D2: FieldElement = FieldElement {
|
||||||
|
value: [-21827239, -5839606, -30745221, 13898782, 229458,
|
||||||
|
15978800, -12551817, -6495438, 29715968, 9444199]
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<'a> From<&'a Point> for Cached
|
||||||
|
{
|
||||||
|
fn from(p: &Point) -> Cached
|
||||||
|
{
|
||||||
|
Cached {
|
||||||
|
yplusx: &p.y + &p.x,
|
||||||
|
yminusx: &p.y - &p.x,
|
||||||
|
z: p.z.clone(),
|
||||||
|
t2d: &p.t * &D2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a PointP1P1> for Point2
|
||||||
|
{
|
||||||
|
fn from(p: &PointP1P1) -> Point2
|
||||||
|
{
|
||||||
|
Point2 {
|
||||||
|
x: &p.x * &p.t,
|
||||||
|
y: &p.y * &p.z,
|
||||||
|
z: &p.z * &p.t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a PointP1P1> for Point
|
||||||
|
{
|
||||||
|
fn from(p: &PointP1P1) -> Point
|
||||||
|
{
|
||||||
|
Point {
|
||||||
|
x: &p.x * &p.t,
|
||||||
|
y: &p.y * &p.z,
|
||||||
|
z: &p.z * &p.t,
|
||||||
|
t: &p.x * &p.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn conversion() {
|
||||||
|
let fname = "testdata/ed25519/conversion.test";
|
||||||
|
run_test(fname.to_string(), 6, |case| {
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negc, cbytes) = case.get("c").unwrap();
|
||||||
|
let (negt, tbytes) = case.get("t").unwrap();
|
||||||
|
let (nego, obytes) = case.get("o").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
|
||||||
|
let a = Point::load_test_value(&abytes);
|
||||||
|
let c = Cached::load_test_value(&cbytes);
|
||||||
|
let t = Point2::load_test_value(&tbytes);
|
||||||
|
let o = PointP1P1::load_test_value(&obytes);
|
||||||
|
let d = Point2::load_test_value(&dbytes);
|
||||||
|
let b = Point::load_test_value(&bbytes);
|
||||||
|
|
||||||
|
assert!(!nega && !negc && !negt && !nego && !negd && !negb);
|
||||||
|
|
||||||
|
let myc = Cached::from(&a);
|
||||||
|
assert_eq!(myc, c);
|
||||||
|
|
||||||
|
let myt = Point2::from(&a);
|
||||||
|
assert_eq!(myt, t);
|
||||||
|
|
||||||
|
let myo = a.double();
|
||||||
|
assert_eq!(myo, o);
|
||||||
|
|
||||||
|
let myd = Point2::from(&o);
|
||||||
|
assert_eq!(myd, d);
|
||||||
|
|
||||||
|
let myb = Point::from(&o);
|
||||||
|
assert_eq!(myb, b);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* r = 2 * p */
|
||||||
|
impl Point2 {
|
||||||
|
fn double(&self) -> PointP1P1
|
||||||
|
{
|
||||||
|
let x0 = self.x.square();
|
||||||
|
let z0 = self.y.square();
|
||||||
|
let t0 = self.z.sq2();
|
||||||
|
let y0 = &self.x + &self.y;
|
||||||
|
let ry = &z0 + &x0;
|
||||||
|
let rz = &z0 - &x0;
|
||||||
|
let rx = &y0.square() - &ry;
|
||||||
|
let rt = &t0 - &rz;
|
||||||
|
PointP1P1 { x: rx, y: ry, z: rz, t: rt }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* r = 2 * p */
|
||||||
|
impl Point {
|
||||||
|
fn double(&self) -> PointP1P1
|
||||||
|
{
|
||||||
|
Point2::from(self).double()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn double() {
|
||||||
|
let fname = "testdata/ed25519/pt_double.test";
|
||||||
|
run_test(fname.to_string(), 4, |case| {
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
let (negc, cbytes) = case.get("c").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
|
||||||
|
assert!(!nega && !negb && !negc && !negd);
|
||||||
|
let a = Point::load_test_value(abytes);
|
||||||
|
let b = PointP1P1::load_test_value(bbytes);
|
||||||
|
let c = Point2::load_test_value(cbytes);
|
||||||
|
let d = PointP1P1::load_test_value(dbytes);
|
||||||
|
|
||||||
|
let myb = a.double();
|
||||||
|
assert_eq!(myb, b);
|
||||||
|
let myd = c.double();
|
||||||
|
assert_eq!(myd, d);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a,'b> Add<&'a Precomp> for &'b Point
|
||||||
|
{
|
||||||
|
type Output = PointP1P1;
|
||||||
|
|
||||||
|
fn add(self, q: &Precomp) -> PointP1P1
|
||||||
|
{
|
||||||
|
let mut rx;
|
||||||
|
let mut ry;
|
||||||
|
let mut rz;
|
||||||
|
let mut rt;
|
||||||
|
|
||||||
|
rx = &self.y + &self.x;
|
||||||
|
ry = &self.y - &self.x;
|
||||||
|
rz = &rx * &q.yplusx;
|
||||||
|
ry *= &q.yminusx;
|
||||||
|
rt = &q.xy2d * &self.t;
|
||||||
|
let t0 = &self.z + &self.z;
|
||||||
|
rx = &rz - &ry;
|
||||||
|
ry += &rz;
|
||||||
|
rz = &t0 + &rt;
|
||||||
|
rt = &t0 - &rt;
|
||||||
|
|
||||||
|
PointP1P1 { x: rx, y: ry, z: rz, t: rt }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a,'b> Sub<&'a Precomp> for &'b Point
|
||||||
|
{
|
||||||
|
type Output = PointP1P1;
|
||||||
|
|
||||||
|
/* r = p - q */
|
||||||
|
fn sub(self, q: &Precomp) -> PointP1P1
|
||||||
|
{
|
||||||
|
let mut rx = &self.y + &self.x;
|
||||||
|
let mut ry = &self.y - &self.x;
|
||||||
|
let mut rz = &rx * &q.yminusx;
|
||||||
|
ry *= &q.yplusx;
|
||||||
|
let mut rt = &q.xy2d * &self.t;
|
||||||
|
let t0 = &self.z + &self.z;
|
||||||
|
rx = &rz - &ry;
|
||||||
|
ry += &rz;
|
||||||
|
rz = &t0 - &rt;
|
||||||
|
rt += &t0;
|
||||||
|
PointP1P1{ x: rx, y: ry, z: rz, t: rt }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn maddsub() {
|
||||||
|
let fname = "testdata/ed25519/maddsub.test";
|
||||||
|
run_test(fname.to_string(), 4, |case| {
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
let (negc, cbytes) = case.get("c").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
|
||||||
|
assert!(!nega && !negb && !negc && !negd);
|
||||||
|
let a = Point::load_test_value(abytes);
|
||||||
|
let b = PointP1P1::load_test_value(bbytes);
|
||||||
|
let c = Precomp::load_test_value(cbytes);
|
||||||
|
let d = PointP1P1::load_test_value(dbytes);
|
||||||
|
|
||||||
|
let myb = &a + &c;
|
||||||
|
assert_eq!(myb, b);
|
||||||
|
let myd = &a - &c;
|
||||||
|
assert_eq!(myd, d);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a,'b> Add<&'a Cached> for &'b Point
|
||||||
|
{
|
||||||
|
type Output = PointP1P1;
|
||||||
|
|
||||||
|
fn add(self, q: &Cached) -> PointP1P1
|
||||||
|
{
|
||||||
|
let mut rx;
|
||||||
|
let mut ry;
|
||||||
|
let mut rz;
|
||||||
|
let mut rt;
|
||||||
|
|
||||||
|
rx = &self.y + &self.x;
|
||||||
|
ry = &self.y - &self.x;
|
||||||
|
rz = &rx * &q.yplusx;
|
||||||
|
ry *= &q.yminusx;
|
||||||
|
rt = &q.t2d * &self.t;
|
||||||
|
rx = &self.z * &q.z;
|
||||||
|
let t0 = &rx + ℞
|
||||||
|
rx = &rz - &ry;
|
||||||
|
ry += &rz;
|
||||||
|
rz = &t0 + &rt;
|
||||||
|
rt = &t0 - &rt;
|
||||||
|
|
||||||
|
PointP1P1{ x: rx, y: ry, z: rz, t: rt }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a,'b> Sub<&'a Cached> for &'b Point
|
||||||
|
{
|
||||||
|
type Output = PointP1P1;
|
||||||
|
|
||||||
|
fn sub(self, q: &Cached) -> PointP1P1
|
||||||
|
{
|
||||||
|
let mut rx;
|
||||||
|
let mut ry;
|
||||||
|
let mut rz;
|
||||||
|
let mut rt;
|
||||||
|
|
||||||
|
rx = &self.y + &self.x;
|
||||||
|
ry = &self.y - &self.x;
|
||||||
|
rz = &rx * &q.yminusx;
|
||||||
|
ry *= &q.yplusx;
|
||||||
|
rt = &q.t2d * &self.t;
|
||||||
|
rx = &self.z * &q.z;
|
||||||
|
let t0 = &rx + ℞
|
||||||
|
rx = &rz - &ry;
|
||||||
|
ry += &rz;
|
||||||
|
rz = &t0 - &rt;
|
||||||
|
rt += &t0;
|
||||||
|
|
||||||
|
PointP1P1{ x: rx, y: ry, z: rz, t: rt }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn addsub() {
|
||||||
|
let fname = "testdata/ed25519/ptaddsub.test";
|
||||||
|
run_test(fname.to_string(), 4, |case| {
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
let (negc, cbytes) = case.get("c").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
|
||||||
|
assert!(!nega && !negb && !negc && !negd);
|
||||||
|
let a = Point::load_test_value(abytes);
|
||||||
|
let b = PointP1P1::load_test_value(bbytes);
|
||||||
|
let c = Cached::load_test_value(cbytes);
|
||||||
|
let d = PointP1P1::load_test_value(dbytes);
|
||||||
|
|
||||||
|
let myb = &a + &c;
|
||||||
|
assert_eq!(myb, b);
|
||||||
|
let myd = &a - &c;
|
||||||
|
assert_eq!(myd, d);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Point {
|
||||||
|
/* h = a * B
|
||||||
|
* where a = a[0]+256*a[1]+...+256^31 a[31]
|
||||||
|
* B is the Ed25519 base point (x,4/5) with x positive.
|
||||||
|
*
|
||||||
|
* Preconditions:
|
||||||
|
* a[31] <= 127 */
|
||||||
|
pub fn scalarmult_base(a: &[u8]) -> Point
|
||||||
|
{
|
||||||
|
let mut e: [i8; 64] = [0; 64];
|
||||||
|
for i in 0..32 {
|
||||||
|
e[2 * i + 0] = ((a[i] >> 0) & 15) as i8;
|
||||||
|
e[2 * i + 1] = ((a[i] >> 4) & 15) as i8;
|
||||||
|
}
|
||||||
|
/* each e[i] is between 0 and 15 */
|
||||||
|
/* e[63] is between 0 and 7 */
|
||||||
|
|
||||||
|
let mut carry = 0;
|
||||||
|
for i in 0..63 {
|
||||||
|
e[i] += carry;
|
||||||
|
carry = e[i] + 8;
|
||||||
|
carry >>= 4;
|
||||||
|
e[i] -= carry << 4;
|
||||||
|
}
|
||||||
|
e[63] += carry;
|
||||||
|
/* each e[i] is between -8 and 8 */
|
||||||
|
|
||||||
|
let mut r;
|
||||||
|
let mut t;
|
||||||
|
|
||||||
|
let mut h = Point::zero();
|
||||||
|
for i in &[1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63] {
|
||||||
|
t = Precomp::table_select(*i / 2, e[*i as usize]);
|
||||||
|
r = &h + &t;
|
||||||
|
h = Point::from(&r);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = h.double();
|
||||||
|
let mut s = Point2::from(&r);
|
||||||
|
r = s.double();
|
||||||
|
s = Point2::from(&r);
|
||||||
|
r = s.double();
|
||||||
|
s = Point2::from(&r);
|
||||||
|
r = s.double();
|
||||||
|
h = Point::from(&r);
|
||||||
|
|
||||||
|
for i in &[0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62] {
|
||||||
|
t = Precomp::table_select(*i / 2, e[*i as usize]);
|
||||||
|
r = &h + &t;
|
||||||
|
h = Point::from(&r);
|
||||||
|
}
|
||||||
|
|
||||||
|
h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn scalarmult_base() {
|
||||||
|
let fname = "testdata/ed25519/scalar_mult.test";
|
||||||
|
run_test(fname.to_string(), 2, |case| {
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
|
||||||
|
assert!(!nega && !negb);
|
||||||
|
let b = Point::load_test_value(bbytes);
|
||||||
|
let mine = Point::scalarmult_base(&abytes);
|
||||||
|
assert_eq!(mine, b);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn slide(r: &mut [i8], a: &[u8])
|
||||||
|
{
|
||||||
|
for i in 0..256 {
|
||||||
|
r[i] = (1 & (a[i >> 3] >> (i & 7))) as i8;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..256 {
|
||||||
|
if r[i] != 0 {
|
||||||
|
let mut b = 1;
|
||||||
|
while (b <= 6) && ((i + b) < 256) {
|
||||||
|
if r[i + b] != 0 {
|
||||||
|
if r[i] + (r[i + b] << b) <= 15 {
|
||||||
|
r[i] += r[i + b] << b;
|
||||||
|
r[i + b] = 0;
|
||||||
|
} else if r[i] - (r[i + b] << b) >= -15 {
|
||||||
|
r[i] -= r[i + b] << b;
|
||||||
|
for k in (i+b)..256 {
|
||||||
|
if r[k] == 0 {
|
||||||
|
r[k] = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r[k] = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn helper_slide() {
|
||||||
|
let fname = "testdata/ed25519/slide.test";
|
||||||
|
run_test(fname.to_string(), 2, |case| {
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
|
||||||
|
assert!(!nega && !negb);
|
||||||
|
let mut mine = [0; 256];
|
||||||
|
slide(&mut mine, &abytes);
|
||||||
|
for i in 0..256 {
|
||||||
|
assert_eq!(mine[i], bbytes[i] as i8);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Point2
|
||||||
|
{
|
||||||
|
/* r = a * A + b * B
|
||||||
|
* where a = a[0]+256*a[1]+...+256^31 a[31].
|
||||||
|
* and b = b[0]+256*b[1]+...+256^31 b[31].
|
||||||
|
* B is the Ed25519 base point (x,4/5) with x positive. */
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn double_scalarmult_vartime(a: &[u8], A: &Point, b: &[u8]) -> Point2
|
||||||
|
{
|
||||||
|
let mut aslide: [i8; 256] = [0; 256];
|
||||||
|
let mut bslide: [i8; 256] = [0; 256];
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
let mut Ai: [Cached; 8] = [Cached::new(), Cached::new(), Cached::new(), Cached::new(),
|
||||||
|
Cached::new(), Cached::new(), Cached::new(), Cached::new()];
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
|
||||||
|
slide(&mut aslide, &a);
|
||||||
|
slide(&mut bslide, &b);
|
||||||
|
|
||||||
|
Ai[0] = Cached::from(A);
|
||||||
|
let mut t = A.double();
|
||||||
|
let A2 = Point::from(&t);
|
||||||
|
t = &A2 + &Ai[0];
|
||||||
|
let mut u = Point::from(&t);
|
||||||
|
Ai[1] = Cached::from(&u);
|
||||||
|
t = &A2 + &Ai[1];
|
||||||
|
u = Point::from(&t);
|
||||||
|
Ai[2] = Cached::from(&u);
|
||||||
|
t = &A2 + &Ai[2];
|
||||||
|
u = Point::from(&t);
|
||||||
|
Ai[3] = Cached::from(&u);
|
||||||
|
t = &A2 + &Ai[3];
|
||||||
|
u = Point::from(&t);
|
||||||
|
Ai[4] = Cached::from(&u);
|
||||||
|
t = &A2 + &Ai[4];
|
||||||
|
u = Point::from(&t);
|
||||||
|
Ai[5] = Cached::from(&u);
|
||||||
|
t = &A2 + &Ai[5];
|
||||||
|
u = Point::from(&t);
|
||||||
|
Ai[6] = Cached::from(&u);
|
||||||
|
t = &A2 + &Ai[6];
|
||||||
|
u = Point::from(&t);
|
||||||
|
Ai[7] = Cached::from(&u);
|
||||||
|
|
||||||
|
let mut r = Point2::zero();
|
||||||
|
|
||||||
|
let mut i: i32 = 255;
|
||||||
|
loop {
|
||||||
|
if (aslide[i as usize] != 0) || (bslide[i as usize] != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i -= 1;
|
||||||
|
if i < 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while i >= 0 {
|
||||||
|
t = r.double();
|
||||||
|
|
||||||
|
if aslide[i as usize] > 0 {
|
||||||
|
u = Point::from(&t);
|
||||||
|
let idx = (aslide[i as usize] / 2) as usize;
|
||||||
|
t = &u + &Ai[idx]
|
||||||
|
} else if aslide[i as usize] < 0 {
|
||||||
|
u = Point::from(&t);
|
||||||
|
let idx = ((-aslide[i as usize]) / 2) as usize;
|
||||||
|
t = &u - &Ai[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
if bslide[i as usize] > 0 {
|
||||||
|
u = Point::from(&t);
|
||||||
|
let idx = (bslide[i as usize] / 2) as usize;
|
||||||
|
t = &u + &BI[idx];
|
||||||
|
} else if bslide[i as usize] < 0 {
|
||||||
|
u = Point::from(&t);
|
||||||
|
let idx = ((-bslide[i as usize]) / 2) as usize;
|
||||||
|
t = &u - &BI[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
r = Point2::from(&t);
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn double_scalarmult() {
|
||||||
|
let fname = "testdata/ed25519/scalar_mult_gen.test";
|
||||||
|
run_test(fname.to_string(), 4, |case| {
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
let (negc, cbytes) = case.get("c").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
|
||||||
|
assert!(!nega && !negb && !negc && !negd);
|
||||||
|
let b = Point::load_test_value(bbytes);
|
||||||
|
let d = Point2::load_test_value(dbytes);
|
||||||
|
let mine = Point2::double_scalarmult_vartime(&abytes, &b, &cbytes);
|
||||||
|
assert_eq!(mine, d);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_encoded_point(x: &FieldElement, y: &FieldElement, z: &FieldElement) -> Vec<u8>
|
||||||
|
{
|
||||||
|
let recip = z.invert();
|
||||||
|
let x_over_z = x * &recip;
|
||||||
|
let y_over_z = y * &recip;
|
||||||
|
let mut bytes = y_over_z.to_bytes();
|
||||||
|
let sign_bit = if x_over_z.isnegative() { 1 } else { 0 };
|
||||||
|
// The preceding computations must execute in constant time, but this
|
||||||
|
// doesn't need to.
|
||||||
|
bytes[31] ^= sign_bit << 7;
|
||||||
|
bytes
|
||||||
|
}
|
||||||
3363
src/ed25519/rfc8032.txt
Normal file
3363
src/ed25519/rfc8032.txt
Normal file
File diff suppressed because it is too large
Load Diff
881
src/ed25519/scalars.rs
Normal file
881
src/ed25519/scalars.rs
Normal file
@@ -0,0 +1,881 @@
|
|||||||
|
use ed25519::loads::{load3,load4};
|
||||||
|
#[cfg(test)]
|
||||||
|
use testing::run_test;
|
||||||
|
|
||||||
|
/* The set of scalars is \Z/l
|
||||||
|
* where l = 2^252 + 27742317777372353535851937790883648493. */
|
||||||
|
|
||||||
|
/* Input:
|
||||||
|
* s[0]+256*s[1]+...+256^63*s[63] = s
|
||||||
|
*
|
||||||
|
* Output:
|
||||||
|
* s[0]+256*s[1]+...+256^31*s[31] = s mod l
|
||||||
|
* where l = 2^252 + 27742317777372353535851937790883648493.
|
||||||
|
* Overwrites s in place. */
|
||||||
|
pub fn x25519_sc_reduce(s: &mut [u8])
|
||||||
|
{
|
||||||
|
let mut s0 : i64 = 2097151 & load3(s) as i64;
|
||||||
|
let mut s1 : i64 = 2097151 & (load4(&s[2..]) >> 5) as i64;
|
||||||
|
let mut s2 : i64 = 2097151 & (load3(&s[5..]) >> 2) as i64;
|
||||||
|
let mut s3 : i64 = 2097151 & (load4(&s[7..]) >> 7) as i64;
|
||||||
|
let mut s4 : i64 = 2097151 & (load4(&s[10..]) >> 4) as i64;
|
||||||
|
let mut s5 : i64 = 2097151 & (load3(&s[13..]) >> 1) as i64;
|
||||||
|
let mut s6 : i64 = 2097151 & (load4(&s[15..]) >> 6) as i64;
|
||||||
|
let mut s7 : i64 = 2097151 & (load3(&s[18..]) >> 3) as i64;
|
||||||
|
let mut s8 : i64 = 2097151 & load3(&s[21..]) as i64;
|
||||||
|
let mut s9 : i64 = 2097151 & (load4(&s[23..]) >> 5) as i64;
|
||||||
|
let mut s10 : i64 = 2097151 & (load3(&s[26..]) >> 2) as i64;
|
||||||
|
let mut s11 : i64 = 2097151 & (load4(&s[28..]) >> 7) as i64;
|
||||||
|
let mut s12 : i64 = 2097151 & (load4(&s[31..]) >> 4) as i64;
|
||||||
|
let mut s13 : i64 = 2097151 & (load3(&s[34..]) >> 1) as i64;
|
||||||
|
let mut s14 : i64 = 2097151 & (load4(&s[36..]) >> 6) as i64;
|
||||||
|
let mut s15 : i64 = 2097151 & (load3(&s[39..]) >> 3) as i64;
|
||||||
|
let mut s16 : i64 = 2097151 & load3(&s[42..]) as i64;
|
||||||
|
let mut s17 : i64 = 2097151 & (load4(&s[44..]) >> 5) as i64;
|
||||||
|
let s18 : i64 = 2097151 & (load3(&s[47..]) >> 2) as i64;
|
||||||
|
let s19 : i64 = 2097151 & (load4(&s[49..]) >> 7) as i64;
|
||||||
|
let s20 : i64 = 2097151 & (load4(&s[52..]) >> 4) as i64;
|
||||||
|
let s21 : i64 = 2097151 & (load3(&s[55..]) >> 1) as i64;
|
||||||
|
let s22 : i64 = 2097151 & (load4(&s[57..]) >> 6) as i64;
|
||||||
|
let s23 : i64 = (load4(&s[60..]) >> 3) as i64 as i64;
|
||||||
|
let mut carry0 : i64;
|
||||||
|
let mut carry1 : i64;
|
||||||
|
let mut carry2 : i64;
|
||||||
|
let mut carry3 : i64;
|
||||||
|
let mut carry4 : i64;
|
||||||
|
let mut carry5 : i64;
|
||||||
|
let mut carry6 : i64;
|
||||||
|
let mut carry7 : i64;
|
||||||
|
let mut carry8 : i64;
|
||||||
|
let mut carry9 : i64;
|
||||||
|
let mut carry10 : i64;
|
||||||
|
let mut carry11 : i64;
|
||||||
|
let carry12 : i64;
|
||||||
|
let carry13 : i64;
|
||||||
|
let carry14 : i64;
|
||||||
|
let carry15 : i64;
|
||||||
|
let carry16 : i64;
|
||||||
|
|
||||||
|
s11 += s23 * 666643;
|
||||||
|
s12 += s23 * 470296;
|
||||||
|
s13 += s23 * 654183;
|
||||||
|
s14 -= s23 * 997805;
|
||||||
|
s15 += s23 * 136657;
|
||||||
|
s16 -= s23 * 683901;
|
||||||
|
//s23 = 0;
|
||||||
|
|
||||||
|
s10 += s22 * 666643;
|
||||||
|
s11 += s22 * 470296;
|
||||||
|
s12 += s22 * 654183;
|
||||||
|
s13 -= s22 * 997805;
|
||||||
|
s14 += s22 * 136657;
|
||||||
|
s15 -= s22 * 683901;
|
||||||
|
//s22 = 0;
|
||||||
|
|
||||||
|
s9 += s21 * 666643;
|
||||||
|
s10 += s21 * 470296;
|
||||||
|
s11 += s21 * 654183;
|
||||||
|
s12 -= s21 * 997805;
|
||||||
|
s13 += s21 * 136657;
|
||||||
|
s14 -= s21 * 683901;
|
||||||
|
//s21 = 0;
|
||||||
|
|
||||||
|
s8 += s20 * 666643;
|
||||||
|
s9 += s20 * 470296;
|
||||||
|
s10 += s20 * 654183;
|
||||||
|
s11 -= s20 * 997805;
|
||||||
|
s12 += s20 * 136657;
|
||||||
|
s13 -= s20 * 683901;
|
||||||
|
//s20 = 0;
|
||||||
|
|
||||||
|
s7 += s19 * 666643;
|
||||||
|
s8 += s19 * 470296;
|
||||||
|
s9 += s19 * 654183;
|
||||||
|
s10 -= s19 * 997805;
|
||||||
|
s11 += s19 * 136657;
|
||||||
|
s12 -= s19 * 683901;
|
||||||
|
//s19 = 0;
|
||||||
|
|
||||||
|
s6 += s18 * 666643;
|
||||||
|
s7 += s18 * 470296;
|
||||||
|
s8 += s18 * 654183;
|
||||||
|
s9 -= s18 * 997805;
|
||||||
|
s10 += s18 * 136657;
|
||||||
|
s11 -= s18 * 683901;
|
||||||
|
//s18 = 0;
|
||||||
|
|
||||||
|
carry6 = (s6 + (1 << 20)) >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry8 = (s8 + (1 << 20)) >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry10 = (s10 + (1 << 20)) >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
carry12 = (s12 + (1 << 20)) >> 21;
|
||||||
|
s13 += carry12;
|
||||||
|
s12 -= carry12 << 21;
|
||||||
|
carry14 = (s14 + (1 << 20)) >> 21;
|
||||||
|
s15 += carry14;
|
||||||
|
s14 -= carry14 << 21;
|
||||||
|
carry16 = (s16 + (1 << 20)) >> 21;
|
||||||
|
s17 += carry16;
|
||||||
|
s16 -= carry16 << 21;
|
||||||
|
|
||||||
|
carry7 = (s7 + (1 << 20)) >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry9 = (s9 + (1 << 20)) >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry11 = (s11 + (1 << 20)) >> 21;
|
||||||
|
s12 += carry11;
|
||||||
|
s11 -= carry11 << 21;
|
||||||
|
carry13 = (s13 + (1 << 20)) >> 21;
|
||||||
|
s14 += carry13;
|
||||||
|
s13 -= carry13 << 21;
|
||||||
|
carry15 = (s15 + (1 << 20)) >> 21;
|
||||||
|
s16 += carry15;
|
||||||
|
s15 -= carry15 << 21;
|
||||||
|
|
||||||
|
s5 += s17 * 666643;
|
||||||
|
s6 += s17 * 470296;
|
||||||
|
s7 += s17 * 654183;
|
||||||
|
s8 -= s17 * 997805;
|
||||||
|
s9 += s17 * 136657;
|
||||||
|
s10 -= s17 * 683901;
|
||||||
|
//s17 = 0;
|
||||||
|
|
||||||
|
s4 += s16 * 666643;
|
||||||
|
s5 += s16 * 470296;
|
||||||
|
s6 += s16 * 654183;
|
||||||
|
s7 -= s16 * 997805;
|
||||||
|
s8 += s16 * 136657;
|
||||||
|
s9 -= s16 * 683901;
|
||||||
|
//s16 = 0;
|
||||||
|
|
||||||
|
s3 += s15 * 666643;
|
||||||
|
s4 += s15 * 470296;
|
||||||
|
s5 += s15 * 654183;
|
||||||
|
s6 -= s15 * 997805;
|
||||||
|
s7 += s15 * 136657;
|
||||||
|
s8 -= s15 * 683901;
|
||||||
|
//s15 = 0;
|
||||||
|
|
||||||
|
s2 += s14 * 666643;
|
||||||
|
s3 += s14 * 470296;
|
||||||
|
s4 += s14 * 654183;
|
||||||
|
s5 -= s14 * 997805;
|
||||||
|
s6 += s14 * 136657;
|
||||||
|
s7 -= s14 * 683901;
|
||||||
|
//s14 = 0;
|
||||||
|
|
||||||
|
s1 += s13 * 666643;
|
||||||
|
s2 += s13 * 470296;
|
||||||
|
s3 += s13 * 654183;
|
||||||
|
s4 -= s13 * 997805;
|
||||||
|
s5 += s13 * 136657;
|
||||||
|
s6 -= s13 * 683901;
|
||||||
|
//s13 = 0;
|
||||||
|
|
||||||
|
s0 += s12 * 666643;
|
||||||
|
s1 += s12 * 470296;
|
||||||
|
s2 += s12 * 654183;
|
||||||
|
s3 -= s12 * 997805;
|
||||||
|
s4 += s12 * 136657;
|
||||||
|
s5 -= s12 * 683901;
|
||||||
|
s12 = 0;
|
||||||
|
|
||||||
|
carry0 = (s0 + (1 << 20)) >> 21;
|
||||||
|
s1 += carry0;
|
||||||
|
s0 -= carry0 << 21;
|
||||||
|
carry2 = (s2 + (1 << 20)) >> 21;
|
||||||
|
s3 += carry2;
|
||||||
|
s2 -= carry2 << 21;
|
||||||
|
carry4 = (s4 + (1 << 20)) >> 21;
|
||||||
|
s5 += carry4;
|
||||||
|
s4 -= carry4 << 21;
|
||||||
|
carry6 = (s6 + (1 << 20)) >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry8 = (s8 + (1 << 20)) >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry10 = (s10 + (1 << 20)) >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
|
||||||
|
carry1 = (s1 + (1 << 20)) >> 21;
|
||||||
|
s2 += carry1;
|
||||||
|
s1 -= carry1 << 21;
|
||||||
|
carry3 = (s3 + (1 << 20)) >> 21;
|
||||||
|
s4 += carry3;
|
||||||
|
s3 -= carry3 << 21;
|
||||||
|
carry5 = (s5 + (1 << 20)) >> 21;
|
||||||
|
s6 += carry5;
|
||||||
|
s5 -= carry5 << 21;
|
||||||
|
carry7 = (s7 + (1 << 20)) >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry9 = (s9 + (1 << 20)) >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry11 = (s11 + (1 << 20)) >> 21;
|
||||||
|
s12 += carry11;
|
||||||
|
s11 -= carry11 << 21;
|
||||||
|
|
||||||
|
s0 += s12 * 666643;
|
||||||
|
s1 += s12 * 470296;
|
||||||
|
s2 += s12 * 654183;
|
||||||
|
s3 -= s12 * 997805;
|
||||||
|
s4 += s12 * 136657;
|
||||||
|
s5 -= s12 * 683901;
|
||||||
|
s12 = 0;
|
||||||
|
|
||||||
|
carry0 = s0 >> 21;
|
||||||
|
s1 += carry0;
|
||||||
|
s0 -= carry0 << 21;
|
||||||
|
carry1 = s1 >> 21;
|
||||||
|
s2 += carry1;
|
||||||
|
s1 -= carry1 << 21;
|
||||||
|
carry2 = s2 >> 21;
|
||||||
|
s3 += carry2;
|
||||||
|
s2 -= carry2 << 21;
|
||||||
|
carry3 = s3 >> 21;
|
||||||
|
s4 += carry3;
|
||||||
|
s3 -= carry3 << 21;
|
||||||
|
carry4 = s4 >> 21;
|
||||||
|
s5 += carry4;
|
||||||
|
s4 -= carry4 << 21;
|
||||||
|
carry5 = s5 >> 21;
|
||||||
|
s6 += carry5;
|
||||||
|
s5 -= carry5 << 21;
|
||||||
|
carry6 = s6 >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry7 = s7 >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry8 = s8 >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry9 = s9 >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry10 = s10 >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
carry11 = s11 >> 21;
|
||||||
|
s12 += carry11;
|
||||||
|
s11 -= carry11 << 21;
|
||||||
|
|
||||||
|
s0 += s12 * 666643;
|
||||||
|
s1 += s12 * 470296;
|
||||||
|
s2 += s12 * 654183;
|
||||||
|
s3 -= s12 * 997805;
|
||||||
|
s4 += s12 * 136657;
|
||||||
|
s5 -= s12 * 683901;
|
||||||
|
//s12 = 0;
|
||||||
|
|
||||||
|
carry0 = s0 >> 21;
|
||||||
|
s1 += carry0;
|
||||||
|
s0 -= carry0 << 21;
|
||||||
|
carry1 = s1 >> 21;
|
||||||
|
s2 += carry1;
|
||||||
|
s1 -= carry1 << 21;
|
||||||
|
carry2 = s2 >> 21;
|
||||||
|
s3 += carry2;
|
||||||
|
s2 -= carry2 << 21;
|
||||||
|
carry3 = s3 >> 21;
|
||||||
|
s4 += carry3;
|
||||||
|
s3 -= carry3 << 21;
|
||||||
|
carry4 = s4 >> 21;
|
||||||
|
s5 += carry4;
|
||||||
|
s4 -= carry4 << 21;
|
||||||
|
carry5 = s5 >> 21;
|
||||||
|
s6 += carry5;
|
||||||
|
s5 -= carry5 << 21;
|
||||||
|
carry6 = s6 >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry7 = s7 >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry8 = s8 >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry9 = s9 >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry10 = s10 >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
|
||||||
|
s[0] = (s0 >> 0) as u8;
|
||||||
|
s[1] = (s0 >> 8) as u8;
|
||||||
|
s[2] = ((s0 >> 16) | (s1 << 5)) as u8;
|
||||||
|
s[3] = (s1 >> 3) as u8;
|
||||||
|
s[4] = (s1 >> 11) as u8;
|
||||||
|
s[5] = ((s1 >> 19) | (s2 << 2)) as u8;
|
||||||
|
s[6] = (s2 >> 6) as u8;
|
||||||
|
s[7] = ((s2 >> 14) | (s3 << 7)) as u8;
|
||||||
|
s[8] = (s3 >> 1) as u8;
|
||||||
|
s[9] = (s3 >> 9) as u8;
|
||||||
|
s[10] = ((s3 >> 17) | (s4 << 4)) as u8;
|
||||||
|
s[11] = (s4 >> 4) as u8;
|
||||||
|
s[12] = (s4 >> 12) as u8;
|
||||||
|
s[13] = ((s4 >> 20) | (s5 << 1)) as u8;
|
||||||
|
s[14] = (s5 >> 7) as u8;
|
||||||
|
s[15] = ((s5 >> 15) | (s6 << 6)) as u8;
|
||||||
|
s[16] = (s6 >> 2) as u8;
|
||||||
|
s[17] = (s6 >> 10) as u8;
|
||||||
|
s[18] = ((s6 >> 18) | (s7 << 3)) as u8;
|
||||||
|
s[19] = (s7 >> 5) as u8;
|
||||||
|
s[20] = (s7 >> 13) as u8;
|
||||||
|
s[21] = (s8 >> 0) as u8;
|
||||||
|
s[22] = (s8 >> 8) as u8;
|
||||||
|
s[23] = ((s8 >> 16) | (s9 << 5)) as u8;
|
||||||
|
s[24] = (s9 >> 3) as u8;
|
||||||
|
s[25] = (s9 >> 11) as u8;
|
||||||
|
s[26] = ((s9 >> 19) | (s10 << 2)) as u8;
|
||||||
|
s[27] = (s10 >> 6) as u8;
|
||||||
|
s[28] = ((s10 >> 14) | (s11 << 7)) as u8;
|
||||||
|
s[29] = (s11 >> 1) as u8;
|
||||||
|
s[30] = (s11 >> 9) as u8;
|
||||||
|
s[31] = (s11 >> 17) as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn reduce() {
|
||||||
|
let fname = "testdata/ed25519/reduce.test";
|
||||||
|
run_test(fname.to_string(), 2, |case| {
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
|
||||||
|
assert!(!nega && !negb);
|
||||||
|
assert_eq!(abytes.len(), 64);
|
||||||
|
assert_eq!(bbytes.len(), 32);
|
||||||
|
let mut copy = abytes.clone();
|
||||||
|
x25519_sc_reduce(&mut copy);
|
||||||
|
assert_eq!(©[0..32], &bbytes[0..]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input:
|
||||||
|
* a[0]+256*a[1]+...+256^31*a[31] = a
|
||||||
|
* b[0]+256*b[1]+...+256^31*b[31] = b
|
||||||
|
* c[0]+256*c[1]+...+256^31*c[31] = c
|
||||||
|
*
|
||||||
|
* Output:
|
||||||
|
* s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
|
||||||
|
* where l = 2^252 + 27742317777372353535851937790883648493. */
|
||||||
|
pub fn x25519_sc_muladd(s: &mut [u8], a: &[u8], b: &[u8], c: &[u8])
|
||||||
|
{
|
||||||
|
let a0 : i64 = 2097151 & load3(a) as i64;
|
||||||
|
let a1 : i64 = 2097151 & (load4(&a[2..]) >> 5) as i64;
|
||||||
|
let a2 : i64 = 2097151 & (load3(&a[5..]) >> 2) as i64;
|
||||||
|
let a3 : i64 = 2097151 & (load4(&a[7..]) >> 7) as i64;
|
||||||
|
let a4 : i64 = 2097151 & (load4(&a[10..]) >> 4) as i64;
|
||||||
|
let a5 : i64 = 2097151 & (load3(&a[13..]) >> 1) as i64;
|
||||||
|
let a6 : i64 = 2097151 & (load4(&a[15..]) >> 6) as i64;
|
||||||
|
let a7 : i64 = 2097151 & (load3(&a[18..]) >> 3) as i64;
|
||||||
|
let a8 : i64 = 2097151 & load3(&a[21..]) as i64;
|
||||||
|
let a9 : i64 = 2097151 & (load4(&a[23..]) >> 5) as i64;
|
||||||
|
let a10 : i64 = 2097151 & (load3(&a[26..]) >> 2) as i64;
|
||||||
|
let a11 : i64 = (load4(&a[28..]) >> 7) as i64;
|
||||||
|
let b0 : i64 = 2097151 & load3(b) as i64;
|
||||||
|
let b1 : i64 = 2097151 & (load4(&b[2..]) >> 5) as i64;
|
||||||
|
let b2 : i64 = 2097151 & (load3(&b[5..]) >> 2) as i64;
|
||||||
|
let b3 : i64 = 2097151 & (load4(&b[7..]) >> 7) as i64;
|
||||||
|
let b4 : i64 = 2097151 & (load4(&b[10..]) >> 4) as i64;
|
||||||
|
let b5 : i64 = 2097151 & (load3(&b[13..]) >> 1) as i64;
|
||||||
|
let b6 : i64 = 2097151 & (load4(&b[15..]) >> 6) as i64;
|
||||||
|
let b7 : i64 = 2097151 & (load3(&b[18..]) >> 3) as i64;
|
||||||
|
let b8 : i64 = 2097151 & load3(&b[21..]) as i64;
|
||||||
|
let b9 : i64 = 2097151 & (load4(&b[23..]) >> 5) as i64;
|
||||||
|
let b10 : i64 = 2097151 & (load3(&b[26..]) >> 2) as i64;
|
||||||
|
let b11 : i64 = (load4(&b[28..]) >> 7) as i64;
|
||||||
|
let c0 : i64 = 2097151 & load3(c) as i64;
|
||||||
|
let c1 : i64 = 2097151 & (load4(&c[2..]) >> 5) as i64;
|
||||||
|
let c2 : i64 = 2097151 & (load3(&c[5..]) >> 2) as i64;
|
||||||
|
let c3 : i64 = 2097151 & (load4(&c[7..]) >> 7) as i64;
|
||||||
|
let c4 : i64 = 2097151 & (load4(&c[10..]) >> 4) as i64;
|
||||||
|
let c5 : i64 = 2097151 & (load3(&c[13..]) >> 1) as i64;
|
||||||
|
let c6 : i64 = 2097151 & (load4(&c[15..]) >> 6) as i64;
|
||||||
|
let c7 : i64 = 2097151 & (load3(&c[18..]) >> 3) as i64;
|
||||||
|
let c8 : i64 = 2097151 & load3(&c[21..]) as i64;
|
||||||
|
let c9 : i64 = 2097151 & (load4(&c[23..]) >> 5) as i64;
|
||||||
|
let c10 : i64 = 2097151 & (load3(&c[26..]) >> 2) as i64;
|
||||||
|
let c11 : i64 = (load4(&c[28..]) >> 7) as i64;
|
||||||
|
let mut s0 : i64;
|
||||||
|
let mut s1 : i64;
|
||||||
|
let mut s2 : i64;
|
||||||
|
let mut s3 : i64;
|
||||||
|
let mut s4 : i64;
|
||||||
|
let mut s5 : i64;
|
||||||
|
let mut s6 : i64;
|
||||||
|
let mut s7 : i64;
|
||||||
|
let mut s8 : i64;
|
||||||
|
let mut s9 : i64;
|
||||||
|
let mut s10 : i64;
|
||||||
|
let mut s11 : i64;
|
||||||
|
let mut s12 : i64;
|
||||||
|
let mut s13 : i64;
|
||||||
|
let mut s14 : i64;
|
||||||
|
let mut s15 : i64;
|
||||||
|
let mut s16 : i64;
|
||||||
|
let mut s17 : i64;
|
||||||
|
let mut s18 : i64;
|
||||||
|
let mut s19 : i64;
|
||||||
|
let mut s20 : i64;
|
||||||
|
let mut s21 : i64;
|
||||||
|
let mut s22 : i64;
|
||||||
|
let mut s23 : i64;
|
||||||
|
let mut carry0 : i64;
|
||||||
|
let mut carry1 : i64;
|
||||||
|
let mut carry2 : i64;
|
||||||
|
let mut carry3 : i64;
|
||||||
|
let mut carry4 : i64;
|
||||||
|
let mut carry5 : i64;
|
||||||
|
let mut carry6 : i64;
|
||||||
|
let mut carry7 : i64;
|
||||||
|
let mut carry8 : i64;
|
||||||
|
let mut carry9 : i64;
|
||||||
|
let mut carry10 : i64;
|
||||||
|
let mut carry11 : i64;
|
||||||
|
let mut carry12 : i64;
|
||||||
|
let mut carry13 : i64;
|
||||||
|
let mut carry14 : i64;
|
||||||
|
let mut carry15 : i64;
|
||||||
|
let mut carry16 : i64;
|
||||||
|
let carry17 : i64;
|
||||||
|
let carry18 : i64;
|
||||||
|
let carry19 : i64;
|
||||||
|
let carry20 : i64;
|
||||||
|
let carry21 : i64;
|
||||||
|
let carry22 : i64;
|
||||||
|
|
||||||
|
s0 = c0 + a0 * b0;
|
||||||
|
s1 = c1 + a0 * b1 + a1 * b0;
|
||||||
|
s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0;
|
||||||
|
s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
|
||||||
|
s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
|
||||||
|
s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
|
||||||
|
s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
|
||||||
|
s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 +
|
||||||
|
a6 * b1 + a7 * b0;
|
||||||
|
s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 +
|
||||||
|
a6 * b2 + a7 * b1 + a8 * b0;
|
||||||
|
s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 +
|
||||||
|
a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
|
||||||
|
s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 +
|
||||||
|
a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
|
||||||
|
s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 +
|
||||||
|
a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
|
||||||
|
s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 +
|
||||||
|
a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
|
||||||
|
s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 +
|
||||||
|
a9 * b4 + a10 * b3 + a11 * b2;
|
||||||
|
s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 +
|
||||||
|
a10 * b4 + a11 * b3;
|
||||||
|
s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 +
|
||||||
|
a11 * b4;
|
||||||
|
s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
|
||||||
|
s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
|
||||||
|
s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
|
||||||
|
s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
|
||||||
|
s20 = a9 * b11 + a10 * b10 + a11 * b9;
|
||||||
|
s21 = a10 * b11 + a11 * b10;
|
||||||
|
s22 = a11 * b11;
|
||||||
|
s23 = 0;
|
||||||
|
|
||||||
|
carry0 = (s0 + (1 << 20)) >> 21;
|
||||||
|
s1 += carry0;
|
||||||
|
s0 -= carry0 << 21;
|
||||||
|
carry2 = (s2 + (1 << 20)) >> 21;
|
||||||
|
s3 += carry2;
|
||||||
|
s2 -= carry2 << 21;
|
||||||
|
carry4 = (s4 + (1 << 20)) >> 21;
|
||||||
|
s5 += carry4;
|
||||||
|
s4 -= carry4 << 21;
|
||||||
|
carry6 = (s6 + (1 << 20)) >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry8 = (s8 + (1 << 20)) >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry10 = (s10 + (1 << 20)) >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
carry12 = (s12 + (1 << 20)) >> 21;
|
||||||
|
s13 += carry12;
|
||||||
|
s12 -= carry12 << 21;
|
||||||
|
carry14 = (s14 + (1 << 20)) >> 21;
|
||||||
|
s15 += carry14;
|
||||||
|
s14 -= carry14 << 21;
|
||||||
|
carry16 = (s16 + (1 << 20)) >> 21;
|
||||||
|
s17 += carry16;
|
||||||
|
s16 -= carry16 << 21;
|
||||||
|
carry18 = (s18 + (1 << 20)) >> 21;
|
||||||
|
s19 += carry18;
|
||||||
|
s18 -= carry18 << 21;
|
||||||
|
carry20 = (s20 + (1 << 20)) >> 21;
|
||||||
|
s21 += carry20;
|
||||||
|
s20 -= carry20 << 21;
|
||||||
|
carry22 = (s22 + (1 << 20)) >> 21;
|
||||||
|
s23 += carry22;
|
||||||
|
s22 -= carry22 << 21;
|
||||||
|
|
||||||
|
carry1 = (s1 + (1 << 20)) >> 21;
|
||||||
|
s2 += carry1;
|
||||||
|
s1 -= carry1 << 21;
|
||||||
|
carry3 = (s3 + (1 << 20)) >> 21;
|
||||||
|
s4 += carry3;
|
||||||
|
s3 -= carry3 << 21;
|
||||||
|
carry5 = (s5 + (1 << 20)) >> 21;
|
||||||
|
s6 += carry5;
|
||||||
|
s5 -= carry5 << 21;
|
||||||
|
carry7 = (s7 + (1 << 20)) >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry9 = (s9 + (1 << 20)) >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry11 = (s11 + (1 << 20)) >> 21;
|
||||||
|
s12 += carry11;
|
||||||
|
s11 -= carry11 << 21;
|
||||||
|
carry13 = (s13 + (1 << 20)) >> 21;
|
||||||
|
s14 += carry13;
|
||||||
|
s13 -= carry13 << 21;
|
||||||
|
carry15 = (s15 + (1 << 20)) >> 21;
|
||||||
|
s16 += carry15;
|
||||||
|
s15 -= carry15 << 21;
|
||||||
|
carry17 = (s17 + (1 << 20)) >> 21;
|
||||||
|
s18 += carry17;
|
||||||
|
s17 -= carry17 << 21;
|
||||||
|
carry19 = (s19 + (1 << 20)) >> 21;
|
||||||
|
s20 += carry19;
|
||||||
|
s19 -= carry19 << 21;
|
||||||
|
carry21 = (s21 + (1 << 20)) >> 21;
|
||||||
|
s22 += carry21;
|
||||||
|
s21 -= carry21 << 21;
|
||||||
|
|
||||||
|
s11 += s23 * 666643;
|
||||||
|
s12 += s23 * 470296;
|
||||||
|
s13 += s23 * 654183;
|
||||||
|
s14 -= s23 * 997805;
|
||||||
|
s15 += s23 * 136657;
|
||||||
|
s16 -= s23 * 683901;
|
||||||
|
//s23 = 0;
|
||||||
|
|
||||||
|
s10 += s22 * 666643;
|
||||||
|
s11 += s22 * 470296;
|
||||||
|
s12 += s22 * 654183;
|
||||||
|
s13 -= s22 * 997805;
|
||||||
|
s14 += s22 * 136657;
|
||||||
|
s15 -= s22 * 683901;
|
||||||
|
//s22 = 0;
|
||||||
|
|
||||||
|
s9 += s21 * 666643;
|
||||||
|
s10 += s21 * 470296;
|
||||||
|
s11 += s21 * 654183;
|
||||||
|
s12 -= s21 * 997805;
|
||||||
|
s13 += s21 * 136657;
|
||||||
|
s14 -= s21 * 683901;
|
||||||
|
//s21 = 0;
|
||||||
|
|
||||||
|
s8 += s20 * 666643;
|
||||||
|
s9 += s20 * 470296;
|
||||||
|
s10 += s20 * 654183;
|
||||||
|
s11 -= s20 * 997805;
|
||||||
|
s12 += s20 * 136657;
|
||||||
|
s13 -= s20 * 683901;
|
||||||
|
//s20 = 0;
|
||||||
|
|
||||||
|
s7 += s19 * 666643;
|
||||||
|
s8 += s19 * 470296;
|
||||||
|
s9 += s19 * 654183;
|
||||||
|
s10 -= s19 * 997805;
|
||||||
|
s11 += s19 * 136657;
|
||||||
|
s12 -= s19 * 683901;
|
||||||
|
//s19 = 0;
|
||||||
|
|
||||||
|
s6 += s18 * 666643;
|
||||||
|
s7 += s18 * 470296;
|
||||||
|
s8 += s18 * 654183;
|
||||||
|
s9 -= s18 * 997805;
|
||||||
|
s10 += s18 * 136657;
|
||||||
|
s11 -= s18 * 683901;
|
||||||
|
//s18 = 0;
|
||||||
|
|
||||||
|
carry6 = (s6 + (1 << 20)) >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry8 = (s8 + (1 << 20)) >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry10 = (s10 + (1 << 20)) >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
carry12 = (s12 + (1 << 20)) >> 21;
|
||||||
|
s13 += carry12;
|
||||||
|
s12 -= carry12 << 21;
|
||||||
|
carry14 = (s14 + (1 << 20)) >> 21;
|
||||||
|
s15 += carry14;
|
||||||
|
s14 -= carry14 << 21;
|
||||||
|
carry16 = (s16 + (1 << 20)) >> 21;
|
||||||
|
s17 += carry16;
|
||||||
|
s16 -= carry16 << 21;
|
||||||
|
|
||||||
|
carry7 = (s7 + (1 << 20)) >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry9 = (s9 + (1 << 20)) >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry11 = (s11 + (1 << 20)) >> 21;
|
||||||
|
s12 += carry11;
|
||||||
|
s11 -= carry11 << 21;
|
||||||
|
carry13 = (s13 + (1 << 20)) >> 21;
|
||||||
|
s14 += carry13;
|
||||||
|
s13 -= carry13 << 21;
|
||||||
|
carry15 = (s15 + (1 << 20)) >> 21;
|
||||||
|
s16 += carry15;
|
||||||
|
s15 -= carry15 << 21;
|
||||||
|
|
||||||
|
s5 += s17 * 666643;
|
||||||
|
s6 += s17 * 470296;
|
||||||
|
s7 += s17 * 654183;
|
||||||
|
s8 -= s17 * 997805;
|
||||||
|
s9 += s17 * 136657;
|
||||||
|
s10 -= s17 * 683901;
|
||||||
|
//s17 = 0;
|
||||||
|
|
||||||
|
s4 += s16 * 666643;
|
||||||
|
s5 += s16 * 470296;
|
||||||
|
s6 += s16 * 654183;
|
||||||
|
s7 -= s16 * 997805;
|
||||||
|
s8 += s16 * 136657;
|
||||||
|
s9 -= s16 * 683901;
|
||||||
|
//s16 = 0;
|
||||||
|
|
||||||
|
s3 += s15 * 666643;
|
||||||
|
s4 += s15 * 470296;
|
||||||
|
s5 += s15 * 654183;
|
||||||
|
s6 -= s15 * 997805;
|
||||||
|
s7 += s15 * 136657;
|
||||||
|
s8 -= s15 * 683901;
|
||||||
|
//s15 = 0;
|
||||||
|
|
||||||
|
s2 += s14 * 666643;
|
||||||
|
s3 += s14 * 470296;
|
||||||
|
s4 += s14 * 654183;
|
||||||
|
s5 -= s14 * 997805;
|
||||||
|
s6 += s14 * 136657;
|
||||||
|
s7 -= s14 * 683901;
|
||||||
|
//s14 = 0;
|
||||||
|
|
||||||
|
s1 += s13 * 666643;
|
||||||
|
s2 += s13 * 470296;
|
||||||
|
s3 += s13 * 654183;
|
||||||
|
s4 -= s13 * 997805;
|
||||||
|
s5 += s13 * 136657;
|
||||||
|
s6 -= s13 * 683901;
|
||||||
|
//s13 = 0;
|
||||||
|
|
||||||
|
s0 += s12 * 666643;
|
||||||
|
s1 += s12 * 470296;
|
||||||
|
s2 += s12 * 654183;
|
||||||
|
s3 -= s12 * 997805;
|
||||||
|
s4 += s12 * 136657;
|
||||||
|
s5 -= s12 * 683901;
|
||||||
|
s12 = 0;
|
||||||
|
|
||||||
|
carry0 = (s0 + (1 << 20)) >> 21;
|
||||||
|
s1 += carry0;
|
||||||
|
s0 -= carry0 << 21;
|
||||||
|
carry2 = (s2 + (1 << 20)) >> 21;
|
||||||
|
s3 += carry2;
|
||||||
|
s2 -= carry2 << 21;
|
||||||
|
carry4 = (s4 + (1 << 20)) >> 21;
|
||||||
|
s5 += carry4;
|
||||||
|
s4 -= carry4 << 21;
|
||||||
|
carry6 = (s6 + (1 << 20)) >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry8 = (s8 + (1 << 20)) >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry10 = (s10 + (1 << 20)) >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
|
||||||
|
carry1 = (s1 + (1 << 20)) >> 21;
|
||||||
|
s2 += carry1;
|
||||||
|
s1 -= carry1 << 21;
|
||||||
|
carry3 = (s3 + (1 << 20)) >> 21;
|
||||||
|
s4 += carry3;
|
||||||
|
s3 -= carry3 << 21;
|
||||||
|
carry5 = (s5 + (1 << 20)) >> 21;
|
||||||
|
s6 += carry5;
|
||||||
|
s5 -= carry5 << 21;
|
||||||
|
carry7 = (s7 + (1 << 20)) >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry9 = (s9 + (1 << 20)) >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry11 = (s11 + (1 << 20)) >> 21;
|
||||||
|
s12 += carry11;
|
||||||
|
s11 -= carry11 << 21;
|
||||||
|
|
||||||
|
s0 += s12 * 666643;
|
||||||
|
s1 += s12 * 470296;
|
||||||
|
s2 += s12 * 654183;
|
||||||
|
s3 -= s12 * 997805;
|
||||||
|
s4 += s12 * 136657;
|
||||||
|
s5 -= s12 * 683901;
|
||||||
|
s12 = 0;
|
||||||
|
|
||||||
|
carry0 = s0 >> 21;
|
||||||
|
s1 += carry0;
|
||||||
|
s0 -= carry0 << 21;
|
||||||
|
carry1 = s1 >> 21;
|
||||||
|
s2 += carry1;
|
||||||
|
s1 -= carry1 << 21;
|
||||||
|
carry2 = s2 >> 21;
|
||||||
|
s3 += carry2;
|
||||||
|
s2 -= carry2 << 21;
|
||||||
|
carry3 = s3 >> 21;
|
||||||
|
s4 += carry3;
|
||||||
|
s3 -= carry3 << 21;
|
||||||
|
carry4 = s4 >> 21;
|
||||||
|
s5 += carry4;
|
||||||
|
s4 -= carry4 << 21;
|
||||||
|
carry5 = s5 >> 21;
|
||||||
|
s6 += carry5;
|
||||||
|
s5 -= carry5 << 21;
|
||||||
|
carry6 = s6 >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry7 = s7 >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry8 = s8 >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry9 = s9 >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry10 = s10 >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
carry11 = s11 >> 21;
|
||||||
|
s12 += carry11;
|
||||||
|
s11 -= carry11 << 21;
|
||||||
|
|
||||||
|
s0 += s12 * 666643;
|
||||||
|
s1 += s12 * 470296;
|
||||||
|
s2 += s12 * 654183;
|
||||||
|
s3 -= s12 * 997805;
|
||||||
|
s4 += s12 * 136657;
|
||||||
|
s5 -= s12 * 683901;
|
||||||
|
//s12 = 0;
|
||||||
|
|
||||||
|
carry0 = s0 >> 21;
|
||||||
|
s1 += carry0;
|
||||||
|
s0 -= carry0 << 21;
|
||||||
|
carry1 = s1 >> 21;
|
||||||
|
s2 += carry1;
|
||||||
|
s1 -= carry1 << 21;
|
||||||
|
carry2 = s2 >> 21;
|
||||||
|
s3 += carry2;
|
||||||
|
s2 -= carry2 << 21;
|
||||||
|
carry3 = s3 >> 21;
|
||||||
|
s4 += carry3;
|
||||||
|
s3 -= carry3 << 21;
|
||||||
|
carry4 = s4 >> 21;
|
||||||
|
s5 += carry4;
|
||||||
|
s4 -= carry4 << 21;
|
||||||
|
carry5 = s5 >> 21;
|
||||||
|
s6 += carry5;
|
||||||
|
s5 -= carry5 << 21;
|
||||||
|
carry6 = s6 >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry7 = s7 >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry8 = s8 >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry9 = s9 >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry10 = s10 >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
|
||||||
|
s[0] = (s0 >> 0) as u8;
|
||||||
|
s[1] = (s0 >> 8) as u8;
|
||||||
|
s[2] = ((s0 >> 16) | (s1 << 5)) as u8;
|
||||||
|
s[3] = (s1 >> 3) as u8;
|
||||||
|
s[4] = (s1 >> 11) as u8;
|
||||||
|
s[5] = ((s1 >> 19) | (s2 << 2)) as u8;
|
||||||
|
s[6] = (s2 >> 6) as u8;
|
||||||
|
s[7] = ((s2 >> 14) | (s3 << 7)) as u8;
|
||||||
|
s[8] = (s3 >> 1) as u8;
|
||||||
|
s[9] = (s3 >> 9) as u8;
|
||||||
|
s[10] = ((s3 >> 17) | (s4 << 4)) as u8;
|
||||||
|
s[11] = (s4 >> 4) as u8;
|
||||||
|
s[12] = (s4 >> 12) as u8;
|
||||||
|
s[13] = ((s4 >> 20) | (s5 << 1)) as u8;
|
||||||
|
s[14] = (s5 >> 7) as u8;
|
||||||
|
s[15] = ((s5 >> 15) | (s6 << 6)) as u8;
|
||||||
|
s[16] = (s6 >> 2) as u8;
|
||||||
|
s[17] = (s6 >> 10) as u8;
|
||||||
|
s[18] = ((s6 >> 18) | (s7 << 3)) as u8;
|
||||||
|
s[19] = (s7 >> 5) as u8;
|
||||||
|
s[20] = (s7 >> 13) as u8;
|
||||||
|
s[21] = (s8 >> 0) as u8;
|
||||||
|
s[22] = (s8 >> 8) as u8;
|
||||||
|
s[23] = ((s8 >> 16) | (s9 << 5)) as u8;
|
||||||
|
s[24] = (s9 >> 3) as u8;
|
||||||
|
s[25] = (s9 >> 11) as u8;
|
||||||
|
s[26] = ((s9 >> 19) | (s10 << 2)) as u8;
|
||||||
|
s[27] = (s10 >> 6) as u8;
|
||||||
|
s[28] = ((s10 >> 14) | (s11 << 7)) as u8;
|
||||||
|
s[29] = (s11 >> 1) as u8;
|
||||||
|
s[30] = (s11 >> 9) as u8;
|
||||||
|
s[31] = (s11 >> 17) as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn muladd() {
|
||||||
|
let fname = "testdata/ed25519/muladd.test";
|
||||||
|
run_test(fname.to_string(), 4, |case| {
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
let (negc, cbytes) = case.get("c").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
|
||||||
|
assert!(!nega && !negb && !negc && !negd);
|
||||||
|
let mut mine = [0; 32];
|
||||||
|
x25519_sc_muladd(&mut mine, abytes, bbytes, cbytes);
|
||||||
|
for i in 0..32 {
|
||||||
|
assert_eq!(&mine[i], &dbytes[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn curve25519_scalar_mask(a: &mut [u8])
|
||||||
|
{
|
||||||
|
assert_eq!(a.len(), 32);
|
||||||
|
a[0] &= 248;
|
||||||
|
a[31] &= 127;
|
||||||
|
a[31] |= 64;
|
||||||
|
}
|
||||||
|
|
||||||
196
src/hmac.rs
Normal file
196
src/hmac.rs
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
//! This module implements the Keyed-Hash Message Authentication Code, or HMAC,
|
||||||
|
//! as defined by NIST 198-1. Now, you might have questions, like:
|
||||||
|
//! * *Where did the 'K' go in the acronym?* I don't know. Maybe we should
|
||||||
|
//! always be saying Keyed-HMAC? It's a mystery.
|
||||||
|
//! * *What is this good for?* I do know the answer to that! HMACs are
|
||||||
|
//! useful when you want to extend the ability of a hash to tell you if
|
||||||
|
//! a message has been modified with the ability to determine if the
|
||||||
|
//! person that sent it had hold of a key. It's thus a version of the
|
||||||
|
//! message signing capability used in asymmetric crypto (`DSA`, `RSA`,
|
||||||
|
//! `ECDSA`, and `ED25519`, as implemented in this crate), but with a
|
||||||
|
//! symmetric key, instead.
|
||||||
|
//!
|
||||||
|
//! Because HMAC can be used with a variety of hash functions, this module
|
||||||
|
//! implements it as a generic structure that takes the associated hash as
|
||||||
|
//! a type argument. This should provide a reasonable level of flexibility,
|
||||||
|
//! while allowing the type system from preventing us from making any number
|
||||||
|
//! of really annoying mistakes. You can specify which of the hash functions
|
||||||
|
//! you want to use by using your standard turbofish:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use simple_crypto::hmac::HMAC;
|
||||||
|
//! use simple_crypto::sha::SHA256;
|
||||||
|
//!
|
||||||
|
//! let key = [0,1,2,3,4]; // very secure
|
||||||
|
//! let msg = [5,6,7,8];
|
||||||
|
//! let hmac = HMAC::<SHA256>::hmac(&key, &msg);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Much like with `SHAKE128` and `SHAKE256` the interface for HMAC is
|
||||||
|
//! similar to, but not quite, the interface for `Hash`. We thus try to
|
||||||
|
//! copy as much of the standard `Hash` interface as we can, but extend
|
||||||
|
//! `new` with a key, rename `hash` to `hmac`, and extend `hmac` with a
|
||||||
|
//! key as well. This provides a similar ability to use HMACs both in an
|
||||||
|
//! incremental mode as well as just do it all at once, as follows:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use simple_crypto::hmac::HMAC;
|
||||||
|
//! use simple_crypto::sha::SHA256;
|
||||||
|
//!
|
||||||
|
//! let key = [0,1,2,3,4]; // like my suitcase
|
||||||
|
//! let msg = [5,6,7,8];
|
||||||
|
//!
|
||||||
|
//! // Compute the HMAC incrementally
|
||||||
|
//! let mut hmacinc = HMAC::<SHA256>::new(&key);
|
||||||
|
//! hmacinc.update(&[5,6]);
|
||||||
|
//! hmacinc.update(&[7,8]);
|
||||||
|
//! let hmac_incremental = hmacinc.finalize();
|
||||||
|
//!
|
||||||
|
//! // Compute the HMAC all at once
|
||||||
|
//! let hmac_once = HMAC::<SHA256>::hmac(&key, &msg);
|
||||||
|
//!
|
||||||
|
//! // ... which should be the same thing
|
||||||
|
//! assert_eq!(hmac_incremental, hmac_once);
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
/// The HMAC structure, parameterized by its hash function.
|
||||||
|
///
|
||||||
|
/// Much like with `SHAKE128` and `SHAKE256` the interface for HMAC is
|
||||||
|
/// similar to, but not quite, the interface for `Hash`. We thus try to
|
||||||
|
/// copy as much of the standard `Hash` interface as we can, but extend
|
||||||
|
/// `new` with a key, rename `hash` to `hmac`, and extend `hmac` with a
|
||||||
|
/// key as well. This provides a similar ability to use HMACs both in an
|
||||||
|
/// incremental mode as well as just do it all at once, as follows:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use simple_crypto::hmac::HMAC;
|
||||||
|
/// use simple_crypto::sha::SHA256;
|
||||||
|
///
|
||||||
|
/// let key = [0,1,2,3,4]; // like my suitcase
|
||||||
|
/// let msg = [5,6,7,8];
|
||||||
|
///
|
||||||
|
/// // Compute the HMAC incrementally
|
||||||
|
/// let mut hmacinc = HMAC::<SHA256>::new(&key);
|
||||||
|
/// hmacinc.update(&[5,6]);
|
||||||
|
/// hmacinc.update(&[7,8]);
|
||||||
|
/// let hmac_incremental = hmacinc.finalize();
|
||||||
|
///
|
||||||
|
/// // Compute the HMAC all at once
|
||||||
|
/// let hmac_once = HMAC::<SHA256>::hmac(&key, &msg);
|
||||||
|
///
|
||||||
|
/// // ... which should be the same thing
|
||||||
|
/// assert_eq!(hmac_incremental, hmac_once);
|
||||||
|
/// ```
|
||||||
|
use super::Hash;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct HMAC<H: Hash + Clone> {
|
||||||
|
ipad_hash: H,
|
||||||
|
opad_hash: H,
|
||||||
|
result: Option<Vec<u8>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H: Hash + Clone> HMAC<H> {
|
||||||
|
/// Generate a new HMAC construction for the provide underlying hash
|
||||||
|
/// function, and prep it to start taking input via the `update`
|
||||||
|
/// method.
|
||||||
|
pub fn new(inkey: &[u8]) -> Self {
|
||||||
|
let hash_blocklen_bytes = H::block_size() / 8;
|
||||||
|
|
||||||
|
// If the input key is longer than the hash block length, then we
|
||||||
|
// immediately hash it down to be the block length. Otherwise, we
|
||||||
|
// leave it be.
|
||||||
|
let mut key = if inkey.len() > hash_blocklen_bytes { H::hash(inkey) }
|
||||||
|
else { inkey.to_vec() };
|
||||||
|
// It may now be too small, or have started too small, in which case
|
||||||
|
// we pad it out with zeros.
|
||||||
|
key.resize(hash_blocklen_bytes, 0);
|
||||||
|
// Generate the inner and outer key pad from this key.
|
||||||
|
let o_key_pad: Vec<u8> = key.iter().map(|x| *x ^ 0x5c).collect();
|
||||||
|
let i_key_pad: Vec<u8> = key.iter().map(|x| *x ^ 0x36).collect();
|
||||||
|
// Now we can start the hashes; obviously we'll have to wait
|
||||||
|
// until we get the rest of the message to complete them.
|
||||||
|
let mut ipad_hash = H::new();
|
||||||
|
ipad_hash.update(&i_key_pad);
|
||||||
|
let mut opad_hash = H::new();
|
||||||
|
opad_hash.update(&o_key_pad);
|
||||||
|
let result = None;
|
||||||
|
HMAC { ipad_hash, opad_hash, result }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add more data as part of the HMAC computation. This can be called
|
||||||
|
/// zero or more times over the lifetime of the HMAC structure. That
|
||||||
|
/// being said, once you call `finalize`, this structure is done, and
|
||||||
|
/// it will ignore further calls to `update`.
|
||||||
|
pub fn update(&mut self, buffer: &[u8])
|
||||||
|
{
|
||||||
|
if self.result.is_none() {
|
||||||
|
self.ipad_hash.update(&buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provide the final HMAC value for the bitrstream as read. This shifts
|
||||||
|
/// this structure into a final mode, in which it will ignore any more
|
||||||
|
/// data provided to it from `update`. You can, however, call `finalize`
|
||||||
|
/// more than once; the HMAC structure caches the return value and will
|
||||||
|
/// return it as many times as you like.
|
||||||
|
pub fn finalize(&mut self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
if let Some(ref res) = self.result {
|
||||||
|
res.clone()
|
||||||
|
} else {
|
||||||
|
self.opad_hash.update(&self.ipad_hash.finalize());
|
||||||
|
let res = self.opad_hash.finalize();
|
||||||
|
self.result = Some(res.clone());
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A useful method for those situations in which you have only one block
|
||||||
|
/// of data to generate an HMAC for. Runs `new`, `update`, and `finalize`
|
||||||
|
/// for you, in order.
|
||||||
|
pub fn hmac(key: &[u8], val: &[u8]) -> Vec<u8>
|
||||||
|
{
|
||||||
|
let mut h = Self::new(key);
|
||||||
|
h.update(val);
|
||||||
|
h.finalize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use sha::{SHA1,SHA224,SHA256,SHA384,SHA512};
|
||||||
|
#[cfg(test)]
|
||||||
|
use testing::run_test;
|
||||||
|
#[cfg(test)]
|
||||||
|
use cryptonum::unsigned::{Decoder,U192};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn nist_vectors() {
|
||||||
|
let fname = "testdata/sha/hmac.test";
|
||||||
|
run_test(fname.to_string(), 6, |case| {
|
||||||
|
let (negh, hbytes) = case.get("h").unwrap();
|
||||||
|
let (negr, rbytes) = case.get("r").unwrap();
|
||||||
|
let (negm, mbytes) = case.get("m").unwrap();
|
||||||
|
let (negk, kbytes) = case.get("k").unwrap();
|
||||||
|
let (negl, lbytes) = case.get("l").unwrap();
|
||||||
|
let (negt, tbytes) = case.get("t").unwrap();
|
||||||
|
|
||||||
|
assert!(!negh && !negr && !negm && !negk && !negl && !negt);
|
||||||
|
let l = usize::from(U192::from_bytes(lbytes));
|
||||||
|
let h = usize::from(U192::from_bytes(hbytes));
|
||||||
|
assert_eq!(l, kbytes.len());
|
||||||
|
let mut res = match h {
|
||||||
|
160 => HMAC::<SHA1>::hmac(&kbytes, &mbytes),
|
||||||
|
224 => HMAC::<SHA224>::hmac(&kbytes, &mbytes),
|
||||||
|
256 => HMAC::<SHA256>::hmac(&kbytes, &mbytes),
|
||||||
|
384 => HMAC::<SHA384>::hmac(&kbytes, &mbytes),
|
||||||
|
512 => HMAC::<SHA512>::hmac(&kbytes, &mbytes),
|
||||||
|
_ => panic!("Weird hash size in HMAC test file")
|
||||||
|
};
|
||||||
|
let t = usize::from(U192::from_bytes(tbytes));
|
||||||
|
res.resize(t, 0);
|
||||||
|
assert_eq!(rbytes, &res);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
64
src/lib.rs
64
src/lib.rs
@@ -9,18 +9,15 @@
|
|||||||
//! that a new user should use, along with documentation regarding how and
|
//! 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
|
//! when they should use it, and examples. For now, it mostly just fowards
|
||||||
//! off to more detailed modules. Help requested!
|
//! off to more detailed modules. Help requested!
|
||||||
|
extern crate base64;
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate chrono;
|
extern crate chrono;
|
||||||
extern crate cryptonum;
|
extern crate cryptonum;
|
||||||
extern crate digest;
|
|
||||||
extern crate hmac;
|
|
||||||
extern crate num;
|
extern crate num;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate quickcheck;
|
extern crate quickcheck;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate sha1;
|
|
||||||
extern crate sha2;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate simple_asn1;
|
extern crate simple_asn1;
|
||||||
|
|
||||||
@@ -35,9 +32,68 @@ pub mod dsa;
|
|||||||
/// The `ecdsa` module provides bare-bones support for ECDSA signing,
|
/// The `ecdsa` module provides bare-bones support for ECDSA signing,
|
||||||
/// verification, and key generation.
|
/// verification, and key generation.
|
||||||
pub mod ecdsa;
|
pub mod ecdsa;
|
||||||
|
/// The `ed25519` provides signing and verification using ED25519.
|
||||||
|
pub mod ed25519;
|
||||||
|
/// The `ssh` module provides support for parsing OpenSSH-formatted SSH keys,
|
||||||
|
/// both public and private.
|
||||||
|
pub mod ssh;
|
||||||
|
/// The `shake` module provides support for SHAKE128 and SHAKE256, two
|
||||||
|
/// variable-length hash functions that derive from the same core hash
|
||||||
|
/// as SHA3.
|
||||||
|
pub mod shake;
|
||||||
|
/// The `hmac` module provides support for keyed-hash message authentication,
|
||||||
|
/// or HMAC, based on any of the hash functions defined in this module.
|
||||||
|
pub mod hmac;
|
||||||
/// The `x509` module supports parsing and generating x.509 certificates, as
|
/// The `x509` module supports parsing and generating x.509 certificates, as
|
||||||
/// used by TLS and others.
|
/// used by TLS and others.
|
||||||
pub mod x509;
|
pub mod x509;
|
||||||
|
/// An implementation of the SHA family of hashes, including the relatively
|
||||||
|
/// weak SHA1 and a bunch of hashes you should use, like the SHA2 and SHA3
|
||||||
|
/// hashes.
|
||||||
|
pub mod sha;
|
||||||
|
|
||||||
|
/// A generic trait for defining what a key pair looks like. This is useful
|
||||||
|
/// in a couple places in which we want to define code regardless of the
|
||||||
|
/// kind of key it is, but is unlikely to be hugely useful to users of the
|
||||||
|
/// library.
|
||||||
|
pub trait KeyPair {
|
||||||
|
/// The type of the public key of this pair.
|
||||||
|
type Public;
|
||||||
|
/// The type of the private key of this pair.
|
||||||
|
type Private;
|
||||||
|
|
||||||
|
/// Generate a key pair given the provided public and private keys.
|
||||||
|
fn new(pbl: Self::Public, prv: Self::Private) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A generic trait for defining a hash function.
|
||||||
|
pub trait Hash: Sized
|
||||||
|
{
|
||||||
|
/// Generate a fresh instance of this hash function, set to the
|
||||||
|
/// appropriate initial state.
|
||||||
|
fn new() -> Self;
|
||||||
|
/// Update the hash function with some more data for it to chew on.
|
||||||
|
/// Nom nom nom. If you give it more information after calling
|
||||||
|
/// `finalize`, the implementation is welcome to do anything it
|
||||||
|
/// wants; mostly they will just ignore additional data, but
|
||||||
|
/// maybe just don't do that.
|
||||||
|
fn update(&mut self, data: &[u8]);
|
||||||
|
/// Finalize the hash function, returning the hash value.
|
||||||
|
fn finalize(&mut self) -> Vec<u8>;
|
||||||
|
/// Return the block size of the underlying hash function, in
|
||||||
|
/// bits. This is mostly useful internally to this crate.
|
||||||
|
fn block_size() -> usize;
|
||||||
|
|
||||||
|
/// This is a convenience routine that runs new(), update(), and
|
||||||
|
/// finalize() on a piece of data all at once. Because that's
|
||||||
|
/// mostly what people want to do.
|
||||||
|
fn hash(data: &[u8]) -> Vec<u8>
|
||||||
|
{
|
||||||
|
let mut x = Self::new();
|
||||||
|
x.update(&data);
|
||||||
|
x.finalize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod testing;
|
mod testing;
|
||||||
|
|||||||
@@ -1,7 +1,23 @@
|
|||||||
|
use cryptonum::unsigned::*;
|
||||||
use num::bigint::BigUint;
|
use num::bigint::BigUint;
|
||||||
use rsa::errors::RSAError;
|
use rsa::errors::RSAError;
|
||||||
use simple_asn1::{ASN1Block,ASN1DecodeErr};
|
use simple_asn1::{ASN1Block,ASN1DecodeErr};
|
||||||
|
|
||||||
|
/// A valid key size for RSA keys, basically, and a (slightly annoying)
|
||||||
|
/// trait that is used to tie these types to their Barrett value types.
|
||||||
|
pub trait RSAMode {
|
||||||
|
type Barrett;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RSAMode for U512 { type Barrett = BarrettU512; }
|
||||||
|
impl RSAMode for U1024 { type Barrett = BarrettU1024; }
|
||||||
|
impl RSAMode for U2048 { type Barrett = BarrettU2048; }
|
||||||
|
impl RSAMode for U3072 { type Barrett = BarrettU3072; }
|
||||||
|
impl RSAMode for U4096 { type Barrett = BarrettU4096; }
|
||||||
|
impl RSAMode for U8192 { type Barrett = BarrettU8192; }
|
||||||
|
impl RSAMode for U15360 { type Barrett = BarrettU15360; }
|
||||||
|
|
||||||
|
|
||||||
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();
|
let mut idhash = Vec::new();
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use simple_asn1::ASN1DecodeErr;
|
use simple_asn1::ASN1DecodeErr;
|
||||||
use rand;
|
use rand;
|
||||||
|
|
||||||
|
/// A bunch of errors that you can get generating, reading, or
|
||||||
|
/// writing RSA keys.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum RSAError {
|
pub enum RSAError {
|
||||||
BadMessageSize,
|
BadMessageSize,
|
||||||
|
|||||||
235
src/rsa/mod.rs
235
src/rsa/mod.rs
@@ -17,6 +17,38 @@
|
|||||||
//! Encryption and decryption are via the OAEP mechanism, as described in
|
//! Encryption and decryption are via the OAEP mechanism, as described in
|
||||||
//! NIST documents.
|
//! NIST documents.
|
||||||
//!
|
//!
|
||||||
|
//! The following is an example of generating an RSA2048 key pair, then using
|
||||||
|
//! it to sign, verify, encrypt, and decrypt some data.
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! extern crate cryptonum;
|
||||||
|
//!
|
||||||
|
//! use simple_crypto::rsa::RSAKeyPair;
|
||||||
|
//! use simple_crypto::rsa::SIGNING_HASH_SHA256;
|
||||||
|
//! use simple_crypto::rsa::OAEPParams;
|
||||||
|
//! use simple_crypto::sha::SHA256;
|
||||||
|
//! use cryptonum::unsigned::U2048;
|
||||||
|
//!
|
||||||
|
//! // Generate a new RSA with key size 2048. (This is an acceptable but
|
||||||
|
//! // not great key size, but is a nice compromise given that this little
|
||||||
|
//! // example runs as part of the test suite.)
|
||||||
|
//! let mut rng = rand::rngs::OsRng::new().unwrap();
|
||||||
|
//! let kp = RSAKeyPair::<U2048>::generate(&mut rng);
|
||||||
|
//!
|
||||||
|
//! // Now that you have this key pair, you can sign and verify messages
|
||||||
|
//! // using it. For example, to sign the vector [0,1,2,3,4] with SHA256
|
||||||
|
//! // and then verify that signature, we would write:
|
||||||
|
//! let msg = vec![0,1,2,3,4];
|
||||||
|
//! let sig = kp.private.sign(&SIGNING_HASH_SHA256, &msg);
|
||||||
|
//! assert!( kp.public.verify(&SIGNING_HASH_SHA256, &msg, &sig) );
|
||||||
|
//!
|
||||||
|
//! // We can also use RSA public keys to encrypt data, which can then be
|
||||||
|
//! // decrypted by the private key.
|
||||||
|
//! let params = OAEPParams::<SHA256>::new(String::from("example!"));
|
||||||
|
//! let cipher = kp.public.encrypt(¶ms, &msg).expect("Encryption error");
|
||||||
|
//! let msg2 = kp.private.decrypt(¶ms, &cipher).expect("Decryption error");
|
||||||
|
//! assert_eq!(msg, msg2);
|
||||||
|
//! ```
|
||||||
mod core;
|
mod core;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod oaep;
|
mod oaep;
|
||||||
@@ -24,6 +56,7 @@ mod private;
|
|||||||
mod public;
|
mod public;
|
||||||
mod signing_hashes;
|
mod signing_hashes;
|
||||||
|
|
||||||
|
pub use self::core::RSAMode;
|
||||||
pub use self::errors::RSAError;
|
pub use self::errors::RSAError;
|
||||||
pub use self::signing_hashes::{SigningHash,
|
pub use self::signing_hashes::{SigningHash,
|
||||||
SIGNING_HASH_NULL,
|
SIGNING_HASH_NULL,
|
||||||
@@ -33,20 +66,16 @@ pub use self::signing_hashes::{SigningHash,
|
|||||||
SIGNING_HASH_SHA384,
|
SIGNING_HASH_SHA384,
|
||||||
SIGNING_HASH_SHA512};
|
SIGNING_HASH_SHA512};
|
||||||
pub use self::oaep::OAEPParams;
|
pub use self::oaep::OAEPParams;
|
||||||
pub use self::private::{RSAPrivate, RSAPrivateKey,
|
pub use self::private::{RSAPrivate, RSAPrivateKey};
|
||||||
RSA512Private, RSA1024Private, RSA2048Private,
|
pub use self::public::{RSAPublic, RSAPublicKey};
|
||||||
RSA3072Private, RSA4096Private, RSA8192Private,
|
|
||||||
RSA15360Private};
|
|
||||||
pub use self::public::{RSAPublic, RSAPublicKey,
|
|
||||||
RSA512Public, RSA1024Public, RSA2048Public,
|
|
||||||
RSA3072Public, RSA4096Public, RSA8192Public,
|
|
||||||
RSA15360Public};
|
|
||||||
|
|
||||||
use cryptonum::signed::{EGCD,ModInv};
|
use cryptonum::signed::{EGCD,ModInv};
|
||||||
use cryptonum::unsigned::{CryptoNum,PrimeGen};
|
use cryptonum::unsigned::{CryptoNum,PrimeGen};
|
||||||
use cryptonum::unsigned::{U256,U512,U1024,U1536,U2048,U3072,U4096,U7680,U8192,U15360};
|
use cryptonum::unsigned::{U256,U512,U1024,U1536,U2048,U3072,U4096,U7680,U8192,U15360};
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
|
#[cfg(test)]
|
||||||
|
use std::fmt;
|
||||||
use std::ops::Sub;
|
use std::ops::Sub;
|
||||||
|
use super::KeyPair;
|
||||||
|
|
||||||
fn diff<T>(a: &T, b: &T) -> T
|
fn diff<T>(a: &T, b: &T) -> T
|
||||||
where
|
where
|
||||||
@@ -60,38 +89,164 @@ fn diff<T>(a: &T, b: &T) -> T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! generate_rsa_pair
|
/// An RSA key pair containing keys of the given size; keeping them in the
|
||||||
{
|
/// type means you'll never forget which one you have.
|
||||||
($pair: ident, $pub: ident, $priv: ident, $uint: ident, $half: ident, $iterations: expr) => {
|
///
|
||||||
pub struct $pair {
|
/// As an aside:
|
||||||
pub public: $pub,
|
/// * `U512` should only be used for testing
|
||||||
pub private: $priv
|
/// * `U1024` should only be used to support old protocols or devices
|
||||||
|
/// * `U2048` is probably your bare minimum
|
||||||
|
/// * `U3072` is a very reasonable choice
|
||||||
|
/// * **`U4096` is what you should use**
|
||||||
|
/// * `U8192` is starting to get a bit silly (and slow)
|
||||||
|
/// * `U15360` is for when you're using encryption to heat your house or server room
|
||||||
|
pub struct RSAKeyPair<R: RSAMode> {
|
||||||
|
pub public: RSAPublicKey<R>,
|
||||||
|
pub private: RSAPrivateKey<R>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $pair {
|
/// A generic RSA key pair that is agnostic about its key size. It's not
|
||||||
pub fn new(pu: $pub, pr: $priv) -> $pair {
|
/// totally clear why this is useful, at this point.
|
||||||
$pair {
|
#[derive(PartialEq)]
|
||||||
|
pub enum RSAPair {
|
||||||
|
R512(RSAPublicKey<U512>, RSAPrivateKey<U512>),
|
||||||
|
R1024(RSAPublicKey<U1024>, RSAPrivateKey<U1024>),
|
||||||
|
R2048(RSAPublicKey<U2048>, RSAPrivateKey<U2048>),
|
||||||
|
R3072(RSAPublicKey<U3072>, RSAPrivateKey<U3072>),
|
||||||
|
R4096(RSAPublicKey<U4096>, RSAPrivateKey<U4096>),
|
||||||
|
R8192(RSAPublicKey<U8192>, RSAPrivateKey<U8192>),
|
||||||
|
R15360(RSAPublicKey<U15360>, RSAPrivateKey<U15360>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl fmt::Debug for RSAPair {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
RSAPair::R512(_,_) => f.write_str("512-bit RSA key pair"),
|
||||||
|
RSAPair::R1024(_,_) => f.write_str("1024-bit RSA key pair"),
|
||||||
|
RSAPair::R2048(_,_) => f.write_str("2048-bit RSA key pair"),
|
||||||
|
RSAPair::R3072(_,_) => f.write_str("3072-bit RSA key pair"),
|
||||||
|
RSAPair::R4096(_,_) => f.write_str("4096-bit RSA key pair"),
|
||||||
|
RSAPair::R8192(_,_) => f.write_str("8192-bit RSA key pair"),
|
||||||
|
RSAPair::R15360(_,_) => f.write_str("15360-bit RSA key pair"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyPair for RSAPair {
|
||||||
|
type Public = RSAPublic;
|
||||||
|
type Private = RSAPrivate;
|
||||||
|
|
||||||
|
fn new(pu: RSAPublic, pr: RSAPrivate) -> RSAPair
|
||||||
|
{
|
||||||
|
match (pu, pr) {
|
||||||
|
(RSAPublic::Key512(pbl), RSAPrivate::Key512(prv)) =>
|
||||||
|
RSAPair::R512(pbl, prv),
|
||||||
|
(RSAPublic::Key1024(pbl), RSAPrivate::Key1024(prv)) =>
|
||||||
|
RSAPair::R1024(pbl, prv),
|
||||||
|
(RSAPublic::Key2048(pbl), RSAPrivate::Key2048(prv)) =>
|
||||||
|
RSAPair::R2048(pbl, prv),
|
||||||
|
(RSAPublic::Key3072(pbl), RSAPrivate::Key3072(prv)) =>
|
||||||
|
RSAPair::R3072(pbl, prv),
|
||||||
|
(RSAPublic::Key4096(pbl), RSAPrivate::Key4096(prv)) =>
|
||||||
|
RSAPair::R4096(pbl, prv),
|
||||||
|
(RSAPublic::Key8192(pbl), RSAPrivate::Key8192(prv)) =>
|
||||||
|
RSAPair::R8192(pbl, prv),
|
||||||
|
(RSAPublic::Key15360(pbl), RSAPrivate::Key15360(prv)) =>
|
||||||
|
RSAPair::R15360(pbl, prv),
|
||||||
|
_ =>
|
||||||
|
panic!("Unmatched public/private arguments to RSAPair::new()")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RSAPair {
|
||||||
|
pub fn sign(&self, signhash: &SigningHash, msg: &[u8]) -> Vec<u8>
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
RSAPair::R512(_,prv) => prv.sign(signhash, msg),
|
||||||
|
RSAPair::R1024(_,prv) => prv.sign(signhash, msg),
|
||||||
|
RSAPair::R2048(_,prv) => prv.sign(signhash, msg),
|
||||||
|
RSAPair::R3072(_,prv) => prv.sign(signhash, msg),
|
||||||
|
RSAPair::R4096(_,prv) => prv.sign(signhash, msg),
|
||||||
|
RSAPair::R8192(_,prv) => prv.sign(signhash, msg),
|
||||||
|
RSAPair::R15360(_,prv) => prv.sign(signhash, msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
RSAPair::R512(pbl,_) => pbl.verify(signhash, msg, sig),
|
||||||
|
RSAPair::R1024(pbl,_) => pbl.verify(signhash, msg, sig),
|
||||||
|
RSAPair::R2048(pbl,_) => pbl.verify(signhash, msg, sig),
|
||||||
|
RSAPair::R3072(pbl,_) => pbl.verify(signhash, msg, sig),
|
||||||
|
RSAPair::R4096(pbl,_) => pbl.verify(signhash, msg, sig),
|
||||||
|
RSAPair::R8192(pbl,_) => pbl.verify(signhash, msg, sig),
|
||||||
|
RSAPair::R15360(pbl,_) => pbl.verify(signhash, msg, sig),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn public(&self) -> RSAPublic
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
&RSAPair::R512(ref pbl,_) => RSAPublic::Key512(pbl.clone()),
|
||||||
|
&RSAPair::R1024(ref pbl,_) => RSAPublic::Key1024(pbl.clone()),
|
||||||
|
&RSAPair::R2048(ref pbl,_) => RSAPublic::Key2048(pbl.clone()),
|
||||||
|
&RSAPair::R3072(ref pbl,_) => RSAPublic::Key3072(pbl.clone()),
|
||||||
|
&RSAPair::R4096(ref pbl,_) => RSAPublic::Key4096(pbl.clone()),
|
||||||
|
&RSAPair::R8192(ref pbl,_) => RSAPublic::Key8192(pbl.clone()),
|
||||||
|
&RSAPair::R15360(ref pbl,_) => RSAPublic::Key15360(pbl.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn private(&self) -> RSAPrivate
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
&RSAPair::R512(_,ref prv) => RSAPrivate::Key512(prv.clone()),
|
||||||
|
&RSAPair::R1024(_,ref prv) => RSAPrivate::Key1024(prv.clone()),
|
||||||
|
&RSAPair::R2048(_,ref prv) => RSAPrivate::Key2048(prv.clone()),
|
||||||
|
&RSAPair::R3072(_,ref prv) => RSAPrivate::Key3072(prv.clone()),
|
||||||
|
&RSAPair::R4096(_,ref prv) => RSAPrivate::Key4096(prv.clone()),
|
||||||
|
&RSAPair::R8192(_,ref prv) => RSAPrivate::Key8192(prv.clone()),
|
||||||
|
&RSAPair::R15360(_,ref prv) => RSAPrivate::Key15360(prv.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! generate_rsa_pair
|
||||||
|
{
|
||||||
|
($uint: ident, $half: ident, $iterations: expr) => {
|
||||||
|
impl KeyPair for RSAKeyPair<$uint> {
|
||||||
|
type Public = RSAPublicKey<$uint>;
|
||||||
|
type Private = RSAPrivateKey<$uint>;
|
||||||
|
|
||||||
|
fn new(pu: RSAPublicKey<$uint>, pr: RSAPrivateKey<$uint>) -> RSAKeyPair<$uint> {
|
||||||
|
RSAKeyPair {
|
||||||
public: pu,
|
public: pu,
|
||||||
private: pr
|
private: pr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generate<G>(rng: &mut G) -> $pair
|
impl RSAKeyPair<$uint> {
|
||||||
|
pub fn generate<G>(rng: &mut G) -> RSAKeyPair<$uint>
|
||||||
where G: RngCore
|
where G: RngCore
|
||||||
{
|
{
|
||||||
loop {
|
loop {
|
||||||
let ebase = 65537u32;
|
let ebase = 65537u32;
|
||||||
let e = $uint::from(ebase);
|
let e = $uint::from(ebase);
|
||||||
let (p, q) = $pair::generate_pq(rng, &$half::from(ebase));
|
let (p, q) = RSAKeyPair::<$uint>::generate_pq(rng, &$half::from(ebase));
|
||||||
let one = $half::from(1u32);
|
let one = $half::from(1u32);
|
||||||
let pminus1 = &p - &one;
|
let pminus1 = &p - &one;
|
||||||
let qminus1 = &q - &one;
|
let qminus1 = &q - &one;
|
||||||
let phi = pminus1 * qminus1;
|
let phi = pminus1 * qminus1;
|
||||||
let n = &p * &q;
|
let n = &p * &q;
|
||||||
if let Some(d) = e.modinv(&phi) {
|
if let Some(d) = e.modinv(&phi) {
|
||||||
let public = $pub::new(n.clone(), e);
|
let public = RSAPublicKey::<$uint>::new(n.clone(), e);
|
||||||
let private = $priv::new(n, d);
|
let private = RSAPrivateKey::<$uint>::new(n, d);
|
||||||
return $pair::new(public, private);
|
return RSAKeyPair::<$uint>::new(public, private);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,13 +284,13 @@ macro_rules! generate_rsa_pair
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_rsa_pair!(RSA512KeyPair, RSA512Public, RSA512Private, U512, U256, 7);
|
generate_rsa_pair!(U512, U256, 7);
|
||||||
generate_rsa_pair!(RSA1024KeyPair, RSA1024Public, RSA1024Private, U1024, U512, 7);
|
generate_rsa_pair!(U1024, U512, 7);
|
||||||
generate_rsa_pair!(RSA2048KeyPair, RSA2048Public, RSA2048Private, U2048, U1024, 4);
|
generate_rsa_pair!(U2048, U1024, 4);
|
||||||
generate_rsa_pair!(RSA3072KeyPair, RSA3072Public, RSA3072Private, U3072, U1536, 3);
|
generate_rsa_pair!(U3072, U1536, 3);
|
||||||
generate_rsa_pair!(RSA4096KeyPair, RSA4096Public, RSA4096Private, U4096, U2048, 3);
|
generate_rsa_pair!(U4096, U2048, 3);
|
||||||
generate_rsa_pair!(RSA8192KeyPair, RSA8192Public, RSA8192Private, U8192, U4096, 3);
|
generate_rsa_pair!(U8192, U4096, 3);
|
||||||
generate_rsa_pair!(RSA15360KeyPair, RSA15360Public, RSA15360Private, U15360, U7680, 3);
|
generate_rsa_pair!(U15360, U7680, 3);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod generation {
|
mod generation {
|
||||||
@@ -143,15 +298,15 @@ mod generation {
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl Clone for RSA512KeyPair {
|
impl Clone for RSAKeyPair<U512> {
|
||||||
fn clone(&self) -> RSA512KeyPair {
|
fn clone(&self) -> RSAKeyPair<U512> {
|
||||||
RSA512KeyPair{
|
RSAKeyPair {
|
||||||
public: RSA512Public {
|
public: RSAPublicKey {
|
||||||
n: self.public.n.clone(),
|
n: self.public.n.clone(),
|
||||||
nu: self.public.nu.clone(),
|
nu: self.public.nu.clone(),
|
||||||
e: self.public.e.clone(),
|
e: self.public.e.clone(),
|
||||||
},
|
},
|
||||||
private: RSA512Private {
|
private: RSAPrivateKey {
|
||||||
nu: self.private.nu.clone(),
|
nu: self.private.nu.clone(),
|
||||||
d: self.private.d.clone()
|
d: self.private.d.clone()
|
||||||
}
|
}
|
||||||
@@ -159,7 +314,7 @@ mod generation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for RSA512KeyPair {
|
impl fmt::Debug for RSAKeyPair<U512> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_struct("RSA512KeyPair")
|
f.debug_struct("RSA512KeyPair")
|
||||||
.field("n", &self.public.n)
|
.field("n", &self.public.n)
|
||||||
@@ -169,14 +324,14 @@ mod generation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Arbitrary for RSA512KeyPair {
|
impl Arbitrary for RSAKeyPair<U512> {
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> RSA512KeyPair {
|
fn arbitrary<G: Gen>(g: &mut G) -> RSAKeyPair<U512> {
|
||||||
RSA512KeyPair::generate(g)
|
RSAKeyPair::<U512>::generate(g)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn generate_and_sign(keypair: RSA512KeyPair, msg: Vec<u8>) -> bool {
|
fn generate_and_sign(keypair: RSAKeyPair<U512>, msg: Vec<u8>) -> bool {
|
||||||
let sig = keypair.private.sign(&SIGNING_HASH_SHA256, &msg);
|
let sig = keypair.private.sign(&SIGNING_HASH_SHA256, &msg);
|
||||||
keypair.public.verify(&SIGNING_HASH_SHA256, &msg, &sig)
|
keypair.public.verify(&SIGNING_HASH_SHA256, &msg, &sig)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
use byteorder::{BigEndian,ByteOrder};
|
use byteorder::{BigEndian,ByteOrder};
|
||||||
use digest::{Digest,FixedOutput};
|
use sha::Hash;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// Parameters for OAEP encryption and decryption: a hash function to use as
|
/// Parameters for OAEP encryption and decryption: a hash function to use as
|
||||||
/// part of the message generation function (MGF1, if you're curious),
|
/// part of the message generation function (MGF1, if you're curious),
|
||||||
/// and any labels you want to include as part of the encryption.
|
/// and any labels you want to include as part of the encryption.
|
||||||
pub struct OAEPParams<H: Default + Digest + FixedOutput> {
|
pub struct OAEPParams<H: Hash> {
|
||||||
pub label: String,
|
pub label: String,
|
||||||
phantom: PhantomData<H>
|
phantom: PhantomData<H>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: Default + Digest + FixedOutput> OAEPParams<H> {
|
impl<H: Hash> OAEPParams<H> {
|
||||||
pub fn new(label: String)
|
pub fn new(label: String)
|
||||||
-> OAEPParams<H>
|
-> OAEPParams<H>
|
||||||
{
|
{
|
||||||
@@ -18,11 +18,11 @@ impl<H: Default + Digest + FixedOutput> OAEPParams<H> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash_len(&self) -> usize {
|
pub fn hash_len(&self) -> usize {
|
||||||
H::default().fixed_result().as_slice().len()
|
H::hash(&[]).len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash(&self, input: &[u8]) -> Vec<u8> {
|
pub fn hash(&self, input: &[u8]) -> Vec<u8> {
|
||||||
H::digest(input).as_slice().to_vec()
|
H::hash(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mgf1(&self, input: &[u8], len: usize) -> Vec<u8> {
|
pub fn mgf1(&self, input: &[u8], len: usize) -> Vec<u8> {
|
||||||
@@ -32,10 +32,10 @@ impl<H: Default + Digest + FixedOutput> OAEPParams<H> {
|
|||||||
while res.len() < len {
|
while res.len() < len {
|
||||||
let mut buffer = [0; 4];
|
let mut buffer = [0; 4];
|
||||||
BigEndian::write_u32(&mut buffer, counter);
|
BigEndian::write_u32(&mut buffer, counter);
|
||||||
let mut digest = H::default();
|
let mut digest = H::new();
|
||||||
digest.input(input);
|
digest.update(input);
|
||||||
digest.input(&buffer);
|
digest.update(&buffer);
|
||||||
let chunk = digest.fixed_result();
|
let chunk = digest.finalize();
|
||||||
res.extend_from_slice(chunk.as_slice());
|
res.extend_from_slice(chunk.as_slice());
|
||||||
counter = counter + 1;
|
counter = counter + 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,49 @@
|
|||||||
use cryptonum::unsigned::*;
|
use cryptonum::unsigned::*;
|
||||||
use digest::{Digest,FixedOutput};
|
use rsa::core::{RSAMode,drop0s,pkcs1_pad,xor_vecs};
|
||||||
use rsa::core::{drop0s,pkcs1_pad,xor_vecs};
|
|
||||||
use rsa::errors::RSAError;
|
use rsa::errors::RSAError;
|
||||||
use rsa::oaep::OAEPParams;
|
use rsa::oaep::OAEPParams;
|
||||||
use rsa::signing_hashes::SigningHash;
|
use rsa::signing_hashes::SigningHash;
|
||||||
|
use sha::Hash;
|
||||||
|
|
||||||
pub trait RSAPrivateKey<N> {
|
/// An RSA private key. Useful for signing messages and decrypting encrypted
|
||||||
/// Generate a new private key using the given modulus and private
|
/// content.
|
||||||
/// exponent. You probably don't want to use this function directly
|
#[derive(Clone,PartialEq)]
|
||||||
/// unless you're writing your own key generation routine or key
|
pub struct RSAPrivateKey<R: RSAMode>
|
||||||
/// parsing library.
|
{
|
||||||
fn new(n: N, d: N) -> Self;
|
pub(crate) nu: R::Barrett,
|
||||||
|
pub(crate) d: R
|
||||||
/// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A generic RSA private key which is agnostic to its key size.
|
||||||
|
#[derive(Clone,PartialEq)]
|
||||||
pub enum RSAPrivate {
|
pub enum RSAPrivate {
|
||||||
Key512(RSA512Private),
|
Key512(RSAPrivateKey<U512>),
|
||||||
Key1024(RSA1024Private),
|
Key1024(RSAPrivateKey<U1024>),
|
||||||
Key2048(RSA2048Private),
|
Key2048(RSAPrivateKey<U2048>),
|
||||||
Key3072(RSA3072Private),
|
Key3072(RSAPrivateKey<U3072>),
|
||||||
Key4096(RSA4096Private),
|
Key4096(RSAPrivateKey<U4096>),
|
||||||
Key8192(RSA8192Private),
|
Key8192(RSAPrivateKey<U8192>),
|
||||||
Key15360(RSA15360Private)
|
Key15360(RSAPrivateKey<U15360>)
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! generate_rsa_private
|
macro_rules! generate_rsa_private
|
||||||
{
|
{
|
||||||
($rsa: ident, $num: ident, $bar: ident, $size: expr) => {
|
($num: ident, $bar: ident, $size: expr) => {
|
||||||
pub struct $rsa {
|
impl RSAPrivateKey<$num> {
|
||||||
pub(crate) nu: $bar,
|
/// Generate a new private key with the given modulus and private
|
||||||
pub(crate) d: $num
|
/// number (`d`). This operation actually does a bit of computation
|
||||||
}
|
/// under the hood, in order to speed up future ones, so you might
|
||||||
|
/// want to strongly consider sharing rather than multiple
|
||||||
impl RSAPrivateKey<$num> for $rsa {
|
/// instantiation. But you do you.
|
||||||
fn new(n: $num, d: $num) -> $rsa {
|
pub fn new(n: $num, d: $num) -> RSAPrivateKey<$num> {
|
||||||
let nu = $bar::new(n.clone());
|
let nu = $bar::new(n.clone());
|
||||||
$rsa { nu: nu, d: d }
|
RSAPrivateKey{ nu: nu, d: d }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign(&self, signhash: &SigningHash, msg: &[u8])
|
/// Sign the given message with the given SigningHash, returning
|
||||||
|
/// the signature. This uses a deterministic PKCS1 method for
|
||||||
|
/// signing messages, so no RNG required.
|
||||||
|
pub fn sign(&self, signhash: &SigningHash, msg: &[u8])
|
||||||
-> Vec<u8>
|
-> Vec<u8>
|
||||||
{
|
{
|
||||||
let hash = (signhash.run)(msg);
|
let hash = (signhash.run)(msg);
|
||||||
@@ -61,9 +54,15 @@ macro_rules! generate_rsa_private
|
|||||||
sig
|
sig
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8])
|
/// Decrypted the provided encrypted blob using the given
|
||||||
|
/// parameters. This does standard RSA OAEP decryption, which is
|
||||||
|
/// rather slow. If you have a choice, you should probably do
|
||||||
|
/// something clever, like only use this encryption/decryption
|
||||||
|
/// method to encrypt/decrypt a shared symmetric key, like an
|
||||||
|
/// AES key. That way, you only do this operation (which is
|
||||||
|
/// SO SLOW) for a relatively small amount of data.
|
||||||
|
pub fn decrypt<H: Hash>(&self, oaep: &OAEPParams<H>, msg: &[u8])
|
||||||
-> Result<Vec<u8>,RSAError>
|
-> Result<Vec<u8>,RSAError>
|
||||||
where H: Default + Digest + FixedOutput
|
|
||||||
{
|
{
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
|
|
||||||
@@ -74,9 +73,7 @@ macro_rules! generate_rsa_private
|
|||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl $rsa {
|
|
||||||
fn sp1(&self, m: &$num) -> $num {
|
fn sp1(&self, m: &$num) -> $num {
|
||||||
m.modexp(&self.d, &self.nu)
|
m.modexp(&self.d, &self.nu)
|
||||||
}
|
}
|
||||||
@@ -85,10 +82,8 @@ macro_rules! generate_rsa_private
|
|||||||
c.modexp(&self.d, &self.nu)
|
c.modexp(&self.d, &self.nu)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn oaep_decrypt<H>(&self, oaep: &OAEPParams<H>, c: &[u8])
|
fn oaep_decrypt<H: Hash>(&self, oaep: &OAEPParams<H>, c: &[u8])
|
||||||
-> Result<Vec<u8>,RSAError>
|
-> Result<Vec<u8>,RSAError>
|
||||||
where
|
|
||||||
H: Default + Digest + FixedOutput
|
|
||||||
{
|
{
|
||||||
let byte_len = $size / 8;
|
let byte_len = $size / 8;
|
||||||
// Step 1b
|
// Step 1b
|
||||||
@@ -139,17 +134,17 @@ macro_rules! generate_rsa_private
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_rsa_private!(RSA512Private, U512, BarrettU512, 512);
|
generate_rsa_private!(U512, BarrettU512, 512);
|
||||||
generate_rsa_private!(RSA1024Private, U1024, BarrettU1024, 1024);
|
generate_rsa_private!(U1024, BarrettU1024, 1024);
|
||||||
generate_rsa_private!(RSA2048Private, U2048, BarrettU2048, 2048);
|
generate_rsa_private!(U2048, BarrettU2048, 2048);
|
||||||
generate_rsa_private!(RSA3072Private, U3072, BarrettU3072, 3072);
|
generate_rsa_private!(U3072, BarrettU3072, 3072);
|
||||||
generate_rsa_private!(RSA4096Private, U4096, BarrettU4096, 4096);
|
generate_rsa_private!(U4096, BarrettU4096, 4096);
|
||||||
generate_rsa_private!(RSA8192Private, U8192, BarrettU8192, 8192);
|
generate_rsa_private!(U8192, BarrettU8192, 8192);
|
||||||
generate_rsa_private!(RSA15360Private, U15360, BarrettU15360, 15360);
|
generate_rsa_private!(U15360, BarrettU15360, 15360);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
macro_rules! sign_test_body {
|
macro_rules! sign_test_body {
|
||||||
($mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||||
let fname = format!("testdata/rsa/sign{}.test", $size);
|
let fname = format!("testdata/rsa/sign{}.test", $size);
|
||||||
run_test(fname.to_string(), 7, |case| {
|
run_test(fname.to_string(), 7, |case| {
|
||||||
let (neg0, dbytes) = case.get("d").unwrap();
|
let (neg0, dbytes) = case.get("d").unwrap();
|
||||||
@@ -173,7 +168,7 @@ macro_rules! sign_test_body {
|
|||||||
512 => &SIGNING_HASH_SHA512,
|
512 => &SIGNING_HASH_SHA512,
|
||||||
x => panic!("Bad signing hash: {}", x)
|
x => panic!("Bad signing hash: {}", x)
|
||||||
};
|
};
|
||||||
let privkey = $rsa{ nu: $bar::from_components(k, n.clone(), nu), d: d };
|
let privkey = RSAPrivateKey{ nu: $bar::from_components(k, n.clone(), nu), d: d };
|
||||||
let sig = privkey.sign(sighash, &mbytes);
|
let sig = privkey.sign(sighash, &mbytes);
|
||||||
assert_eq!(*sbytes, sig);
|
assert_eq!(*sbytes, sig);
|
||||||
});
|
});
|
||||||
@@ -182,7 +177,7 @@ macro_rules! sign_test_body {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
macro_rules! decrypt_test_body {
|
macro_rules! decrypt_test_body {
|
||||||
($mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||||
let fname = format!("testdata/rsa/encrypt{}.test", $size);
|
let fname = format!("testdata/rsa/encrypt{}.test", $size);
|
||||||
run_test(fname.to_string(), 9, |case| {
|
run_test(fname.to_string(), 9, |case| {
|
||||||
let (neg0, nbytes) = case.get("n").unwrap();
|
let (neg0, nbytes) = case.get("n").unwrap();
|
||||||
@@ -203,13 +198,13 @@ macro_rules! decrypt_test_body {
|
|||||||
let k = usize::from(bigk);
|
let k = usize::from(bigk);
|
||||||
let d = $num::from_bytes(dbytes);
|
let d = $num::from_bytes(dbytes);
|
||||||
let nu = $bar::from_components(k, n64, nu);
|
let nu = $bar::from_components(k, n64, nu);
|
||||||
let privkey = $rsa{ nu: nu, d: d };
|
let privkey = RSAPrivateKey{ nu: nu, d: d };
|
||||||
let lstr = String::from_utf8(lbytes.clone()).unwrap();
|
let lstr = String::from_utf8(lbytes.clone()).unwrap();
|
||||||
let message = match usize::from($num::from_bytes(hbytes)) {
|
let message = match usize::from($num::from_bytes(hbytes)) {
|
||||||
224 => privkey.decrypt(&OAEPParams::<Sha224>::new(lstr), &cbytes),
|
224 => privkey.decrypt(&OAEPParams::<SHA224>::new(lstr), &cbytes),
|
||||||
256 => privkey.decrypt(&OAEPParams::<Sha256>::new(lstr), &cbytes),
|
256 => privkey.decrypt(&OAEPParams::<SHA256>::new(lstr), &cbytes),
|
||||||
384 => privkey.decrypt(&OAEPParams::<Sha384>::new(lstr), &cbytes),
|
384 => privkey.decrypt(&OAEPParams::<SHA384>::new(lstr), &cbytes),
|
||||||
512 => privkey.decrypt(&OAEPParams::<Sha512>::new(lstr), &cbytes),
|
512 => privkey.decrypt(&OAEPParams::<SHA512>::new(lstr), &cbytes),
|
||||||
x => panic!("Unknown hash number: {}", x)
|
x => panic!("Unknown hash number: {}", x)
|
||||||
};
|
};
|
||||||
assert!(message.is_ok());
|
assert!(message.is_ok());
|
||||||
@@ -219,7 +214,7 @@ macro_rules! decrypt_test_body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! generate_tests {
|
macro_rules! generate_tests {
|
||||||
($mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
mod $mod {
|
mod $mod {
|
||||||
@@ -227,20 +222,20 @@ macro_rules! generate_tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use testing::run_test;
|
use testing::run_test;
|
||||||
use rsa::signing_hashes::*;
|
use rsa::signing_hashes::*;
|
||||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sign() {
|
fn sign() {
|
||||||
sign_test_body!($mod, $rsa, $num, $bar, $num64, $size);
|
sign_test_body!($mod, $num, $bar, $num64, $size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decrypt() {
|
fn decrypt() {
|
||||||
decrypt_test_body!($mod, $rsa, $num, $bar, $num64, $size);
|
decrypt_test_body!($mod, $num, $bar, $num64, $size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(ignore $mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
(ignore $mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
mod $mod {
|
mod $mod {
|
||||||
@@ -248,27 +243,27 @@ macro_rules! generate_tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use testing::run_test;
|
use testing::run_test;
|
||||||
use rsa::signing_hashes::*;
|
use rsa::signing_hashes::*;
|
||||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||||
|
|
||||||
#[ignore]
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
fn sign() {
|
fn sign() {
|
||||||
sign_test_body!($mod, $rsa, $num, $bar, $num64, $size);
|
sign_test_body!($mod, $num, $bar, $num64, $size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
fn decrypt() {
|
fn decrypt() {
|
||||||
decrypt_test_body!($mod, $rsa, $num, $bar, $num64, $size);
|
decrypt_test_body!($mod, $num, $bar, $num64, $size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_tests!(RSA512, RSA512Private, U512, BarrettU512, U576, 512);
|
generate_tests!( RSA512, U512, BarrettU512, U576, 512);
|
||||||
generate_tests!(RSA1024, RSA1024Private, U1024, BarrettU1024, U1088, 1024);
|
generate_tests!( RSA1024, U1024, BarrettU1024, U1088, 1024);
|
||||||
generate_tests!(RSA2048, RSA2048Private, U2048, BarrettU2048, U2112, 2048);
|
generate_tests!( RSA2048, U2048, BarrettU2048, U2112, 2048);
|
||||||
generate_tests!(RSA3072, RSA3072Private, U3072, BarrettU3072, U3136, 3072);
|
generate_tests!( RSA3072, U3072, BarrettU3072, U3136, 3072);
|
||||||
generate_tests!(RSA4096, RSA4096Private, U4096, BarrettU4096, U4160, 4096);
|
generate_tests!( RSA4096, U4096, BarrettU4096, U4160, 4096);
|
||||||
generate_tests!(ignore RSA8192, RSA8192Private, U8192, BarrettU8192, U8256, 8192);
|
generate_tests!(ignore RSA8192, U8192, BarrettU8192, U8256, 8192);
|
||||||
generate_tests!(ignore RSA15360, RSA15360Private, U15360, BarrettU15360, U15424, 15360);
|
generate_tests!(ignore RSA15360, U15360, BarrettU15360, U15424, 15360);
|
||||||
@@ -1,76 +1,42 @@
|
|||||||
use cryptonum::unsigned::*;
|
use cryptonum::unsigned::*;
|
||||||
use digest::{Digest,FixedOutput};
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use rsa::core::{decode_biguint,pkcs1_pad,xor_vecs};
|
use rsa::core::{RSAMode,decode_biguint,pkcs1_pad,xor_vecs};
|
||||||
use rsa::errors::RSAError;
|
use rsa::errors::RSAError;
|
||||||
use rsa::oaep::OAEPParams;
|
use rsa::oaep::OAEPParams;
|
||||||
use rsa::signing_hashes::SigningHash;
|
use rsa::signing_hashes::SigningHash;
|
||||||
|
use sha::Hash;
|
||||||
use simple_asn1::{ASN1Block,ASN1DecodeErr,ASN1EncodeErr,
|
use simple_asn1::{ASN1Block,ASN1DecodeErr,ASN1EncodeErr,
|
||||||
ASN1Class,FromASN1,ToASN1};
|
ASN1Class,FromASN1,ToASN1};
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use utils::TranslateNums;
|
use utils::TranslateNums;
|
||||||
|
|
||||||
pub trait RSAPublicKey<N> {
|
/// An RSA public key. Useful for verifying signatures or encrypting data to
|
||||||
/// Generate a new public key pair for the given modulus and
|
/// send to the private key holder.
|
||||||
/// exponent. You should probably not call this directly unless
|
#[derive(Clone,PartialEq)]
|
||||||
/// you're writing a key generation function or writing your own
|
pub struct RSAPublicKey<R: RSAMode> {
|
||||||
/// public key parser.
|
pub(crate) n: R,
|
||||||
fn new(n: N, e: N) -> Self;
|
pub(crate) nu: R::Barrett,
|
||||||
|
pub(crate) e: R
|
||||||
/// 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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A generic private key that is agnostic to the key size.
|
||||||
|
#[derive(Clone,PartialEq)]
|
||||||
pub enum RSAPublic {
|
pub enum RSAPublic {
|
||||||
Key512(RSA512Public),
|
Key512( RSAPublicKey<U512>),
|
||||||
Key1024(RSA1024Public),
|
Key1024( RSAPublicKey<U1024>),
|
||||||
Key2048(RSA2048Public),
|
Key2048( RSAPublicKey<U2048>),
|
||||||
Key3072(RSA3072Public),
|
Key3072( RSAPublicKey<U3072>),
|
||||||
Key4096(RSA4096Public),
|
Key4096( RSAPublicKey<U4096>),
|
||||||
Key8192(RSA8192Public),
|
Key8192( RSAPublicKey<U8192>),
|
||||||
Key15360(RSA15360Public)
|
Key15360(RSAPublicKey<U15360>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RSAPublic {
|
impl RSAPublic {
|
||||||
|
/// Verify that the given signature is for the given message, passing
|
||||||
|
/// in the same signing arguments used to sign the message in the
|
||||||
|
/// first place.
|
||||||
pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool
|
pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
@@ -109,43 +75,43 @@ impl FromASN1 for RSAPublic {
|
|||||||
512 => {
|
512 => {
|
||||||
let n2 = U512::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
let n2 = U512::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||||
let e2 = U512::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
let e2 = U512::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||||
let res = RSA512Public::new(n2, e2);
|
let res = RSAPublicKey::<U512>::new(n2, e2);
|
||||||
Ok((RSAPublic::Key512(res), rest))
|
Ok((RSAPublic::Key512(res), rest))
|
||||||
}
|
}
|
||||||
1024 => {
|
1024 => {
|
||||||
let n2 = U1024::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
let n2 = U1024::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||||
let e2 = U1024::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
let e2 = U1024::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||||
let res = RSA1024Public::new(n2, e2);
|
let res = RSAPublicKey::<U1024>::new(n2, e2);
|
||||||
Ok((RSAPublic::Key1024(res), rest))
|
Ok((RSAPublic::Key1024(res), rest))
|
||||||
}
|
}
|
||||||
2048 => {
|
2048 => {
|
||||||
let n2 = U2048::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
let n2 = U2048::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||||
let e2 = U2048::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
let e2 = U2048::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||||
let res = RSA2048Public::new(n2, e2);
|
let res = RSAPublicKey::<U2048>::new(n2, e2);
|
||||||
Ok((RSAPublic::Key2048(res), rest))
|
Ok((RSAPublic::Key2048(res), rest))
|
||||||
}
|
}
|
||||||
3072 => {
|
3072 => {
|
||||||
let n2 = U3072::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
let n2 = U3072::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||||
let e2 = U3072::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
let e2 = U3072::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||||
let res = RSA3072Public::new(n2, e2);
|
let res = RSAPublicKey::<U3072>::new(n2, e2);
|
||||||
Ok((RSAPublic::Key3072(res), rest))
|
Ok((RSAPublic::Key3072(res), rest))
|
||||||
}
|
}
|
||||||
4096 => {
|
4096 => {
|
||||||
let n2 = U4096::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
let n2 = U4096::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||||
let e2 = U4096::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
let e2 = U4096::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||||
let res = RSA4096Public::new(n2, e2);
|
let res = RSAPublicKey::<U4096>::new(n2, e2);
|
||||||
Ok((RSAPublic::Key4096(res), rest))
|
Ok((RSAPublic::Key4096(res), rest))
|
||||||
}
|
}
|
||||||
8192 => {
|
8192 => {
|
||||||
let n2 = U8192::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
let n2 = U8192::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||||
let e2 = U8192::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
let e2 = U8192::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||||
let res = RSA8192Public::new(n2, e2);
|
let res = RSAPublicKey::<U8192>::new(n2, e2);
|
||||||
Ok((RSAPublic::Key8192(res), rest))
|
Ok((RSAPublic::Key8192(res), rest))
|
||||||
}
|
}
|
||||||
15360 => {
|
15360 => {
|
||||||
let n2 = U15360::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
let n2 = U15360::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||||
let e2 = U15360::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
let e2 = U15360::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||||
let res = RSA15360Public::new(n2, e2);
|
let res = RSAPublicKey::<U15360>::new(n2, e2);
|
||||||
Ok((RSAPublic::Key15360(res), rest))
|
Ok((RSAPublic::Key15360(res), rest))
|
||||||
}
|
}
|
||||||
_ =>
|
_ =>
|
||||||
@@ -176,23 +142,39 @@ impl ToASN1 for RSAPublic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl fmt::Debug for RSAPublic {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
RSAPublic::Key512(x) => write!(fmt, "RSA:{:?}", x),
|
||||||
|
RSAPublic::Key1024(x) => write!(fmt, "RSA:{:?}", x),
|
||||||
|
RSAPublic::Key2048(x) => write!(fmt, "RSA:{:?}", x),
|
||||||
|
RSAPublic::Key3072(x) => write!(fmt, "RSA:{:?}", x),
|
||||||
|
RSAPublic::Key4096(x) => write!(fmt, "RSA:{:?}", x),
|
||||||
|
RSAPublic::Key8192(x) => write!(fmt, "RSA:{:?}", x),
|
||||||
|
RSAPublic::Key15360(x) => write!(fmt, "RSA:{:?}", x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! generate_rsa_public
|
macro_rules! generate_rsa_public
|
||||||
{
|
{
|
||||||
($rsa: ident, $num: ident, $bar: ident, $var: ident, $size: expr) => {
|
($num: ident, $bar: ident, $var: ident, $size: expr) => {
|
||||||
#[derive(PartialEq)]
|
impl RSAPublicKey<$num> {
|
||||||
pub struct $rsa {
|
/// Generate a new public key pair for the given modulus and
|
||||||
pub(crate) n: $num,
|
/// exponent. You should probably not call this directly unless
|
||||||
pub(crate) nu: $bar,
|
/// you're writing a key generation function or writing your own
|
||||||
pub(crate) e: $num
|
/// public key parser.
|
||||||
}
|
pub fn new(n: $num, e: $num) -> RSAPublicKey<$num> {
|
||||||
|
|
||||||
impl RSAPublicKey<$num> for $rsa {
|
|
||||||
fn new(n: $num, e: $num) -> $rsa {
|
|
||||||
let nu = $bar::new(n.clone());
|
let nu = $bar::new(n.clone());
|
||||||
$rsa { n: n, nu: nu, e: e }
|
RSAPublicKey{ n: n, nu: nu, e: e }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8])
|
/// 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.
|
||||||
|
pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8])
|
||||||
-> bool
|
-> bool
|
||||||
{
|
{
|
||||||
let hash: Vec<u8> = (signhash.run)(msg);
|
let hash: Vec<u8> = (signhash.run)(msg);
|
||||||
@@ -203,11 +185,22 @@ macro_rules! generate_rsa_public
|
|||||||
em == em_
|
em == em_
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encrypt_rng<G,H>(&self,g: &mut G,oaep: &OAEPParams<H>,msg: &[u8])
|
/// 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.
|
||||||
|
pub fn encrypt_rng<G,H>(&self,g: &mut G,oaep: &OAEPParams<H>,msg: &[u8])
|
||||||
-> Result<Vec<u8>,RSAError>
|
-> Result<Vec<u8>,RSAError>
|
||||||
where
|
where
|
||||||
G: Rng,
|
G: Rng,
|
||||||
H: Default + Digest + FixedOutput
|
H: Hash
|
||||||
{
|
{
|
||||||
let byte_len = $size / 8;
|
let byte_len = $size / 8;
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
@@ -222,9 +215,22 @@ macro_rules! generate_rsa_public
|
|||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
pub fn encrypt<H: Hash>(&self,oaep:&OAEPParams<H>,msg:&[u8])
|
||||||
|
-> Result<Vec<u8>,RSAError>
|
||||||
|
{
|
||||||
|
let mut g = OsRng::new()?;
|
||||||
|
self.encrypt_rng(&mut g, oaep, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $rsa {
|
|
||||||
fn vp1(&self, s: &$num) -> $num {
|
fn vp1(&self, s: &$num) -> $num {
|
||||||
s.modexp(&self.e, &self.nu)
|
s.modexp(&self.e, &self.nu)
|
||||||
}
|
}
|
||||||
@@ -237,7 +243,7 @@ macro_rules! generate_rsa_public
|
|||||||
-> Result<Vec<u8>,RSAError>
|
-> Result<Vec<u8>,RSAError>
|
||||||
where
|
where
|
||||||
G: Rng,
|
G: Rng,
|
||||||
H: Default + Digest + FixedOutput
|
H: Hash
|
||||||
{
|
{
|
||||||
let byte_len = $size / 8;
|
let byte_len = $size / 8;
|
||||||
// Step 1b
|
// Step 1b
|
||||||
@@ -283,11 +289,11 @@ macro_rules! generate_rsa_public
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromASN1 for $rsa {
|
impl FromASN1 for RSAPublicKey<$num> {
|
||||||
type Error = RSAError;
|
type Error = RSAError;
|
||||||
|
|
||||||
fn from_asn1(bs: &[ASN1Block])
|
fn from_asn1(bs: &[ASN1Block])
|
||||||
-> Result<($rsa,&[ASN1Block]),RSAError>
|
-> Result<(RSAPublicKey<$num>,&[ASN1Block]),RSAError>
|
||||||
{
|
{
|
||||||
let (core, rest) = RSAPublic::from_asn1(bs)?;
|
let (core, rest) = RSAPublic::from_asn1(bs)?;
|
||||||
|
|
||||||
@@ -298,7 +304,7 @@ macro_rules! generate_rsa_public
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToASN1 for $rsa {
|
impl ToASN1 for RSAPublicKey<$num> {
|
||||||
type Error = ASN1EncodeErr;
|
type Error = ASN1EncodeErr;
|
||||||
|
|
||||||
fn to_asn1_class(&self, c: ASN1Class)
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
@@ -314,7 +320,7 @@ macro_rules! generate_rsa_public
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
impl fmt::Debug for $rsa {
|
impl fmt::Debug for RSAPublicKey<$num> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt.debug_struct(stringify!($rsa))
|
fmt.debug_struct(stringify!($rsa))
|
||||||
.field("n", &self.n)
|
.field("n", &self.n)
|
||||||
@@ -326,17 +332,17 @@ macro_rules! generate_rsa_public
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_rsa_public!(RSA512Public, U512, BarrettU512, Key512, 512);
|
generate_rsa_public!(U512, BarrettU512, Key512, 512);
|
||||||
generate_rsa_public!(RSA1024Public, U1024, BarrettU1024, Key1024, 1024);
|
generate_rsa_public!(U1024, BarrettU1024, Key1024, 1024);
|
||||||
generate_rsa_public!(RSA2048Public, U2048, BarrettU2048, Key2048, 2048);
|
generate_rsa_public!(U2048, BarrettU2048, Key2048, 2048);
|
||||||
generate_rsa_public!(RSA3072Public, U3072, BarrettU3072, Key3072, 3072);
|
generate_rsa_public!(U3072, BarrettU3072, Key3072, 3072);
|
||||||
generate_rsa_public!(RSA4096Public, U4096, BarrettU4096, Key4096, 4096);
|
generate_rsa_public!(U4096, BarrettU4096, Key4096, 4096);
|
||||||
generate_rsa_public!(RSA8192Public, U8192, BarrettU8192, Key8192, 8192);
|
generate_rsa_public!(U8192, BarrettU8192, Key8192, 8192);
|
||||||
generate_rsa_public!(RSA15360Public, U15360, BarrettU15360, Key15360, 15360);
|
generate_rsa_public!(U15360, BarrettU15360, Key15360, 15360);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
macro_rules! new_test_body {
|
macro_rules! new_test_body {
|
||||||
($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||||
let fname = format!("testdata/rsa/sign{}.test", $size);
|
let fname = format!("testdata/rsa/sign{}.test", $size);
|
||||||
run_test(fname.to_string(), 7, |case| {
|
run_test(fname.to_string(), 7, |case| {
|
||||||
let (neg0, nbytes) = case.get("n").unwrap();
|
let (neg0, nbytes) = case.get("n").unwrap();
|
||||||
@@ -350,8 +356,8 @@ macro_rules! new_test_body {
|
|||||||
let bigk = $num::from_bytes(kbytes);
|
let bigk = $num::from_bytes(kbytes);
|
||||||
let k = usize::from(bigk);
|
let k = usize::from(bigk);
|
||||||
let e = $num::from(65537u64);
|
let e = $num::from(65537u64);
|
||||||
let pubkey2 = $rsa::new(n.clone(), e.clone());
|
let pubkey2 = RSAPublicKey::<$num>::new(n.clone(), e.clone());
|
||||||
let pubkey1 = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
let pubkey1 = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
||||||
assert_eq!(pubkey1, pubkey2);
|
assert_eq!(pubkey1, pubkey2);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -359,7 +365,7 @@ macro_rules! new_test_body {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
macro_rules! encode_test_body {
|
macro_rules! encode_test_body {
|
||||||
($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||||
let fname = format!("testdata/rsa/sign{}.test", $size);
|
let fname = format!("testdata/rsa/sign{}.test", $size);
|
||||||
run_test(fname.to_string(), 7, |case| {
|
run_test(fname.to_string(), 7, |case| {
|
||||||
let (neg0, nbytes) = case.get("n").unwrap();
|
let (neg0, nbytes) = case.get("n").unwrap();
|
||||||
@@ -373,9 +379,9 @@ macro_rules! encode_test_body {
|
|||||||
let bigk = $num::from_bytes(kbytes);
|
let bigk = $num::from_bytes(kbytes);
|
||||||
let k = usize::from(bigk);
|
let k = usize::from(bigk);
|
||||||
let e = $num::from(65537u64);
|
let e = $num::from(65537u64);
|
||||||
let pubkey = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
let pubkey = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
||||||
let asn1 = pubkey.to_asn1().unwrap();
|
let asn1 = pubkey.to_asn1().unwrap();
|
||||||
let (pubkey2, _) = $rsa::from_asn1(&asn1).unwrap();
|
let (pubkey2, _) = RSAPublicKey::from_asn1(&asn1).unwrap();
|
||||||
assert_eq!(pubkey, pubkey2);
|
assert_eq!(pubkey, pubkey2);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -383,7 +389,7 @@ macro_rules! encode_test_body {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
macro_rules! verify_test_body {
|
macro_rules! verify_test_body {
|
||||||
($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||||
let fname = format!("testdata/rsa/sign{}.test", $size);
|
let fname = format!("testdata/rsa/sign{}.test", $size);
|
||||||
run_test(fname.to_string(), 7, |case| {
|
run_test(fname.to_string(), 7, |case| {
|
||||||
let (neg0, nbytes) = case.get("n").unwrap();
|
let (neg0, nbytes) = case.get("n").unwrap();
|
||||||
@@ -400,7 +406,7 @@ macro_rules! verify_test_body {
|
|||||||
let bigk = $num::from_bytes(kbytes);
|
let bigk = $num::from_bytes(kbytes);
|
||||||
let k = usize::from(bigk);
|
let k = usize::from(bigk);
|
||||||
let e = $num::from(65537u64);
|
let e = $num::from(65537u64);
|
||||||
let pubkey = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
let pubkey = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
||||||
let hashnum = u64::from($num::from_bytes(hbytes));
|
let hashnum = u64::from($num::from_bytes(hbytes));
|
||||||
let sighash = match hashnum {
|
let sighash = match hashnum {
|
||||||
160 => &SIGNING_HASH_SHA1,
|
160 => &SIGNING_HASH_SHA1,
|
||||||
@@ -417,7 +423,7 @@ macro_rules! verify_test_body {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
macro_rules! encrypt_test_body {
|
macro_rules! encrypt_test_body {
|
||||||
($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||||
let fname = format!("testdata/rsa/encrypt{}.test", $size);
|
let fname = format!("testdata/rsa/encrypt{}.test", $size);
|
||||||
run_test(fname.to_string(), 9, |case| {
|
run_test(fname.to_string(), 9, |case| {
|
||||||
let (neg0, nbytes) = case.get("n").unwrap();
|
let (neg0, nbytes) = case.get("n").unwrap();
|
||||||
@@ -438,22 +444,22 @@ macro_rules! encrypt_test_body {
|
|||||||
let e = $num::from(65537u64);
|
let e = $num::from(65537u64);
|
||||||
let d = $num::from_bytes(dbytes);
|
let d = $num::from_bytes(dbytes);
|
||||||
let nu = $bar::from_components(k, n64, nu);
|
let nu = $bar::from_components(k, n64, nu);
|
||||||
let pubkey = $rsa{ n: n.clone(), nu: nu.clone(), e: e };
|
let pubkey = RSAPublicKey{ n: n.clone(), nu: nu.clone(), e: e };
|
||||||
let privkey = $priv{ nu: nu, d: d };
|
let privkey = RSAPrivateKey{ nu: nu, d: d };
|
||||||
let lstr = String::from_utf8(lbytes.clone()).unwrap();
|
let lstr = String::from_utf8(lbytes.clone()).unwrap();
|
||||||
let cipher = match usize::from($num::from_bytes(hbytes)) {
|
let cipher = match usize::from($num::from_bytes(hbytes)) {
|
||||||
224 => pubkey.encrypt(&OAEPParams::<Sha224>::new(lstr.clone()), mbytes),
|
224 => pubkey.encrypt(&OAEPParams::<SHA224>::new(lstr.clone()), mbytes),
|
||||||
256 => pubkey.encrypt(&OAEPParams::<Sha256>::new(lstr.clone()), mbytes),
|
256 => pubkey.encrypt(&OAEPParams::<SHA256>::new(lstr.clone()), mbytes),
|
||||||
384 => pubkey.encrypt(&OAEPParams::<Sha384>::new(lstr.clone()), mbytes),
|
384 => pubkey.encrypt(&OAEPParams::<SHA384>::new(lstr.clone()), mbytes),
|
||||||
512 => pubkey.encrypt(&OAEPParams::<Sha512>::new(lstr.clone()), mbytes),
|
512 => pubkey.encrypt(&OAEPParams::<SHA512>::new(lstr.clone()), mbytes),
|
||||||
x => panic!("Unknown hash number: {}", x)
|
x => panic!("Unknown hash number: {}", x)
|
||||||
};
|
};
|
||||||
assert!(cipher.is_ok());
|
assert!(cipher.is_ok());
|
||||||
let message = match usize::from($num::from_bytes(hbytes)) {
|
let message = match usize::from($num::from_bytes(hbytes)) {
|
||||||
224 => privkey.decrypt(&OAEPParams::<Sha224>::new(lstr), &cipher.unwrap()),
|
224 => privkey.decrypt(&OAEPParams::<SHA224>::new(lstr), &cipher.unwrap()),
|
||||||
256 => privkey.decrypt(&OAEPParams::<Sha256>::new(lstr), &cipher.unwrap()),
|
256 => privkey.decrypt(&OAEPParams::<SHA256>::new(lstr), &cipher.unwrap()),
|
||||||
384 => privkey.decrypt(&OAEPParams::<Sha384>::new(lstr), &cipher.unwrap()),
|
384 => privkey.decrypt(&OAEPParams::<SHA384>::new(lstr), &cipher.unwrap()),
|
||||||
512 => privkey.decrypt(&OAEPParams::<Sha512>::new(lstr), &cipher.unwrap()),
|
512 => privkey.decrypt(&OAEPParams::<SHA512>::new(lstr), &cipher.unwrap()),
|
||||||
x => panic!("Unknown hash number: {}", x)
|
x => panic!("Unknown hash number: {}", x)
|
||||||
};
|
};
|
||||||
assert!(message.is_ok());
|
assert!(message.is_ok());
|
||||||
@@ -463,7 +469,7 @@ macro_rules! encrypt_test_body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! generate_tests {
|
macro_rules! generate_tests {
|
||||||
($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
mod $mod {
|
mod $mod {
|
||||||
@@ -472,19 +478,19 @@ macro_rules! generate_tests {
|
|||||||
use testing::run_test;
|
use testing::run_test;
|
||||||
use rsa::private::*;
|
use rsa::private::*;
|
||||||
use rsa::signing_hashes::*;
|
use rsa::signing_hashes::*;
|
||||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn new() { new_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
|
fn new() { new_test_body!($mod, $num, $bar, $num64, $size); }
|
||||||
#[test]
|
#[test]
|
||||||
fn encode() { encode_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
|
fn encode() { encode_test_body!($mod, $num, $bar, $num64, $size); }
|
||||||
#[test]
|
#[test]
|
||||||
fn verify() { verify_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
|
fn verify() { verify_test_body!($mod, $num, $bar, $num64, $size); }
|
||||||
#[test]
|
#[test]
|
||||||
fn encrypt() { encrypt_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
|
fn encrypt() { encrypt_test_body!($mod, $num, $bar, $num64, $size); }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(ignore $mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
(ignore $mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
mod $mod {
|
mod $mod {
|
||||||
@@ -493,28 +499,28 @@ macro_rules! generate_tests {
|
|||||||
use testing::run_test;
|
use testing::run_test;
|
||||||
use rsa::private::*;
|
use rsa::private::*;
|
||||||
use rsa::signing_hashes::*;
|
use rsa::signing_hashes::*;
|
||||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||||
|
|
||||||
#[ignore]
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
fn new() { new_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
|
fn new() { new_test_body!($mod, $num, $bar, $num64, $size); }
|
||||||
#[ignore]
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
fn encode() { encode_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
|
fn encode() { encode_test_body!($mod, $num, $bar, $num64, $size); }
|
||||||
#[ignore]
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
fn verify() { verify_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
|
fn verify() { verify_test_body!($mod, $num, $bar, $num64, $size); }
|
||||||
#[ignore]
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
fn encrypt() { encrypt_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
|
fn encrypt() { encrypt_test_body!($mod, $num, $bar, $num64, $size); }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_tests!(RSA512, RSA512Public, RSA512Private, U512, BarrettU512, U576, 512);
|
generate_tests!( RSA512, U512, BarrettU512, U576, 512);
|
||||||
generate_tests!(RSA1024, RSA1024Public, RSA1024Private, U1024, BarrettU1024, U1088, 1024);
|
generate_tests!( RSA1024, U1024, BarrettU1024, U1088, 1024);
|
||||||
generate_tests!(RSA2048, RSA2048Public, RSA2048Private, U2048, BarrettU2048, U2112, 2048);
|
generate_tests!( RSA2048, U2048, BarrettU2048, U2112, 2048);
|
||||||
generate_tests!(RSA3072, RSA3072Public, RSA3072Private, U3072, BarrettU3072, U3136, 3072);
|
generate_tests!( RSA3072, U3072, BarrettU3072, U3136, 3072);
|
||||||
generate_tests!(RSA4096, RSA4096Public, RSA4096Private, U4096, BarrettU4096, U4160, 4096);
|
generate_tests!( RSA4096, U4096, BarrettU4096, U4160, 4096);
|
||||||
generate_tests!(ignore RSA8192, RSA8192Public, RSA8192Private, U8192, BarrettU8192, U8256, 8192);
|
generate_tests!(ignore RSA8192, U8192, BarrettU8192, U8256, 8192);
|
||||||
generate_tests!(ignore RSA15360, RSA15360Public, RSA15360Private, U15360, BarrettU15360, U15424, 15360);
|
generate_tests!(ignore RSA15360, U15360, BarrettU15360, U15424, 15360);
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
use digest::Digest;
|
use sha::{Hash,SHA1,SHA224,SHA256,SHA384,SHA512};
|
||||||
use sha1::Sha1;
|
|
||||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
/// A hash that can be used to sign a message.
|
/// A hash that can be used to sign a message.
|
||||||
@@ -28,13 +26,9 @@ impl fmt::Debug for SigningHash {
|
|||||||
pub static SIGNING_HASH_NULL: SigningHash = SigningHash {
|
pub static SIGNING_HASH_NULL: SigningHash = SigningHash {
|
||||||
name: "NULL",
|
name: "NULL",
|
||||||
ident: &[],
|
ident: &[],
|
||||||
run: nohash
|
run: |x| { x.to_vec() }
|
||||||
};
|
};
|
||||||
|
|
||||||
fn nohash(i: &[u8]) -> Vec<u8> {
|
|
||||||
i.to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sign a hash based on SHA1. You shouldn't use this unless you're using
|
/// Sign a hash based on SHA1. You shouldn't use this unless you're using
|
||||||
/// very small keys, and this is the only one available to you. Even then,
|
/// very small keys, and this is the only one available to you. Even then,
|
||||||
/// why are you using such small keys?!
|
/// why are you using such small keys?!
|
||||||
@@ -42,13 +36,9 @@ pub static SIGNING_HASH_SHA1: SigningHash = SigningHash {
|
|||||||
name: "SHA1",
|
name: "SHA1",
|
||||||
ident: &[0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,
|
ident: &[0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,
|
||||||
0x02,0x1a,0x05,0x00,0x04,0x14],
|
0x02,0x1a,0x05,0x00,0x04,0x14],
|
||||||
run: runsha1
|
run: |x| { SHA1::hash(x) }
|
||||||
};
|
};
|
||||||
|
|
||||||
fn runsha1(i: &[u8]) -> Vec<u8> {
|
|
||||||
Sha1::digest(i).as_slice().to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sign a hash based on SHA2-224. This is the first reasonable choice
|
/// Sign a hash based on SHA2-224. This is the first reasonable choice
|
||||||
/// we've come across, and is useful when you have smaller RSA key sizes.
|
/// we've come across, and is useful when you have smaller RSA key sizes.
|
||||||
/// I wouldn't recommend it, though.
|
/// I wouldn't recommend it, though.
|
||||||
@@ -57,26 +47,18 @@ pub static SIGNING_HASH_SHA224: SigningHash = SigningHash {
|
|||||||
ident: &[0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
ident: &[0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||||
0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,
|
0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,
|
||||||
0x1c],
|
0x1c],
|
||||||
run: runsha224
|
run: |x| { SHA224::hash(x) }
|
||||||
};
|
};
|
||||||
|
|
||||||
fn runsha224(i: &[u8]) -> Vec<u8> {
|
|
||||||
Sha224::digest(i).as_slice().to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sign a hash based on SHA2-256. The first one I'd recommend!
|
/// Sign a hash based on SHA2-256. The first one I'd recommend!
|
||||||
pub static SIGNING_HASH_SHA256: SigningHash = SigningHash {
|
pub static SIGNING_HASH_SHA256: SigningHash = SigningHash {
|
||||||
name: "SHA256",
|
name: "SHA256",
|
||||||
ident: &[0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
ident: &[0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||||
0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,
|
0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,
|
||||||
0x20],
|
0x20],
|
||||||
run: runsha256
|
run: |x| { SHA256::hash(x) }
|
||||||
};
|
};
|
||||||
|
|
||||||
fn runsha256(i: &[u8]) -> Vec<u8> {
|
|
||||||
Sha256::digest(i).as_slice().to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sign a hash based on SHA2-384. Approximately 50% better than
|
/// Sign a hash based on SHA2-384. Approximately 50% better than
|
||||||
/// SHA-256.
|
/// SHA-256.
|
||||||
pub static SIGNING_HASH_SHA384: SigningHash = SigningHash {
|
pub static SIGNING_HASH_SHA384: SigningHash = SigningHash {
|
||||||
@@ -84,13 +66,9 @@ pub static SIGNING_HASH_SHA384: SigningHash = SigningHash {
|
|||||||
ident: &[0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
ident: &[0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||||
0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,
|
0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,
|
||||||
0x30],
|
0x30],
|
||||||
run: runsha384
|
run: |x| { SHA384::hash(x) }
|
||||||
};
|
};
|
||||||
|
|
||||||
fn runsha384(i: &[u8]) -> Vec<u8> {
|
|
||||||
Sha384::digest(i).as_slice().to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sign a hash based on SHA2-512. At this point, you're getting a bit
|
/// Sign a hash based on SHA2-512. At this point, you're getting a bit
|
||||||
/// silly. But if you want to through 8kbit RSA keys with a 512 bit SHA2
|
/// silly. But if you want to through 8kbit RSA keys with a 512 bit SHA2
|
||||||
/// signing hash, we're totally behind you.
|
/// signing hash, we're totally behind you.
|
||||||
@@ -99,11 +77,5 @@ pub static SIGNING_HASH_SHA512: SigningHash = SigningHash {
|
|||||||
ident: &[0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
ident: &[0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||||
0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,
|
0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,
|
||||||
0x40],
|
0x40],
|
||||||
run: runsha512
|
run: |x| { SHA512::hash(x) }
|
||||||
};
|
};
|
||||||
|
|
||||||
fn runsha512(i: &[u8]) -> Vec<u8> {
|
|
||||||
Sha512::digest(i).as_slice().to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
64
src/sha/mod.rs
Normal file
64
src/sha/mod.rs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
//! The SHA family of hash functions, as defined by NIST; specifically, from
|
||||||
|
//! NIST 180-4 (for SHA1 and SHA2) and NIST 202 (for SHA3).
|
||||||
|
//!
|
||||||
|
//! These hash functions are used through their instantiation of the `Hash`
|
||||||
|
//! trait, located in the parent `simple_crypto` module and re-exported
|
||||||
|
//! here for convenience. Thus, you're not going to see a lot of functions
|
||||||
|
//! or macros, here, just the type declarations.
|
||||||
|
//!
|
||||||
|
//! To use SHA2-384, as an example, you could run the following code:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use simple_crypto::sha::{Hash,SHA384};
|
||||||
|
//!
|
||||||
|
//! let empty: [u8; 0] = [0; 0];
|
||||||
|
//! let mut digest_incremental = SHA384::new();
|
||||||
|
//! digest_incremental.update(&empty);
|
||||||
|
//! digest_incremental.update(&empty);
|
||||||
|
//! digest_incremental.update(&empty);
|
||||||
|
//! let result = digest_incremental.finalize();
|
||||||
|
//!
|
||||||
|
//! assert_eq!(result, vec![0x38,0xb0,0x60,0xa7,0x51,0xac,0x96,0x38,
|
||||||
|
//! 0x4c,0xd9,0x32,0x7e,0xb1,0xb1,0xe3,0x6a,
|
||||||
|
//! 0x21,0xfd,0xb7,0x11,0x14,0xbe,0x07,0x43,
|
||||||
|
//! 0x4c,0x0c,0xc7,0xbf,0x63,0xf6,0xe1,0xda,
|
||||||
|
//! 0x27,0x4e,0xde,0xbf,0xe7,0x6f,0x65,0xfb,
|
||||||
|
//! 0xd5,0x1a,0xd2,0xf1,0x48,0x98,0xb9,0x5b]);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! For other hashes, just substitute the appropriate hash structure for
|
||||||
|
//! `SHA384`. The `Hash` trait also includes a do-it-all-at-once built-in
|
||||||
|
//! function for those cases when you just have a single blob of data
|
||||||
|
//! you want to hash, rather than an incremental set of data:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use simple_crypto::sha::{Hash,SHA3_256};
|
||||||
|
//!
|
||||||
|
//! let empty: [u8; 0] = [0; 0];
|
||||||
|
//! let result = SHA3_256::hash(&empty);
|
||||||
|
//!
|
||||||
|
//! assert_eq!(result, vec![0xa7,0xff,0xc6,0xf8,0xbf,0x1e,0xd7,0x66,
|
||||||
|
//! 0x51,0xc1,0x47,0x56,0xa0,0x61,0xd6,0x62,
|
||||||
|
//! 0xf5,0x80,0xff,0x4d,0xe4,0x3b,0x49,0xfa,
|
||||||
|
//! 0x82,0xd8,0x0a,0x4b,0x80,0xf8,0x43,0x4a]);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! In general, you should not use SHA1 for anything but supporting legacy
|
||||||
|
//! systems. We recommend either SHA2 or SHA3 at their 256-, 384-, or 512-bit
|
||||||
|
//! sizes. NIST claims (in FIPS 202, page 23-24) that SHA2 and SHA3 are
|
||||||
|
//! approximately equivalent in terms of security for collision, preimate,
|
||||||
|
//! and second preimage attacks, but that SHA3 improves upon SHA2 against
|
||||||
|
//! length-extension and other attacks. On the other hand, SHA2 has been
|
||||||
|
//! banged on for a little longer, and there's some claims that it's more
|
||||||
|
//! resistant to quantum attacks. So ... make your own decisions.
|
||||||
|
#[macro_use]
|
||||||
|
mod shared;
|
||||||
|
mod sha1;
|
||||||
|
mod sha2;
|
||||||
|
mod sha3;
|
||||||
|
|
||||||
|
pub use super::Hash;
|
||||||
|
pub use self::sha1::SHA1;
|
||||||
|
pub use self::sha2::{SHA224,SHA256,SHA384,SHA512};
|
||||||
|
pub use self::sha3::{SHA3_224,SHA3_256,SHA3_384,SHA3_512};
|
||||||
|
pub(crate) use self::sha3::Keccak;
|
||||||
306
src/sha/sha1.rs
Normal file
306
src/sha/sha1.rs
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
use byteorder::{BigEndian,WriteBytesExt};
|
||||||
|
use super::super::Hash;
|
||||||
|
use sha::shared::calculate_k;
|
||||||
|
|
||||||
|
/// The SHA1 hash. Don't use this except to support legacy systems.
|
||||||
|
///
|
||||||
|
/// To use, you can run it in incremental mode -- by calling new(),
|
||||||
|
/// update() zero or more times, and then finalize() -- or you can
|
||||||
|
/// just invoke the hash directly. For example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use simple_crypto::sha::{Hash,SHA1};
|
||||||
|
///
|
||||||
|
/// let empty = [0; 0];
|
||||||
|
/// // Do the hash using the incremental API
|
||||||
|
/// let mut hashf = SHA1::new();
|
||||||
|
/// hashf.update(&empty);
|
||||||
|
/// let result_incremental = hashf.finalize();
|
||||||
|
/// // Do the hash using the direct API
|
||||||
|
/// let result_direct = SHA1::hash(&empty);
|
||||||
|
/// // ... and they should be the same
|
||||||
|
/// assert_eq!(result_incremental,result_direct);
|
||||||
|
/// ```
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SHA1 {
|
||||||
|
state: [u32; 5],
|
||||||
|
buffer: Vec<u8>,
|
||||||
|
done: bool,
|
||||||
|
l: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! sha1_step {
|
||||||
|
($op: ident, $out: ident, $ins: expr, $k: expr, $w: ident) => {
|
||||||
|
let $out = {
|
||||||
|
let [a,b,c,d,e] = $ins;
|
||||||
|
let ap = a.rotate_left(5) + $op!(b,c,d) + e + $k + $w;
|
||||||
|
let bp = a;
|
||||||
|
let cp = b.rotate_left(30);
|
||||||
|
let dp = c;
|
||||||
|
let ep = d;
|
||||||
|
[ap, bp, cp, dp, ep]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SHA1 {
|
||||||
|
fn process(&mut self, w00: u32, w01: u32, w02: u32, w03: u32,
|
||||||
|
w04: u32, w05: u32, w06: u32, w07: u32,
|
||||||
|
w08: u32, w09: u32, w10: u32, w11: u32,
|
||||||
|
w12: u32, w13: u32, w14: u32, w15: u32)
|
||||||
|
{
|
||||||
|
let w16 = (w13 ^ w08 ^ w02 ^ w00).rotate_left(1);
|
||||||
|
let w17 = (w14 ^ w09 ^ w03 ^ w01).rotate_left(1);
|
||||||
|
let w18 = (w15 ^ w10 ^ w04 ^ w02).rotate_left(1);
|
||||||
|
let w19 = (w16 ^ w11 ^ w05 ^ w03).rotate_left(1);
|
||||||
|
let w20 = (w17 ^ w12 ^ w06 ^ w04).rotate_left(1);
|
||||||
|
let w21 = (w18 ^ w13 ^ w07 ^ w05).rotate_left(1);
|
||||||
|
let w22 = (w19 ^ w14 ^ w08 ^ w06).rotate_left(1);
|
||||||
|
let w23 = (w20 ^ w15 ^ w09 ^ w07).rotate_left(1);
|
||||||
|
let w24 = (w21 ^ w16 ^ w10 ^ w08).rotate_left(1);
|
||||||
|
let w25 = (w22 ^ w17 ^ w11 ^ w09).rotate_left(1);
|
||||||
|
let w26 = (w23 ^ w18 ^ w12 ^ w10).rotate_left(1);
|
||||||
|
let w27 = (w24 ^ w19 ^ w13 ^ w11).rotate_left(1);
|
||||||
|
let w28 = (w25 ^ w20 ^ w14 ^ w12).rotate_left(1);
|
||||||
|
let w29 = (w26 ^ w21 ^ w15 ^ w13).rotate_left(1);
|
||||||
|
let w30 = (w27 ^ w22 ^ w16 ^ w14).rotate_left(1);
|
||||||
|
let w31 = (w28 ^ w23 ^ w17 ^ w15).rotate_left(1);
|
||||||
|
let w32 = (w29 ^ w24 ^ w18 ^ w16).rotate_left(1);
|
||||||
|
let w33 = (w30 ^ w25 ^ w19 ^ w17).rotate_left(1);
|
||||||
|
let w34 = (w31 ^ w26 ^ w20 ^ w18).rotate_left(1);
|
||||||
|
let w35 = (w32 ^ w27 ^ w21 ^ w19).rotate_left(1);
|
||||||
|
let w36 = (w33 ^ w28 ^ w22 ^ w20).rotate_left(1);
|
||||||
|
let w37 = (w34 ^ w29 ^ w23 ^ w21).rotate_left(1);
|
||||||
|
let w38 = (w35 ^ w30 ^ w24 ^ w22).rotate_left(1);
|
||||||
|
let w39 = (w36 ^ w31 ^ w25 ^ w23).rotate_left(1);
|
||||||
|
let w40 = (w37 ^ w32 ^ w26 ^ w24).rotate_left(1);
|
||||||
|
let w41 = (w38 ^ w33 ^ w27 ^ w25).rotate_left(1);
|
||||||
|
let w42 = (w39 ^ w34 ^ w28 ^ w26).rotate_left(1);
|
||||||
|
let w43 = (w40 ^ w35 ^ w29 ^ w27).rotate_left(1);
|
||||||
|
let w44 = (w41 ^ w36 ^ w30 ^ w28).rotate_left(1);
|
||||||
|
let w45 = (w42 ^ w37 ^ w31 ^ w29).rotate_left(1);
|
||||||
|
let w46 = (w43 ^ w38 ^ w32 ^ w30).rotate_left(1);
|
||||||
|
let w47 = (w44 ^ w39 ^ w33 ^ w31).rotate_left(1);
|
||||||
|
let w48 = (w45 ^ w40 ^ w34 ^ w32).rotate_left(1);
|
||||||
|
let w49 = (w46 ^ w41 ^ w35 ^ w33).rotate_left(1);
|
||||||
|
let w50 = (w47 ^ w42 ^ w36 ^ w34).rotate_left(1);
|
||||||
|
let w51 = (w48 ^ w43 ^ w37 ^ w35).rotate_left(1);
|
||||||
|
let w52 = (w49 ^ w44 ^ w38 ^ w36).rotate_left(1);
|
||||||
|
let w53 = (w50 ^ w45 ^ w39 ^ w37).rotate_left(1);
|
||||||
|
let w54 = (w51 ^ w46 ^ w40 ^ w38).rotate_left(1);
|
||||||
|
let w55 = (w52 ^ w47 ^ w41 ^ w39).rotate_left(1);
|
||||||
|
let w56 = (w53 ^ w48 ^ w42 ^ w40).rotate_left(1);
|
||||||
|
let w57 = (w54 ^ w49 ^ w43 ^ w41).rotate_left(1);
|
||||||
|
let w58 = (w55 ^ w50 ^ w44 ^ w42).rotate_left(1);
|
||||||
|
let w59 = (w56 ^ w51 ^ w45 ^ w43).rotate_left(1);
|
||||||
|
let w60 = (w57 ^ w52 ^ w46 ^ w44).rotate_left(1);
|
||||||
|
let w61 = (w58 ^ w53 ^ w47 ^ w45).rotate_left(1);
|
||||||
|
let w62 = (w59 ^ w54 ^ w48 ^ w46).rotate_left(1);
|
||||||
|
let w63 = (w60 ^ w55 ^ w49 ^ w47).rotate_left(1);
|
||||||
|
let w64 = (w61 ^ w56 ^ w50 ^ w48).rotate_left(1);
|
||||||
|
let w65 = (w62 ^ w57 ^ w51 ^ w49).rotate_left(1);
|
||||||
|
let w66 = (w63 ^ w58 ^ w52 ^ w50).rotate_left(1);
|
||||||
|
let w67 = (w64 ^ w59 ^ w53 ^ w51).rotate_left(1);
|
||||||
|
let w68 = (w65 ^ w60 ^ w54 ^ w52).rotate_left(1);
|
||||||
|
let w69 = (w66 ^ w61 ^ w55 ^ w53).rotate_left(1);
|
||||||
|
let w70 = (w67 ^ w62 ^ w56 ^ w54).rotate_left(1);
|
||||||
|
let w71 = (w68 ^ w63 ^ w57 ^ w55).rotate_left(1);
|
||||||
|
let w72 = (w69 ^ w64 ^ w58 ^ w56).rotate_left(1);
|
||||||
|
let w73 = (w70 ^ w65 ^ w59 ^ w57).rotate_left(1);
|
||||||
|
let w74 = (w71 ^ w66 ^ w60 ^ w58).rotate_left(1);
|
||||||
|
let w75 = (w72 ^ w67 ^ w61 ^ w59).rotate_left(1);
|
||||||
|
let w76 = (w73 ^ w68 ^ w62 ^ w60).rotate_left(1);
|
||||||
|
let w77 = (w74 ^ w69 ^ w63 ^ w61).rotate_left(1);
|
||||||
|
let w78 = (w75 ^ w70 ^ w64 ^ w62).rotate_left(1);
|
||||||
|
let w79 = (w76 ^ w71 ^ w65 ^ w63).rotate_left(1);
|
||||||
|
sha1_step!(ch, s01, self.state, 0x5a827999, w00);
|
||||||
|
sha1_step!(ch, s02, s01, 0x5a827999, w01);
|
||||||
|
sha1_step!(ch, s03, s02, 0x5a827999, w02);
|
||||||
|
sha1_step!(ch, s04, s03, 0x5a827999, w03);
|
||||||
|
sha1_step!(ch, s05, s04, 0x5a827999, w04);
|
||||||
|
sha1_step!(ch, s06, s05, 0x5a827999, w05);
|
||||||
|
sha1_step!(ch, s07, s06, 0x5a827999, w06);
|
||||||
|
sha1_step!(ch, s08, s07, 0x5a827999, w07);
|
||||||
|
sha1_step!(ch, s09, s08, 0x5a827999, w08);
|
||||||
|
sha1_step!(ch, s10, s09, 0x5a827999, w09);
|
||||||
|
sha1_step!(ch, s11, s10, 0x5a827999, w10);
|
||||||
|
sha1_step!(ch, s12, s11, 0x5a827999, w11);
|
||||||
|
sha1_step!(ch, s13, s12, 0x5a827999, w12);
|
||||||
|
sha1_step!(ch, s14, s13, 0x5a827999, w13);
|
||||||
|
sha1_step!(ch, s15, s14, 0x5a827999, w14);
|
||||||
|
sha1_step!(ch, s16, s15, 0x5a827999, w15);
|
||||||
|
sha1_step!(ch, s17, s16, 0x5a827999, w16);
|
||||||
|
sha1_step!(ch, s18, s17, 0x5a827999, w17);
|
||||||
|
sha1_step!(ch, s19, s18, 0x5a827999, w18);
|
||||||
|
sha1_step!(ch, s20, s19, 0x5a827999, w19);
|
||||||
|
sha1_step!(parity, s21, s20, 0x6ed9eba1, w20);
|
||||||
|
sha1_step!(parity, s22, s21, 0x6ed9eba1, w21);
|
||||||
|
sha1_step!(parity, s23, s22, 0x6ed9eba1, w22);
|
||||||
|
sha1_step!(parity, s24, s23, 0x6ed9eba1, w23);
|
||||||
|
sha1_step!(parity, s25, s24, 0x6ed9eba1, w24);
|
||||||
|
sha1_step!(parity, s26, s25, 0x6ed9eba1, w25);
|
||||||
|
sha1_step!(parity, s27, s26, 0x6ed9eba1, w26);
|
||||||
|
sha1_step!(parity, s28, s27, 0x6ed9eba1, w27);
|
||||||
|
sha1_step!(parity, s29, s28, 0x6ed9eba1, w28);
|
||||||
|
sha1_step!(parity, s30, s29, 0x6ed9eba1, w29);
|
||||||
|
sha1_step!(parity, s31, s30, 0x6ed9eba1, w30);
|
||||||
|
sha1_step!(parity, s32, s31, 0x6ed9eba1, w31);
|
||||||
|
sha1_step!(parity, s33, s32, 0x6ed9eba1, w32);
|
||||||
|
sha1_step!(parity, s34, s33, 0x6ed9eba1, w33);
|
||||||
|
sha1_step!(parity, s35, s34, 0x6ed9eba1, w34);
|
||||||
|
sha1_step!(parity, s36, s35, 0x6ed9eba1, w35);
|
||||||
|
sha1_step!(parity, s37, s36, 0x6ed9eba1, w36);
|
||||||
|
sha1_step!(parity, s38, s37, 0x6ed9eba1, w37);
|
||||||
|
sha1_step!(parity, s39, s38, 0x6ed9eba1, w38);
|
||||||
|
sha1_step!(parity, s40, s39, 0x6ed9eba1, w39);
|
||||||
|
sha1_step!(maj, s41, s40, 0x8f1bbcdc, w40);
|
||||||
|
sha1_step!(maj, s42, s41, 0x8f1bbcdc, w41);
|
||||||
|
sha1_step!(maj, s43, s42, 0x8f1bbcdc, w42);
|
||||||
|
sha1_step!(maj, s44, s43, 0x8f1bbcdc, w43);
|
||||||
|
sha1_step!(maj, s45, s44, 0x8f1bbcdc, w44);
|
||||||
|
sha1_step!(maj, s46, s45, 0x8f1bbcdc, w45);
|
||||||
|
sha1_step!(maj, s47, s46, 0x8f1bbcdc, w46);
|
||||||
|
sha1_step!(maj, s48, s47, 0x8f1bbcdc, w47);
|
||||||
|
sha1_step!(maj, s49, s48, 0x8f1bbcdc, w48);
|
||||||
|
sha1_step!(maj, s50, s49, 0x8f1bbcdc, w49);
|
||||||
|
sha1_step!(maj, s51, s50, 0x8f1bbcdc, w50);
|
||||||
|
sha1_step!(maj, s52, s51, 0x8f1bbcdc, w51);
|
||||||
|
sha1_step!(maj, s53, s52, 0x8f1bbcdc, w52);
|
||||||
|
sha1_step!(maj, s54, s53, 0x8f1bbcdc, w53);
|
||||||
|
sha1_step!(maj, s55, s54, 0x8f1bbcdc, w54);
|
||||||
|
sha1_step!(maj, s56, s55, 0x8f1bbcdc, w55);
|
||||||
|
sha1_step!(maj, s57, s56, 0x8f1bbcdc, w56);
|
||||||
|
sha1_step!(maj, s58, s57, 0x8f1bbcdc, w57);
|
||||||
|
sha1_step!(maj, s59, s58, 0x8f1bbcdc, w58);
|
||||||
|
sha1_step!(maj, s60, s59, 0x8f1bbcdc, w59);
|
||||||
|
sha1_step!(parity, s61, s60, 0xca62c1d6, w60);
|
||||||
|
sha1_step!(parity, s62, s61, 0xca62c1d6, w61);
|
||||||
|
sha1_step!(parity, s63, s62, 0xca62c1d6, w62);
|
||||||
|
sha1_step!(parity, s64, s63, 0xca62c1d6, w63);
|
||||||
|
sha1_step!(parity, s65, s64, 0xca62c1d6, w64);
|
||||||
|
sha1_step!(parity, s66, s65, 0xca62c1d6, w65);
|
||||||
|
sha1_step!(parity, s67, s66, 0xca62c1d6, w66);
|
||||||
|
sha1_step!(parity, s68, s67, 0xca62c1d6, w67);
|
||||||
|
sha1_step!(parity, s69, s68, 0xca62c1d6, w68);
|
||||||
|
sha1_step!(parity, s70, s69, 0xca62c1d6, w69);
|
||||||
|
sha1_step!(parity, s71, s70, 0xca62c1d6, w70);
|
||||||
|
sha1_step!(parity, s72, s71, 0xca62c1d6, w71);
|
||||||
|
sha1_step!(parity, s73, s72, 0xca62c1d6, w72);
|
||||||
|
sha1_step!(parity, s74, s73, 0xca62c1d6, w73);
|
||||||
|
sha1_step!(parity, s75, s74, 0xca62c1d6, w74);
|
||||||
|
sha1_step!(parity, s76, s75, 0xca62c1d6, w75);
|
||||||
|
sha1_step!(parity, s77, s76, 0xca62c1d6, w76);
|
||||||
|
sha1_step!(parity, s78, s77, 0xca62c1d6, w77);
|
||||||
|
sha1_step!(parity, s79, s78, 0xca62c1d6, w78);
|
||||||
|
sha1_step!(parity, s80, s79, 0xca62c1d6, w79);
|
||||||
|
self.state[0] += s80[0];
|
||||||
|
self.state[1] += s80[1];
|
||||||
|
self.state[2] += s80[2];
|
||||||
|
self.state[3] += s80[3];
|
||||||
|
self.state[4] += s80[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish(&mut self)
|
||||||
|
{
|
||||||
|
let bitlen = self.l * 8;
|
||||||
|
let k = calculate_k(448, 512, bitlen);
|
||||||
|
// INVARIANT: k is necessarily > 0, and (k + 1) is a multiple of 8
|
||||||
|
let bytes_to_add = (k + 1) / 8;
|
||||||
|
let mut padvec = Vec::with_capacity(bytes_to_add + 8);
|
||||||
|
padvec.push(0x80); // Set the high bit, since the first bit after the data
|
||||||
|
// should be set
|
||||||
|
padvec.resize(bytes_to_add, 0);
|
||||||
|
padvec.write_u64::<BigEndian>(bitlen as u64).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
self.update(&padvec);
|
||||||
|
self.done = true;
|
||||||
|
assert_eq!(self.buffer.len(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for SHA1
|
||||||
|
{
|
||||||
|
fn new() -> SHA1
|
||||||
|
{
|
||||||
|
SHA1 {
|
||||||
|
state: [ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 ],
|
||||||
|
buffer: Vec::with_capacity(64),
|
||||||
|
done: false,
|
||||||
|
l: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, block: &[u8])
|
||||||
|
{
|
||||||
|
if !self.done {
|
||||||
|
let mut offset = 0;
|
||||||
|
|
||||||
|
self.l += block.len();
|
||||||
|
|
||||||
|
if self.buffer.len() + block.len() < 64 {
|
||||||
|
self.buffer.extend_from_slice(block);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.buffer.len() > 0 {
|
||||||
|
// We must be able to build up a 64 byte chunk, at this point, otherwise
|
||||||
|
// the math above would've been wrong.
|
||||||
|
while self.buffer.len() < 64 {
|
||||||
|
self.buffer.push(block[offset]);
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
process_u32_block!(self.buffer, 0, self);
|
||||||
|
// Reset the buffer now, we're done with that nonsense for the moment
|
||||||
|
self.buffer.resize(0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (offset + 64) <= block.len() {
|
||||||
|
process_u32_block!(block, offset, self);
|
||||||
|
offset += 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
if offset < block.len() {
|
||||||
|
self.buffer.extend_from_slice(&block[offset..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
if !self.done {
|
||||||
|
self.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut output = Vec::with_capacity(20);
|
||||||
|
output.write_u32::<BigEndian>(self.state[0]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state[1]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state[2]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state[3]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state[4]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_size() -> usize
|
||||||
|
{
|
||||||
|
512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use testing::run_test;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn nist() {
|
||||||
|
let fname = "testdata/sha/nist_sha1.test";
|
||||||
|
run_test(fname.to_string(), 3, |case| {
|
||||||
|
let (negl, lbytes) = case.get("l").unwrap();
|
||||||
|
let (negm, mbytes) = case.get("m").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
|
||||||
|
assert!(!negl && !negm && !negd);
|
||||||
|
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||||
|
let digest = SHA1::hash(&msg);
|
||||||
|
assert_eq!(dbytes, &digest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
842
src/sha/sha2.rs
Normal file
842
src/sha/sha2.rs
Normal file
@@ -0,0 +1,842 @@
|
|||||||
|
use byteorder::{BigEndian,ByteOrder,WriteBytesExt};
|
||||||
|
use sha::shared::calculate_k;
|
||||||
|
use super::super::Hash;
|
||||||
|
|
||||||
|
/// The SHA2-224 hash.
|
||||||
|
///
|
||||||
|
/// To use, you can run it in incremental mode -- by calling new(),
|
||||||
|
/// update() zero or more times, and then finalize() -- or you can
|
||||||
|
/// just invoke the hash directly. For example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use simple_crypto::sha::{Hash,SHA224};
|
||||||
|
///
|
||||||
|
/// let empty = [0; 0];
|
||||||
|
/// // Do the hash using the incremental API
|
||||||
|
/// let mut hashf = SHA224::new();
|
||||||
|
/// hashf.update(&empty);
|
||||||
|
/// let result_incremental = hashf.finalize();
|
||||||
|
/// // Do the hash using the direct API
|
||||||
|
/// let result_direct = SHA224::hash(&empty);
|
||||||
|
/// // ... and they should be the same
|
||||||
|
/// assert_eq!(result_incremental,result_direct);
|
||||||
|
/// ```
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SHA224 {
|
||||||
|
state: SHA256State
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for SHA224 {
|
||||||
|
fn new() -> Self
|
||||||
|
{
|
||||||
|
let state = SHA256State::new([0xc1059ed8,0x367cd507,0x3070dd17,0xf70e5939,
|
||||||
|
0xffc00b31,0x68581511,0x64f98fa7,0xbefa4fa4]);
|
||||||
|
SHA224{ state }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, data: &[u8])
|
||||||
|
{
|
||||||
|
self.state.update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
if !self.state.done {
|
||||||
|
self.state.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut output = Vec::with_capacity(28);
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[0]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[1]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[2]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[3]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[4]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[5]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[6]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_size() -> usize
|
||||||
|
{
|
||||||
|
512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The SHA2-256 hash. [GOOD]
|
||||||
|
///
|
||||||
|
/// To use, you can run it in incremental mode -- by calling new(),
|
||||||
|
/// update() zero or more times, and then finalize() -- or you can
|
||||||
|
/// just invoke the hash directly. For example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use simple_crypto::sha::{Hash,SHA256};
|
||||||
|
///
|
||||||
|
/// let empty = [0; 0];
|
||||||
|
/// // Do the hash using the incremental API
|
||||||
|
/// let mut hashf = SHA256::new();
|
||||||
|
/// hashf.update(&empty);
|
||||||
|
/// let result_incremental = hashf.finalize();
|
||||||
|
/// // Do the hash using the direct API
|
||||||
|
/// let result_direct = SHA256::hash(&empty);
|
||||||
|
/// // ... and they should be the same
|
||||||
|
/// assert_eq!(result_incremental,result_direct);
|
||||||
|
/// ```
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SHA256 {
|
||||||
|
state: SHA256State
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for SHA256 {
|
||||||
|
fn new() -> Self
|
||||||
|
{
|
||||||
|
let state = SHA256State::new([0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,
|
||||||
|
0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19]);
|
||||||
|
SHA256{ state }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, data: &[u8])
|
||||||
|
{
|
||||||
|
self.state.update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
if !self.state.done {
|
||||||
|
self.state.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut output = Vec::with_capacity(28);
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[0]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[1]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[2]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[3]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[4]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[5]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[6]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u32::<BigEndian>(self.state.state[7]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_size() -> usize
|
||||||
|
{
|
||||||
|
512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The SHA2-384 hash. [BETTER]
|
||||||
|
///
|
||||||
|
/// To use, you can run it in incremental mode -- by calling new(),
|
||||||
|
/// update() zero or more times, and then finalize() -- or you can
|
||||||
|
/// just invoke the hash directly. For example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use simple_crypto::sha::{Hash,SHA384};
|
||||||
|
///
|
||||||
|
/// let empty = [0; 0];
|
||||||
|
/// // Do the hash using the incremental API
|
||||||
|
/// let mut hashf = SHA384::new();
|
||||||
|
/// hashf.update(&empty);
|
||||||
|
/// let result_incremental = hashf.finalize();
|
||||||
|
/// // Do the hash using the direct API
|
||||||
|
/// let result_direct = SHA384::hash(&empty);
|
||||||
|
/// // ... and they should be the same
|
||||||
|
/// assert_eq!(result_incremental,result_direct);
|
||||||
|
/// ```
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SHA384 {
|
||||||
|
state: SHA512State
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for SHA384 {
|
||||||
|
fn new() -> Self
|
||||||
|
{
|
||||||
|
let state = SHA512State::new([0xcbbb9d5dc1059ed8,0x629a292a367cd507,
|
||||||
|
0x9159015a3070dd17,0x152fecd8f70e5939,
|
||||||
|
0x67332667ffc00b31,0x8eb44a8768581511,
|
||||||
|
0xdb0c2e0d64f98fa7,0x47b5481dbefa4fa4]);
|
||||||
|
SHA384{ state }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, data: &[u8])
|
||||||
|
{
|
||||||
|
self.state.update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
if !self.state.done {
|
||||||
|
self.state.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut output = Vec::with_capacity(64);
|
||||||
|
output.write_u64::<BigEndian>(self.state.state[0]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u64::<BigEndian>(self.state.state[1]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u64::<BigEndian>(self.state.state[2]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u64::<BigEndian>(self.state.state[3]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u64::<BigEndian>(self.state.state[4]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u64::<BigEndian>(self.state.state[5]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_size() -> usize
|
||||||
|
{
|
||||||
|
1024
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The SHA2-512 hash. [BEST]
|
||||||
|
///
|
||||||
|
/// To use, you can run it in incremental mode -- by calling new(),
|
||||||
|
/// update() zero or more times, and then finalize() -- or you can
|
||||||
|
/// just invoke the hash directly. For example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use simple_crypto::sha::{Hash,SHA512};
|
||||||
|
///
|
||||||
|
/// let empty = [0; 0];
|
||||||
|
/// // Do the hash using the incremental API
|
||||||
|
/// let mut hashf = SHA512::new();
|
||||||
|
/// hashf.update(&empty);
|
||||||
|
/// let result_incremental = hashf.finalize();
|
||||||
|
/// // Do the hash using the direct API
|
||||||
|
/// let result_direct = SHA512::hash(&empty);
|
||||||
|
/// // ... and they should be the same
|
||||||
|
/// assert_eq!(result_incremental,result_direct);
|
||||||
|
/// ```
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SHA512 {
|
||||||
|
state: SHA512State
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for SHA512 {
|
||||||
|
fn new() -> Self
|
||||||
|
{
|
||||||
|
let state = SHA512State::new([0x6a09e667f3bcc908,0xbb67ae8584caa73b,
|
||||||
|
0x3c6ef372fe94f82b,0xa54ff53a5f1d36f1,
|
||||||
|
0x510e527fade682d1,0x9b05688c2b3e6c1f,
|
||||||
|
0x1f83d9abfb41bd6b,0x5be0cd19137e2179]);
|
||||||
|
SHA512{ state }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, data: &[u8])
|
||||||
|
{
|
||||||
|
self.state.update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
if !self.state.done {
|
||||||
|
self.state.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut output = Vec::with_capacity(64);
|
||||||
|
output.write_u64::<BigEndian>(self.state.state[0]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u64::<BigEndian>(self.state.state[1]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u64::<BigEndian>(self.state.state[2]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u64::<BigEndian>(self.state.state[3]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u64::<BigEndian>(self.state.state[4]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u64::<BigEndian>(self.state.state[5]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u64::<BigEndian>(self.state.state[6]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output.write_u64::<BigEndian>(self.state.state[7]).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_size() -> usize
|
||||||
|
{
|
||||||
|
1024
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! bsig256_0 {
|
||||||
|
($x: ident) => {
|
||||||
|
$x.rotate_right(2) ^ $x.rotate_right(13) ^ $x.rotate_right(22)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! bsig256_1 {
|
||||||
|
($x: ident) => {
|
||||||
|
$x.rotate_right(6) ^ $x.rotate_right(11) ^ $x.rotate_right(25)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! lsig256_0 {
|
||||||
|
($x: ident) => {
|
||||||
|
$x.rotate_right(7) ^ $x.rotate_right(18) ^ ($x >> 3)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! lsig256_1 {
|
||||||
|
($x: ident) => {
|
||||||
|
$x.rotate_right(17) ^ $x.rotate_right(19) ^ ($x >> 10)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct SHA256State {
|
||||||
|
state: [u32; 8],
|
||||||
|
buffer: Vec<u8>,
|
||||||
|
done: bool,
|
||||||
|
l: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SHA256State {
|
||||||
|
fn new(values: [u32; 8]) -> Self {
|
||||||
|
SHA256State {
|
||||||
|
state: values,
|
||||||
|
buffer: Vec::with_capacity(64),
|
||||||
|
done: false,
|
||||||
|
l: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process(&mut self, w00: u32, w01: u32, w02: u32, w03: u32,
|
||||||
|
w04: u32, w05: u32, w06: u32, w07: u32,
|
||||||
|
w08: u32, w09: u32, w10: u32, w11: u32,
|
||||||
|
w12: u32, w13: u32, w14: u32, w15: u32)
|
||||||
|
{
|
||||||
|
let w16 = lsig256_1!(w14) + w09 + lsig256_0!(w01) + w00;
|
||||||
|
let w17 = lsig256_1!(w15) + w10 + lsig256_0!(w02) + w01;
|
||||||
|
let w18 = lsig256_1!(w16) + w11 + lsig256_0!(w03) + w02;
|
||||||
|
let w19 = lsig256_1!(w17) + w12 + lsig256_0!(w04) + w03;
|
||||||
|
let w20 = lsig256_1!(w18) + w13 + lsig256_0!(w05) + w04;
|
||||||
|
let w21 = lsig256_1!(w19) + w14 + lsig256_0!(w06) + w05;
|
||||||
|
let w22 = lsig256_1!(w20) + w15 + lsig256_0!(w07) + w06;
|
||||||
|
let w23 = lsig256_1!(w21) + w16 + lsig256_0!(w08) + w07;
|
||||||
|
let w24 = lsig256_1!(w22) + w17 + lsig256_0!(w09) + w08;
|
||||||
|
let w25 = lsig256_1!(w23) + w18 + lsig256_0!(w10) + w09;
|
||||||
|
let w26 = lsig256_1!(w24) + w19 + lsig256_0!(w11) + w10;
|
||||||
|
let w27 = lsig256_1!(w25) + w20 + lsig256_0!(w12) + w11;
|
||||||
|
let w28 = lsig256_1!(w26) + w21 + lsig256_0!(w13) + w12;
|
||||||
|
let w29 = lsig256_1!(w27) + w22 + lsig256_0!(w14) + w13;
|
||||||
|
let w30 = lsig256_1!(w28) + w23 + lsig256_0!(w15) + w14;
|
||||||
|
let w31 = lsig256_1!(w29) + w24 + lsig256_0!(w16) + w15;
|
||||||
|
let w32 = lsig256_1!(w30) + w25 + lsig256_0!(w17) + w16;
|
||||||
|
let w33 = lsig256_1!(w31) + w26 + lsig256_0!(w18) + w17;
|
||||||
|
let w34 = lsig256_1!(w32) + w27 + lsig256_0!(w19) + w18;
|
||||||
|
let w35 = lsig256_1!(w33) + w28 + lsig256_0!(w20) + w19;
|
||||||
|
let w36 = lsig256_1!(w34) + w29 + lsig256_0!(w21) + w20;
|
||||||
|
let w37 = lsig256_1!(w35) + w30 + lsig256_0!(w22) + w21;
|
||||||
|
let w38 = lsig256_1!(w36) + w31 + lsig256_0!(w23) + w22;
|
||||||
|
let w39 = lsig256_1!(w37) + w32 + lsig256_0!(w24) + w23;
|
||||||
|
let w40 = lsig256_1!(w38) + w33 + lsig256_0!(w25) + w24;
|
||||||
|
let w41 = lsig256_1!(w39) + w34 + lsig256_0!(w26) + w25;
|
||||||
|
let w42 = lsig256_1!(w40) + w35 + lsig256_0!(w27) + w26;
|
||||||
|
let w43 = lsig256_1!(w41) + w36 + lsig256_0!(w28) + w27;
|
||||||
|
let w44 = lsig256_1!(w42) + w37 + lsig256_0!(w29) + w28;
|
||||||
|
let w45 = lsig256_1!(w43) + w38 + lsig256_0!(w30) + w29;
|
||||||
|
let w46 = lsig256_1!(w44) + w39 + lsig256_0!(w31) + w30;
|
||||||
|
let w47 = lsig256_1!(w45) + w40 + lsig256_0!(w32) + w31;
|
||||||
|
let w48 = lsig256_1!(w46) + w41 + lsig256_0!(w33) + w32;
|
||||||
|
let w49 = lsig256_1!(w47) + w42 + lsig256_0!(w34) + w33;
|
||||||
|
let w50 = lsig256_1!(w48) + w43 + lsig256_0!(w35) + w34;
|
||||||
|
let w51 = lsig256_1!(w49) + w44 + lsig256_0!(w36) + w35;
|
||||||
|
let w52 = lsig256_1!(w50) + w45 + lsig256_0!(w37) + w36;
|
||||||
|
let w53 = lsig256_1!(w51) + w46 + lsig256_0!(w38) + w37;
|
||||||
|
let w54 = lsig256_1!(w52) + w47 + lsig256_0!(w39) + w38;
|
||||||
|
let w55 = lsig256_1!(w53) + w48 + lsig256_0!(w40) + w39;
|
||||||
|
let w56 = lsig256_1!(w54) + w49 + lsig256_0!(w41) + w40;
|
||||||
|
let w57 = lsig256_1!(w55) + w50 + lsig256_0!(w42) + w41;
|
||||||
|
let w58 = lsig256_1!(w56) + w51 + lsig256_0!(w43) + w42;
|
||||||
|
let w59 = lsig256_1!(w57) + w52 + lsig256_0!(w44) + w43;
|
||||||
|
let w60 = lsig256_1!(w58) + w53 + lsig256_0!(w45) + w44;
|
||||||
|
let w61 = lsig256_1!(w59) + w54 + lsig256_0!(w46) + w45;
|
||||||
|
let w62 = lsig256_1!(w60) + w55 + lsig256_0!(w47) + w46;
|
||||||
|
let w63 = lsig256_1!(w61) + w56 + lsig256_0!(w48) + w47;
|
||||||
|
let s01 = step256(self.state,0x428a2f98,w00);
|
||||||
|
let s02 = step256(s01,0x71374491,w01);
|
||||||
|
let s03 = step256(s02,0xb5c0fbcf,w02);
|
||||||
|
let s04 = step256(s03,0xe9b5dba5,w03);
|
||||||
|
let s05 = step256(s04,0x3956c25b,w04);
|
||||||
|
let s06 = step256(s05,0x59f111f1,w05);
|
||||||
|
let s07 = step256(s06,0x923f82a4,w06);
|
||||||
|
let s08 = step256(s07,0xab1c5ed5,w07);
|
||||||
|
let s09 = step256(s08,0xd807aa98,w08);
|
||||||
|
let s10 = step256(s09,0x12835b01,w09);
|
||||||
|
let s11 = step256(s10,0x243185be,w10);
|
||||||
|
let s12 = step256(s11,0x550c7dc3,w11);
|
||||||
|
let s13 = step256(s12,0x72be5d74,w12);
|
||||||
|
let s14 = step256(s13,0x80deb1fe,w13);
|
||||||
|
let s15 = step256(s14,0x9bdc06a7,w14);
|
||||||
|
let s16 = step256(s15,0xc19bf174,w15);
|
||||||
|
let s17 = step256(s16,0xe49b69c1,w16);
|
||||||
|
let s18 = step256(s17,0xefbe4786,w17);
|
||||||
|
let s19 = step256(s18,0x0fc19dc6,w18);
|
||||||
|
let s20 = step256(s19,0x240ca1cc,w19);
|
||||||
|
let s21 = step256(s20,0x2de92c6f,w20);
|
||||||
|
let s22 = step256(s21,0x4a7484aa,w21);
|
||||||
|
let s23 = step256(s22,0x5cb0a9dc,w22);
|
||||||
|
let s24 = step256(s23,0x76f988da,w23);
|
||||||
|
let s25 = step256(s24,0x983e5152,w24);
|
||||||
|
let s26 = step256(s25,0xa831c66d,w25);
|
||||||
|
let s27 = step256(s26,0xb00327c8,w26);
|
||||||
|
let s28 = step256(s27,0xbf597fc7,w27);
|
||||||
|
let s29 = step256(s28,0xc6e00bf3,w28);
|
||||||
|
let s30 = step256(s29,0xd5a79147,w29);
|
||||||
|
let s31 = step256(s30,0x06ca6351,w30);
|
||||||
|
let s32 = step256(s31,0x14292967,w31);
|
||||||
|
let s33 = step256(s32,0x27b70a85,w32);
|
||||||
|
let s34 = step256(s33,0x2e1b2138,w33);
|
||||||
|
let s35 = step256(s34,0x4d2c6dfc,w34);
|
||||||
|
let s36 = step256(s35,0x53380d13,w35);
|
||||||
|
let s37 = step256(s36,0x650a7354,w36);
|
||||||
|
let s38 = step256(s37,0x766a0abb,w37);
|
||||||
|
let s39 = step256(s38,0x81c2c92e,w38);
|
||||||
|
let s40 = step256(s39,0x92722c85,w39);
|
||||||
|
let s41 = step256(s40,0xa2bfe8a1,w40);
|
||||||
|
let s42 = step256(s41,0xa81a664b,w41);
|
||||||
|
let s43 = step256(s42,0xc24b8b70,w42);
|
||||||
|
let s44 = step256(s43,0xc76c51a3,w43);
|
||||||
|
let s45 = step256(s44,0xd192e819,w44);
|
||||||
|
let s46 = step256(s45,0xd6990624,w45);
|
||||||
|
let s47 = step256(s46,0xf40e3585,w46);
|
||||||
|
let s48 = step256(s47,0x106aa070,w47);
|
||||||
|
let s49 = step256(s48,0x19a4c116,w48);
|
||||||
|
let s50 = step256(s49,0x1e376c08,w49);
|
||||||
|
let s51 = step256(s50,0x2748774c,w50);
|
||||||
|
let s52 = step256(s51,0x34b0bcb5,w51);
|
||||||
|
let s53 = step256(s52,0x391c0cb3,w52);
|
||||||
|
let s54 = step256(s53,0x4ed8aa4a,w53);
|
||||||
|
let s55 = step256(s54,0x5b9cca4f,w54);
|
||||||
|
let s56 = step256(s55,0x682e6ff3,w55);
|
||||||
|
let s57 = step256(s56,0x748f82ee,w56);
|
||||||
|
let s58 = step256(s57,0x78a5636f,w57);
|
||||||
|
let s59 = step256(s58,0x84c87814,w58);
|
||||||
|
let s60 = step256(s59,0x8cc70208,w59);
|
||||||
|
let s61 = step256(s60,0x90befffa,w60);
|
||||||
|
let s62 = step256(s61,0xa4506ceb,w61);
|
||||||
|
let s63 = step256(s62,0xbef9a3f7,w62);
|
||||||
|
let s64 = step256(s63,0xc67178f2,w63);
|
||||||
|
self.state[0] += s64[0];
|
||||||
|
self.state[1] += s64[1];
|
||||||
|
self.state[2] += s64[2];
|
||||||
|
self.state[3] += s64[3];
|
||||||
|
self.state[4] += s64[4];
|
||||||
|
self.state[5] += s64[5];
|
||||||
|
self.state[6] += s64[6];
|
||||||
|
self.state[7] += s64[7];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, block: &[u8]) {
|
||||||
|
if !self.done {
|
||||||
|
let mut offset = 0;
|
||||||
|
|
||||||
|
self.l += block.len();
|
||||||
|
|
||||||
|
if self.buffer.len() + block.len() < 64 {
|
||||||
|
self.buffer.extend_from_slice(block);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.buffer.len() > 0 {
|
||||||
|
// We must be able to build up a 64 byte chunk, at this point, otherwise
|
||||||
|
// the math above would've been wrong.
|
||||||
|
while self.buffer.len() < 64 {
|
||||||
|
self.buffer.push(block[offset]);
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
process_u32_block!(self.buffer, 0, self);
|
||||||
|
// Reset the buffer now, we're done with that nonsense for the moment
|
||||||
|
self.buffer.resize(0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (offset + 64) <= block.len() {
|
||||||
|
process_u32_block!(block, offset, self);
|
||||||
|
offset += 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
if offset < block.len() {
|
||||||
|
self.buffer.extend_from_slice(&block[offset..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish(&mut self) {
|
||||||
|
let bitlen = self.l * 8;
|
||||||
|
let k = calculate_k(448, 512, bitlen);
|
||||||
|
// INVARIANT: k is necessarily > 0, and (k + 1) is a multiple of 8
|
||||||
|
let bytes_to_add = (k + 1) / 8;
|
||||||
|
let mut padvec = Vec::with_capacity(bytes_to_add + 8);
|
||||||
|
padvec.push(0x80); // Set the high bit, since the first bit after the data
|
||||||
|
// should be set
|
||||||
|
padvec.resize(bytes_to_add, 0);
|
||||||
|
padvec.write_u64::<BigEndian>(bitlen as u64).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
self.update(&padvec);
|
||||||
|
self.done = true;
|
||||||
|
assert_eq!(self.buffer.len(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn step256(state0: [u32; 8], k: u32, w: u32) -> [u32; 8]
|
||||||
|
{
|
||||||
|
let [a,b,c,d,e,f,g,h] = state0;
|
||||||
|
let t1 = h + bsig256_1!(e) + ch!(e,f,g) + k + w;
|
||||||
|
let t2 = bsig256_0!(a) + maj!(a,b,c);
|
||||||
|
let hp = g;
|
||||||
|
let gp = f;
|
||||||
|
let fp = e;
|
||||||
|
let ep = d + t1;
|
||||||
|
let dp = c;
|
||||||
|
let cp = b;
|
||||||
|
let bp = a;
|
||||||
|
let ap = t1 + t2;
|
||||||
|
[ap,bp,cp,dp,ep,fp,gp,hp]
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! bsig512_0 {
|
||||||
|
($x: ident) => {
|
||||||
|
$x.rotate_right(28) ^ $x.rotate_right(34) ^ $x.rotate_right(39)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! bsig512_1 {
|
||||||
|
($x: ident) => {
|
||||||
|
$x.rotate_right(14) ^ $x.rotate_right(18) ^ $x.rotate_right(41)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! lsig512_0 {
|
||||||
|
($x: ident) => {
|
||||||
|
$x.rotate_right(1) ^ $x.rotate_right(8) ^ ($x >> 7)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! lsig512_1 {
|
||||||
|
($x: ident) => {
|
||||||
|
$x.rotate_right(19) ^ $x.rotate_right(61) ^ ($x >> 6)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! process_u64_block {
|
||||||
|
($buf: expr, $off: expr, $self: ident) => {{
|
||||||
|
let w00 = BigEndian::read_u64(&$buf[$off+0..]);
|
||||||
|
let w01 = BigEndian::read_u64(&$buf[$off+8..]);
|
||||||
|
let w02 = BigEndian::read_u64(&$buf[$off+16..]);
|
||||||
|
let w03 = BigEndian::read_u64(&$buf[$off+24..]);
|
||||||
|
let w04 = BigEndian::read_u64(&$buf[$off+32..]);
|
||||||
|
let w05 = BigEndian::read_u64(&$buf[$off+40..]);
|
||||||
|
let w06 = BigEndian::read_u64(&$buf[$off+48..]);
|
||||||
|
let w07 = BigEndian::read_u64(&$buf[$off+56..]);
|
||||||
|
let w08 = BigEndian::read_u64(&$buf[$off+64..]);
|
||||||
|
let w09 = BigEndian::read_u64(&$buf[$off+72..]);
|
||||||
|
let w10 = BigEndian::read_u64(&$buf[$off+80..]);
|
||||||
|
let w11 = BigEndian::read_u64(&$buf[$off+88..]);
|
||||||
|
let w12 = BigEndian::read_u64(&$buf[$off+96..]);
|
||||||
|
let w13 = BigEndian::read_u64(&$buf[$off+104..]);
|
||||||
|
let w14 = BigEndian::read_u64(&$buf[$off+112..]);
|
||||||
|
let w15 = BigEndian::read_u64(&$buf[$off+120..]);
|
||||||
|
$self.process(w00, w01, w02, w03, w04, w05, w06, w07,
|
||||||
|
w08, w09, w10, w11, w12, w13, w14, w15);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct SHA512State {
|
||||||
|
state: [u64; 8],
|
||||||
|
buffer: Vec<u8>,
|
||||||
|
done: bool,
|
||||||
|
l: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SHA512State {
|
||||||
|
fn new(values: [u64; 8]) -> Self {
|
||||||
|
SHA512State {
|
||||||
|
state: values,
|
||||||
|
buffer: Vec::with_capacity(128),
|
||||||
|
done: false,
|
||||||
|
l: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process(&mut self, w00: u64, w01: u64, w02: u64, w03: u64,
|
||||||
|
w04: u64, w05: u64, w06: u64, w07: u64,
|
||||||
|
w08: u64, w09: u64, w10: u64, w11: u64,
|
||||||
|
w12: u64, w13: u64, w14: u64, w15: u64)
|
||||||
|
{
|
||||||
|
let w16 = lsig512_1!(w14) + w09 + lsig512_0!(w01) + w00;
|
||||||
|
let w17 = lsig512_1!(w15) + w10 + lsig512_0!(w02) + w01;
|
||||||
|
let w18 = lsig512_1!(w16) + w11 + lsig512_0!(w03) + w02;
|
||||||
|
let w19 = lsig512_1!(w17) + w12 + lsig512_0!(w04) + w03;
|
||||||
|
let w20 = lsig512_1!(w18) + w13 + lsig512_0!(w05) + w04;
|
||||||
|
let w21 = lsig512_1!(w19) + w14 + lsig512_0!(w06) + w05;
|
||||||
|
let w22 = lsig512_1!(w20) + w15 + lsig512_0!(w07) + w06;
|
||||||
|
let w23 = lsig512_1!(w21) + w16 + lsig512_0!(w08) + w07;
|
||||||
|
let w24 = lsig512_1!(w22) + w17 + lsig512_0!(w09) + w08;
|
||||||
|
let w25 = lsig512_1!(w23) + w18 + lsig512_0!(w10) + w09;
|
||||||
|
let w26 = lsig512_1!(w24) + w19 + lsig512_0!(w11) + w10;
|
||||||
|
let w27 = lsig512_1!(w25) + w20 + lsig512_0!(w12) + w11;
|
||||||
|
let w28 = lsig512_1!(w26) + w21 + lsig512_0!(w13) + w12;
|
||||||
|
let w29 = lsig512_1!(w27) + w22 + lsig512_0!(w14) + w13;
|
||||||
|
let w30 = lsig512_1!(w28) + w23 + lsig512_0!(w15) + w14;
|
||||||
|
let w31 = lsig512_1!(w29) + w24 + lsig512_0!(w16) + w15;
|
||||||
|
let w32 = lsig512_1!(w30) + w25 + lsig512_0!(w17) + w16;
|
||||||
|
let w33 = lsig512_1!(w31) + w26 + lsig512_0!(w18) + w17;
|
||||||
|
let w34 = lsig512_1!(w32) + w27 + lsig512_0!(w19) + w18;
|
||||||
|
let w35 = lsig512_1!(w33) + w28 + lsig512_0!(w20) + w19;
|
||||||
|
let w36 = lsig512_1!(w34) + w29 + lsig512_0!(w21) + w20;
|
||||||
|
let w37 = lsig512_1!(w35) + w30 + lsig512_0!(w22) + w21;
|
||||||
|
let w38 = lsig512_1!(w36) + w31 + lsig512_0!(w23) + w22;
|
||||||
|
let w39 = lsig512_1!(w37) + w32 + lsig512_0!(w24) + w23;
|
||||||
|
let w40 = lsig512_1!(w38) + w33 + lsig512_0!(w25) + w24;
|
||||||
|
let w41 = lsig512_1!(w39) + w34 + lsig512_0!(w26) + w25;
|
||||||
|
let w42 = lsig512_1!(w40) + w35 + lsig512_0!(w27) + w26;
|
||||||
|
let w43 = lsig512_1!(w41) + w36 + lsig512_0!(w28) + w27;
|
||||||
|
let w44 = lsig512_1!(w42) + w37 + lsig512_0!(w29) + w28;
|
||||||
|
let w45 = lsig512_1!(w43) + w38 + lsig512_0!(w30) + w29;
|
||||||
|
let w46 = lsig512_1!(w44) + w39 + lsig512_0!(w31) + w30;
|
||||||
|
let w47 = lsig512_1!(w45) + w40 + lsig512_0!(w32) + w31;
|
||||||
|
let w48 = lsig512_1!(w46) + w41 + lsig512_0!(w33) + w32;
|
||||||
|
let w49 = lsig512_1!(w47) + w42 + lsig512_0!(w34) + w33;
|
||||||
|
let w50 = lsig512_1!(w48) + w43 + lsig512_0!(w35) + w34;
|
||||||
|
let w51 = lsig512_1!(w49) + w44 + lsig512_0!(w36) + w35;
|
||||||
|
let w52 = lsig512_1!(w50) + w45 + lsig512_0!(w37) + w36;
|
||||||
|
let w53 = lsig512_1!(w51) + w46 + lsig512_0!(w38) + w37;
|
||||||
|
let w54 = lsig512_1!(w52) + w47 + lsig512_0!(w39) + w38;
|
||||||
|
let w55 = lsig512_1!(w53) + w48 + lsig512_0!(w40) + w39;
|
||||||
|
let w56 = lsig512_1!(w54) + w49 + lsig512_0!(w41) + w40;
|
||||||
|
let w57 = lsig512_1!(w55) + w50 + lsig512_0!(w42) + w41;
|
||||||
|
let w58 = lsig512_1!(w56) + w51 + lsig512_0!(w43) + w42;
|
||||||
|
let w59 = lsig512_1!(w57) + w52 + lsig512_0!(w44) + w43;
|
||||||
|
let w60 = lsig512_1!(w58) + w53 + lsig512_0!(w45) + w44;
|
||||||
|
let w61 = lsig512_1!(w59) + w54 + lsig512_0!(w46) + w45;
|
||||||
|
let w62 = lsig512_1!(w60) + w55 + lsig512_0!(w47) + w46;
|
||||||
|
let w63 = lsig512_1!(w61) + w56 + lsig512_0!(w48) + w47;
|
||||||
|
let w64 = lsig512_1!(w62) + w57 + lsig512_0!(w49) + w48;
|
||||||
|
let w65 = lsig512_1!(w63) + w58 + lsig512_0!(w50) + w49;
|
||||||
|
let w66 = lsig512_1!(w64) + w59 + lsig512_0!(w51) + w50;
|
||||||
|
let w67 = lsig512_1!(w65) + w60 + lsig512_0!(w52) + w51;
|
||||||
|
let w68 = lsig512_1!(w66) + w61 + lsig512_0!(w53) + w52;
|
||||||
|
let w69 = lsig512_1!(w67) + w62 + lsig512_0!(w54) + w53;
|
||||||
|
let w70 = lsig512_1!(w68) + w63 + lsig512_0!(w55) + w54;
|
||||||
|
let w71 = lsig512_1!(w69) + w64 + lsig512_0!(w56) + w55;
|
||||||
|
let w72 = lsig512_1!(w70) + w65 + lsig512_0!(w57) + w56;
|
||||||
|
let w73 = lsig512_1!(w71) + w66 + lsig512_0!(w58) + w57;
|
||||||
|
let w74 = lsig512_1!(w72) + w67 + lsig512_0!(w59) + w58;
|
||||||
|
let w75 = lsig512_1!(w73) + w68 + lsig512_0!(w60) + w59;
|
||||||
|
let w76 = lsig512_1!(w74) + w69 + lsig512_0!(w61) + w60;
|
||||||
|
let w77 = lsig512_1!(w75) + w70 + lsig512_0!(w62) + w61;
|
||||||
|
let w78 = lsig512_1!(w76) + w71 + lsig512_0!(w63) + w62;
|
||||||
|
let w79 = lsig512_1!(w77) + w72 + lsig512_0!(w64) + w63;
|
||||||
|
let s01 = step512(self.state,0x428a2f98d728ae22,w00);
|
||||||
|
let s02 = step512(s01,0x7137449123ef65cd,w01);
|
||||||
|
let s03 = step512(s02,0xb5c0fbcfec4d3b2f,w02);
|
||||||
|
let s04 = step512(s03,0xe9b5dba58189dbbc,w03);
|
||||||
|
let s05 = step512(s04,0x3956c25bf348b538,w04);
|
||||||
|
let s06 = step512(s05,0x59f111f1b605d019,w05);
|
||||||
|
let s07 = step512(s06,0x923f82a4af194f9b,w06);
|
||||||
|
let s08 = step512(s07,0xab1c5ed5da6d8118,w07);
|
||||||
|
let s09 = step512(s08,0xd807aa98a3030242,w08);
|
||||||
|
let s10 = step512(s09,0x12835b0145706fbe,w09);
|
||||||
|
let s11 = step512(s10,0x243185be4ee4b28c,w10);
|
||||||
|
let s12 = step512(s11,0x550c7dc3d5ffb4e2,w11);
|
||||||
|
let s13 = step512(s12,0x72be5d74f27b896f,w12);
|
||||||
|
let s14 = step512(s13,0x80deb1fe3b1696b1,w13);
|
||||||
|
let s15 = step512(s14,0x9bdc06a725c71235,w14);
|
||||||
|
let s16 = step512(s15,0xc19bf174cf692694,w15);
|
||||||
|
let s17 = step512(s16,0xe49b69c19ef14ad2,w16);
|
||||||
|
let s18 = step512(s17,0xefbe4786384f25e3,w17);
|
||||||
|
let s19 = step512(s18,0x0fc19dc68b8cd5b5,w18);
|
||||||
|
let s20 = step512(s19,0x240ca1cc77ac9c65,w19);
|
||||||
|
let s21 = step512(s20,0x2de92c6f592b0275,w20);
|
||||||
|
let s22 = step512(s21,0x4a7484aa6ea6e483,w21);
|
||||||
|
let s23 = step512(s22,0x5cb0a9dcbd41fbd4,w22);
|
||||||
|
let s24 = step512(s23,0x76f988da831153b5,w23);
|
||||||
|
let s25 = step512(s24,0x983e5152ee66dfab,w24);
|
||||||
|
let s26 = step512(s25,0xa831c66d2db43210,w25);
|
||||||
|
let s27 = step512(s26,0xb00327c898fb213f,w26);
|
||||||
|
let s28 = step512(s27,0xbf597fc7beef0ee4,w27);
|
||||||
|
let s29 = step512(s28,0xc6e00bf33da88fc2,w28);
|
||||||
|
let s30 = step512(s29,0xd5a79147930aa725,w29);
|
||||||
|
let s31 = step512(s30,0x06ca6351e003826f,w30);
|
||||||
|
let s32 = step512(s31,0x142929670a0e6e70,w31);
|
||||||
|
let s33 = step512(s32,0x27b70a8546d22ffc,w32);
|
||||||
|
let s34 = step512(s33,0x2e1b21385c26c926,w33);
|
||||||
|
let s35 = step512(s34,0x4d2c6dfc5ac42aed,w34);
|
||||||
|
let s36 = step512(s35,0x53380d139d95b3df,w35);
|
||||||
|
let s37 = step512(s36,0x650a73548baf63de,w36);
|
||||||
|
let s38 = step512(s37,0x766a0abb3c77b2a8,w37);
|
||||||
|
let s39 = step512(s38,0x81c2c92e47edaee6,w38);
|
||||||
|
let s40 = step512(s39,0x92722c851482353b,w39);
|
||||||
|
let s41 = step512(s40,0xa2bfe8a14cf10364,w40);
|
||||||
|
let s42 = step512(s41,0xa81a664bbc423001,w41);
|
||||||
|
let s43 = step512(s42,0xc24b8b70d0f89791,w42);
|
||||||
|
let s44 = step512(s43,0xc76c51a30654be30,w43);
|
||||||
|
let s45 = step512(s44,0xd192e819d6ef5218,w44);
|
||||||
|
let s46 = step512(s45,0xd69906245565a910,w45);
|
||||||
|
let s47 = step512(s46,0xf40e35855771202a,w46);
|
||||||
|
let s48 = step512(s47,0x106aa07032bbd1b8,w47);
|
||||||
|
let s49 = step512(s48,0x19a4c116b8d2d0c8,w48);
|
||||||
|
let s50 = step512(s49,0x1e376c085141ab53,w49);
|
||||||
|
let s51 = step512(s50,0x2748774cdf8eeb99,w50);
|
||||||
|
let s52 = step512(s51,0x34b0bcb5e19b48a8,w51);
|
||||||
|
let s53 = step512(s52,0x391c0cb3c5c95a63,w52);
|
||||||
|
let s54 = step512(s53,0x4ed8aa4ae3418acb,w53);
|
||||||
|
let s55 = step512(s54,0x5b9cca4f7763e373,w54);
|
||||||
|
let s56 = step512(s55,0x682e6ff3d6b2b8a3,w55);
|
||||||
|
let s57 = step512(s56,0x748f82ee5defb2fc,w56);
|
||||||
|
let s58 = step512(s57,0x78a5636f43172f60,w57);
|
||||||
|
let s59 = step512(s58,0x84c87814a1f0ab72,w58);
|
||||||
|
let s60 = step512(s59,0x8cc702081a6439ec,w59);
|
||||||
|
let s61 = step512(s60,0x90befffa23631e28,w60);
|
||||||
|
let s62 = step512(s61,0xa4506cebde82bde9,w61);
|
||||||
|
let s63 = step512(s62,0xbef9a3f7b2c67915,w62);
|
||||||
|
let s64 = step512(s63,0xc67178f2e372532b,w63);
|
||||||
|
let s65 = step512(s64,0xca273eceea26619c,w64);
|
||||||
|
let s66 = step512(s65,0xd186b8c721c0c207,w65);
|
||||||
|
let s67 = step512(s66,0xeada7dd6cde0eb1e,w66);
|
||||||
|
let s68 = step512(s67,0xf57d4f7fee6ed178,w67);
|
||||||
|
let s69 = step512(s68,0x06f067aa72176fba,w68);
|
||||||
|
let s70 = step512(s69,0x0a637dc5a2c898a6,w69);
|
||||||
|
let s71 = step512(s70,0x113f9804bef90dae,w70);
|
||||||
|
let s72 = step512(s71,0x1b710b35131c471b,w71);
|
||||||
|
let s73 = step512(s72,0x28db77f523047d84,w72);
|
||||||
|
let s74 = step512(s73,0x32caab7b40c72493,w73);
|
||||||
|
let s75 = step512(s74,0x3c9ebe0a15c9bebc,w74);
|
||||||
|
let s76 = step512(s75,0x431d67c49c100d4c,w75);
|
||||||
|
let s77 = step512(s76,0x4cc5d4becb3e42b6,w76);
|
||||||
|
let s78 = step512(s77,0x597f299cfc657e2a,w77);
|
||||||
|
let s79 = step512(s78,0x5fcb6fab3ad6faec,w78);
|
||||||
|
let s80 = step512(s79,0x6c44198c4a475817,w79);
|
||||||
|
self.state[0] += s80[0];
|
||||||
|
self.state[1] += s80[1];
|
||||||
|
self.state[2] += s80[2];
|
||||||
|
self.state[3] += s80[3];
|
||||||
|
self.state[4] += s80[4];
|
||||||
|
self.state[5] += s80[5];
|
||||||
|
self.state[6] += s80[6];
|
||||||
|
self.state[7] += s80[7];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, block: &[u8]) {
|
||||||
|
if !self.done {
|
||||||
|
let mut offset = 0;
|
||||||
|
|
||||||
|
self.l += block.len();
|
||||||
|
|
||||||
|
if self.buffer.len() + block.len() < 128 {
|
||||||
|
self.buffer.extend_from_slice(block);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.buffer.len() > 0 {
|
||||||
|
// We must be able to build up a 128 byte chunk, at this point, otherwise
|
||||||
|
// the math above would've been wrong.
|
||||||
|
while self.buffer.len() < 128 {
|
||||||
|
self.buffer.push(block[offset]);
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
process_u64_block!(self.buffer, 0, self);
|
||||||
|
// Reset the buffer now, we're done with that nonsense for the moment
|
||||||
|
self.buffer.resize(0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (offset + 128) <= block.len() {
|
||||||
|
process_u64_block!(block, offset, self);
|
||||||
|
offset += 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
if offset < block.len() {
|
||||||
|
self.buffer.extend_from_slice(&block[offset..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish(&mut self) {
|
||||||
|
let bitlen = self.l * 8;
|
||||||
|
let k = calculate_k(896, 1024, bitlen);
|
||||||
|
// INVARIANT: k is necessarily > 0, and (k + 1) is a multiple of 8
|
||||||
|
let bytes_to_add = (k + 1) / 8;
|
||||||
|
let mut padvec = Vec::with_capacity(bytes_to_add + 16);
|
||||||
|
padvec.push(0x80); // Set the high bit, since the first bit after the data
|
||||||
|
// should be set
|
||||||
|
padvec.resize(bytes_to_add, 0);
|
||||||
|
padvec.write_u128::<BigEndian>(bitlen as u128).expect("Broken writing value to pre-allocated Vec?");
|
||||||
|
self.update(&padvec);
|
||||||
|
self.done = true;
|
||||||
|
assert_eq!(self.buffer.len(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn step512(state0: [u64; 8], k: u64, w: u64) -> [u64; 8]
|
||||||
|
{
|
||||||
|
let [a,b,c,d,e,f,g,h] = state0;
|
||||||
|
let t1 = h + bsig512_1!(e) + ch!(e,f,g) + k + w;
|
||||||
|
let t2 = bsig512_0!(a) + maj!(a,b,c);
|
||||||
|
let hp = g;
|
||||||
|
let gp = f;
|
||||||
|
let fp = e;
|
||||||
|
let ep = d + t1;
|
||||||
|
let dp = c;
|
||||||
|
let cp = b;
|
||||||
|
let bp = a;
|
||||||
|
let ap = t1 + t2;
|
||||||
|
[ap,bp,cp,dp,ep,fp,gp,hp]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use testing::run_test;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn nist_sha224() {
|
||||||
|
let fname = "testdata/sha/nist_sha224.test";
|
||||||
|
run_test(fname.to_string(), 3, |case| {
|
||||||
|
let (negl, lbytes) = case.get("l").unwrap();
|
||||||
|
let (negm, mbytes) = case.get("m").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
|
||||||
|
assert!(!negl && !negm && !negd);
|
||||||
|
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||||
|
let digest = SHA224::hash(&msg);
|
||||||
|
assert_eq!(dbytes, &digest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn nist_sha256() {
|
||||||
|
let fname = "testdata/sha/nist_sha256.test";
|
||||||
|
run_test(fname.to_string(), 3, |case| {
|
||||||
|
let (negl, lbytes) = case.get("l").unwrap();
|
||||||
|
let (negm, mbytes) = case.get("m").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
|
||||||
|
assert!(!negl && !negm && !negd);
|
||||||
|
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||||
|
let digest = SHA256::hash(&msg);
|
||||||
|
assert_eq!(dbytes, &digest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn nist_sha384() {
|
||||||
|
let fname = "testdata/sha/nist_sha384.test";
|
||||||
|
run_test(fname.to_string(), 3, |case| {
|
||||||
|
let (negl, lbytes) = case.get("l").unwrap();
|
||||||
|
let (negm, mbytes) = case.get("m").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
|
||||||
|
assert!(!negl && !negm && !negd);
|
||||||
|
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||||
|
let digest = SHA384::hash(&msg);
|
||||||
|
assert_eq!(dbytes, &digest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn nist_sha512() {
|
||||||
|
let fname = "testdata/sha/nist_sha512.test";
|
||||||
|
run_test(fname.to_string(), 3, |case| {
|
||||||
|
let (negl, lbytes) = case.get("l").unwrap();
|
||||||
|
let (negm, mbytes) = case.get("m").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
|
||||||
|
assert!(!negl && !negm && !negd);
|
||||||
|
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||||
|
let digest = SHA512::hash(&msg);
|
||||||
|
assert_eq!(dbytes, &digest);
|
||||||
|
});
|
||||||
|
}
|
||||||
610
src/sha/sha3.rs
Normal file
610
src/sha/sha3.rs
Normal file
@@ -0,0 +1,610 @@
|
|||||||
|
use super::super::Hash;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct Keccak {
|
||||||
|
rate_in_bytes: usize,
|
||||||
|
rate_in_longs: usize,
|
||||||
|
buffer: Vec<u8>,
|
||||||
|
state: [u64; 25], // This is Keccak-f[1600]
|
||||||
|
output: Option<Vec<u8>>
|
||||||
|
}
|
||||||
|
|
||||||
|
const KECCAK_ROUND_CONSTANTS: [u64; 24] =
|
||||||
|
[ 0x0000000000000001u64, 0x0000000000008082u64,
|
||||||
|
0x800000000000808au64, 0x8000000080008000u64,
|
||||||
|
0x000000000000808bu64, 0x0000000080000001u64,
|
||||||
|
0x8000000080008081u64, 0x8000000000008009u64,
|
||||||
|
0x000000000000008au64, 0x0000000000000088u64,
|
||||||
|
0x0000000080008009u64, 0x000000008000000au64,
|
||||||
|
0x000000008000808bu64, 0x800000000000008bu64,
|
||||||
|
0x8000000000008089u64, 0x8000000000008003u64,
|
||||||
|
0x8000000000008002u64, 0x8000000000000080u64,
|
||||||
|
0x000000000000800au64, 0x800000008000000au64,
|
||||||
|
0x8000000080008081u64, 0x8000000000008080u64,
|
||||||
|
0x0000000080000001u64, 0x8000000080008008u64,
|
||||||
|
];
|
||||||
|
|
||||||
|
macro_rules! absorb {
|
||||||
|
($self: ident, $block: expr, $sidx: expr) => {{
|
||||||
|
let mut i = 0;
|
||||||
|
let mut off = 0;
|
||||||
|
|
||||||
|
while i < $self.rate_in_longs {
|
||||||
|
let word = ($block[$sidx+off+0] as u64) << 00 |
|
||||||
|
($block[$sidx+off+1] as u64) << 08 |
|
||||||
|
($block[$sidx+off+2] as u64) << 16 |
|
||||||
|
($block[$sidx+off+3] as u64) << 24 |
|
||||||
|
($block[$sidx+off+4] as u64) << 32 |
|
||||||
|
($block[$sidx+off+5] as u64) << 40 |
|
||||||
|
($block[$sidx+off+6] as u64) << 48 |
|
||||||
|
($block[$sidx+off+7] as u64) << 56;
|
||||||
|
$self.state[i] ^= word;
|
||||||
|
off += 8;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$self.permute();
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Keccak {
|
||||||
|
pub fn new(rate: usize) -> Self
|
||||||
|
{
|
||||||
|
assert_eq!(rate % 64, 0);
|
||||||
|
Keccak {
|
||||||
|
rate_in_bytes: rate / 8,
|
||||||
|
rate_in_longs: rate / 64,
|
||||||
|
buffer: Vec::with_capacity(rate),
|
||||||
|
state: [0; 25],
|
||||||
|
output: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn permute(&mut self)
|
||||||
|
{
|
||||||
|
// This is a translation of the very easy-to-read implementation in BouncyCastle
|
||||||
|
for i in 0..24 {
|
||||||
|
// Theta!
|
||||||
|
let c0 = self.state[0] ^ self.state[5] ^ self.state[10] ^ self.state[15] ^ self.state[20];
|
||||||
|
let c1 = self.state[1] ^ self.state[6] ^ self.state[11] ^ self.state[16] ^ self.state[21];
|
||||||
|
let c2 = self.state[2] ^ self.state[7] ^ self.state[12] ^ self.state[17] ^ self.state[22];
|
||||||
|
let c3 = self.state[3] ^ self.state[8] ^ self.state[13] ^ self.state[18] ^ self.state[23];
|
||||||
|
let c4 = self.state[4] ^ self.state[9] ^ self.state[14] ^ self.state[19] ^ self.state[24];
|
||||||
|
let d0 = c0.rotate_left(1) ^ c3;
|
||||||
|
let d1 = c1.rotate_left(1) ^ c4;
|
||||||
|
let d2 = c2.rotate_left(1) ^ c0;
|
||||||
|
let d3 = c3.rotate_left(1) ^ c1;
|
||||||
|
let d4 = c4.rotate_left(1) ^ c2;
|
||||||
|
self.state[0] ^= d1; self.state[5] ^= d1; self.state[10] ^= d1; self.state[15] ^= d1; self.state[20] ^= d1;
|
||||||
|
self.state[1] ^= d2; self.state[6] ^= d2; self.state[11] ^= d2; self.state[16] ^= d2; self.state[21] ^= d2;
|
||||||
|
self.state[2] ^= d3; self.state[7] ^= d3; self.state[12] ^= d3; self.state[17] ^= d3; self.state[22] ^= d3;
|
||||||
|
self.state[3] ^= d4; self.state[8] ^= d4; self.state[13] ^= d4; self.state[18] ^= d4; self.state[23] ^= d4;
|
||||||
|
self.state[4] ^= d0; self.state[9] ^= d0; self.state[14] ^= d0; self.state[19] ^= d0; self.state[24] ^= d0;
|
||||||
|
// Rho & Pi!
|
||||||
|
let t1 = self.state[01].rotate_left(1);
|
||||||
|
self.state[01] = self.state[06].rotate_left(44);
|
||||||
|
self.state[06] = self.state[09].rotate_left(20);
|
||||||
|
self.state[09] = self.state[22].rotate_left(61);
|
||||||
|
self.state[22] = self.state[14].rotate_left(39);
|
||||||
|
self.state[14] = self.state[20].rotate_left(18);
|
||||||
|
self.state[20] = self.state[02].rotate_left(62);
|
||||||
|
self.state[02] = self.state[12].rotate_left(43);
|
||||||
|
self.state[12] = self.state[13].rotate_left(25);
|
||||||
|
self.state[13] = self.state[19].rotate_left(8);
|
||||||
|
self.state[19] = self.state[23].rotate_left(56);
|
||||||
|
self.state[23] = self.state[15].rotate_left(41);
|
||||||
|
self.state[15] = self.state[04].rotate_left(27);
|
||||||
|
self.state[04] = self.state[24].rotate_left(14);
|
||||||
|
self.state[24] = self.state[21].rotate_left(2);
|
||||||
|
self.state[21] = self.state[08].rotate_left(55);
|
||||||
|
self.state[08] = self.state[16].rotate_left(45);
|
||||||
|
self.state[16] = self.state[05].rotate_left(36);
|
||||||
|
self.state[05] = self.state[03].rotate_left(28);
|
||||||
|
self.state[03] = self.state[18].rotate_left(21);
|
||||||
|
self.state[18] = self.state[17].rotate_left(15);
|
||||||
|
self.state[17] = self.state[11].rotate_left(10);
|
||||||
|
self.state[11] = self.state[07].rotate_left(6);
|
||||||
|
self.state[07] = self.state[10].rotate_left(3);
|
||||||
|
self.state[10] = t1;
|
||||||
|
// Chi!
|
||||||
|
let t2 = self.state[00] ^ (!self.state[01] & self.state[02]);
|
||||||
|
let t3 = self.state[01] ^ (!self.state[02] & self.state[03]);
|
||||||
|
self.state[02] ^= !self.state[03] & self.state[04];
|
||||||
|
self.state[03] ^= !self.state[04] & self.state[00];
|
||||||
|
self.state[04] ^= !self.state[00] & self.state[01];
|
||||||
|
self.state[00] = t2;
|
||||||
|
self.state[01] = t3;
|
||||||
|
|
||||||
|
let t4 = self.state[05] ^ (!self.state[06] & self.state[07]);
|
||||||
|
let t5 = self.state[06] ^ (!self.state[07] & self.state[08]);
|
||||||
|
self.state[07] ^= !self.state[08] & self.state[09];
|
||||||
|
self.state[08] ^= !self.state[09] & self.state[05];
|
||||||
|
self.state[09] ^= !self.state[05] & self.state[06];
|
||||||
|
self.state[05] = t4;
|
||||||
|
self.state[06] = t5;
|
||||||
|
|
||||||
|
let t6 = self.state[10] ^ (!self.state[11] & self.state[12]);
|
||||||
|
let t7 = self.state[11] ^ (!self.state[12] & self.state[13]);
|
||||||
|
self.state[12] ^= !self.state[13] & self.state[14];
|
||||||
|
self.state[13] ^= !self.state[14] & self.state[10];
|
||||||
|
self.state[14] ^= !self.state[10] & self.state[11];
|
||||||
|
self.state[10] = t6;
|
||||||
|
self.state[11] = t7;
|
||||||
|
|
||||||
|
let t8 = self.state[15] ^ (!self.state[16] & self.state[17]);
|
||||||
|
let t9 = self.state[16] ^ (!self.state[17] & self.state[18]);
|
||||||
|
self.state[17] ^= !self.state[18] & self.state[19];
|
||||||
|
self.state[18] ^= !self.state[19] & self.state[15];
|
||||||
|
self.state[19] ^= !self.state[15] & self.state[16];
|
||||||
|
self.state[15] = t8;
|
||||||
|
self.state[16] = t9;
|
||||||
|
|
||||||
|
let ta = self.state[20] ^ (!self.state[21] & self.state[22]);
|
||||||
|
let tb = self.state[21] ^ (!self.state[22] & self.state[23]);
|
||||||
|
self.state[22] ^= !self.state[23] & self.state[24];
|
||||||
|
self.state[23] ^= !self.state[24] & self.state[20];
|
||||||
|
self.state[24] ^= !self.state[20] & self.state[21];
|
||||||
|
self.state[20] = ta;
|
||||||
|
self.state[21] = tb;
|
||||||
|
|
||||||
|
// iota
|
||||||
|
self.state[00] ^= KECCAK_ROUND_CONSTANTS[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process(&mut self, bytes: &[u8])
|
||||||
|
{
|
||||||
|
if self.output.is_none() {
|
||||||
|
let mut offset = 0;
|
||||||
|
|
||||||
|
if self.buffer.len() + bytes.len() < self.rate_in_bytes {
|
||||||
|
self.buffer.extend_from_slice(bytes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.buffer.len() > 0 {
|
||||||
|
// We must be able to build up a chunk at our absorbtion rate, at this
|
||||||
|
// point, otherwise the math above would've been wrong.
|
||||||
|
while self.buffer.len() < self.rate_in_bytes {
|
||||||
|
self.buffer.push(bytes[offset]);
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
absorb!(self, self.buffer, 0);
|
||||||
|
// Reset the buffer now, we're done with that nonsense for the moment
|
||||||
|
self.buffer.resize(0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (offset + self.rate_in_bytes) <= bytes.len() {
|
||||||
|
absorb!(self, bytes, offset);
|
||||||
|
offset += self.rate_in_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if offset < bytes.len() {
|
||||||
|
self.buffer.extend_from_slice(&bytes[offset..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tag_and_pad(&mut self, tag_byte: u8)
|
||||||
|
{
|
||||||
|
if self.output.is_none() {
|
||||||
|
assert!(self.buffer.len() < self.rate_in_bytes);
|
||||||
|
// what we need to do here is tag on a final 01, to tag that as SHA3,
|
||||||
|
// and then pad it out, with an 0x80 at the end.
|
||||||
|
self.buffer.push(tag_byte);
|
||||||
|
self.buffer.resize(self.rate_in_bytes, 0);
|
||||||
|
self.buffer[self.rate_in_bytes-1] |= 0x80;
|
||||||
|
absorb!(self, self.buffer, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn squeeze(&mut self, output_len: usize) -> Vec<u8>
|
||||||
|
{
|
||||||
|
if let Some(ref result) = self.output {
|
||||||
|
result.clone()
|
||||||
|
} else {
|
||||||
|
let mut res = Vec::new();
|
||||||
|
|
||||||
|
while res.len() < output_len {
|
||||||
|
for i in 0..self.rate_in_longs {
|
||||||
|
res.push( (self.state[i] >> 00) as u8 );
|
||||||
|
res.push( (self.state[i] >> 08) as u8 );
|
||||||
|
res.push( (self.state[i] >> 16) as u8 );
|
||||||
|
res.push( (self.state[i] >> 24) as u8 );
|
||||||
|
res.push( (self.state[i] >> 32) as u8 );
|
||||||
|
res.push( (self.state[i] >> 40) as u8 );
|
||||||
|
res.push( (self.state[i] >> 48) as u8 );
|
||||||
|
res.push( (self.state[i] >> 56) as u8 );
|
||||||
|
}
|
||||||
|
self.permute();
|
||||||
|
}
|
||||||
|
|
||||||
|
res.resize(output_len, 0);
|
||||||
|
self.output = Some(res.clone());
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The SHA3-224 hash.
|
||||||
|
///
|
||||||
|
/// To use, you can run it in incremental mode -- by calling new(),
|
||||||
|
/// update() zero or more times, and then finalize() -- or you can
|
||||||
|
/// just invoke the hash directly. For example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use simple_crypto::sha::{Hash,SHA3_224};
|
||||||
|
///
|
||||||
|
/// let empty = [0; 0];
|
||||||
|
/// // Do the hash using the incremental API
|
||||||
|
/// let mut hashf = SHA3_224::new();
|
||||||
|
/// hashf.update(&empty);
|
||||||
|
/// let result_incremental = hashf.finalize();
|
||||||
|
/// // Do the hash using the direct API
|
||||||
|
/// let result_direct = SHA3_224::hash(&empty);
|
||||||
|
/// // ... and they should be the same
|
||||||
|
/// assert_eq!(result_incremental,result_direct);
|
||||||
|
/// ```
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SHA3_224 {
|
||||||
|
state: Keccak
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for SHA3_224 {
|
||||||
|
fn new() -> Self
|
||||||
|
{
|
||||||
|
SHA3_224{ state: Keccak::new(1600 - 448) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, buffer: &[u8])
|
||||||
|
{
|
||||||
|
self.state.process(&buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
self.state.tag_and_pad(0x06);
|
||||||
|
self.state.squeeze(224 / 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_size() -> usize
|
||||||
|
{
|
||||||
|
1152
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod sha224 {
|
||||||
|
use super::*;
|
||||||
|
use testing::run_test;
|
||||||
|
|
||||||
|
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-224_Msg0.pdf
|
||||||
|
#[test]
|
||||||
|
fn nist_empty_example() {
|
||||||
|
let empty = [0; 0];
|
||||||
|
let hashres = [0x6B,0x4E,0x03,0x42,0x36,0x67,0xDB,0xB7,0x3B,0x6E,0x15,
|
||||||
|
0x45,0x4F,0x0E,0xB1,0xAB,0xD4,0x59,0x7F,0x9A,0x1B,0x07,
|
||||||
|
0x8E,0x3F,0x5B,0x5A,0x6B,0xC7];
|
||||||
|
let mine = SHA3_224::hash(&empty);
|
||||||
|
assert_eq!(hashres.to_vec(), mine);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-224_1600.pdf
|
||||||
|
#[test]
|
||||||
|
fn nist_1600_example() {
|
||||||
|
let example = [0xA3; 200];
|
||||||
|
let hashres = [0x93,0x76,0x81,0x6A,0xBA,0x50,0x3F,0x72,
|
||||||
|
0xF9,0x6C,0xE7,0xEB,0x65,0xAC,0x09,0x5D,
|
||||||
|
0xEE,0xE3,0xBE,0x4B,0xF9,0xBB,0xC2,0xA1,
|
||||||
|
0xCB,0x7E,0x11,0xE0];
|
||||||
|
let mine = SHA3_224::hash(&example);
|
||||||
|
assert_eq!(hashres.to_vec(), mine);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn nist_test_vectors() {
|
||||||
|
let fname = "testdata/sha/nist_sha3_224.test";
|
||||||
|
run_test(fname.to_string(), 3, |case| {
|
||||||
|
let (negl, lbytes) = case.get("l").unwrap();
|
||||||
|
let (negm, mbytes) = case.get("m").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
|
||||||
|
assert!(!negl && !negm && !negd);
|
||||||
|
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||||
|
let digest = SHA3_224::hash(&msg);
|
||||||
|
assert_eq!(dbytes, &digest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The SHA3-256 hash. [GOOD]
|
||||||
|
///
|
||||||
|
/// To use, you can run it in incremental mode -- by calling new(),
|
||||||
|
/// update() zero or more times, and then finalize() -- or you can
|
||||||
|
/// just invoke the hash directly. For example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use simple_crypto::sha::{Hash,SHA3_256};
|
||||||
|
///
|
||||||
|
/// let empty = [0; 0];
|
||||||
|
/// // Do the hash using the incremental API
|
||||||
|
/// let mut hashf = SHA3_256::new();
|
||||||
|
/// hashf.update(&empty);
|
||||||
|
/// let result_incremental = hashf.finalize();
|
||||||
|
/// // Do the hash using the direct API
|
||||||
|
/// let result_direct = SHA3_256::hash(&empty);
|
||||||
|
/// // ... and they should be the same
|
||||||
|
/// assert_eq!(result_incremental,result_direct);
|
||||||
|
/// ```
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SHA3_256 {
|
||||||
|
state: Keccak
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for SHA3_256 {
|
||||||
|
fn new() -> Self
|
||||||
|
{
|
||||||
|
SHA3_256{ state: Keccak::new(1600 - 512) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, buffer: &[u8])
|
||||||
|
{
|
||||||
|
self.state.process(&buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
self.state.tag_and_pad(0x06);
|
||||||
|
self.state.squeeze(256 / 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_size() -> usize
|
||||||
|
{
|
||||||
|
1088
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod sha256 {
|
||||||
|
use super::*;
|
||||||
|
use testing::run_test;
|
||||||
|
|
||||||
|
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-256.pdf
|
||||||
|
#[test]
|
||||||
|
fn nist_empty_example() {
|
||||||
|
let empty = [0; 0];
|
||||||
|
let hashres = [0xA7,0xFF,0xC6,0xF8,0xBF,0x1E,0xD7,0x66,
|
||||||
|
0x51,0xC1,0x47,0x56,0xA0,0x61,0xD6,0x62,
|
||||||
|
0xF5,0x80,0xFF,0x4D,0xE4,0x3B,0x49,0xFA,
|
||||||
|
0x82,0xD8,0x0A,0x4B,0x80,0xF8,0x43,0x4A];
|
||||||
|
let mine = SHA3_256::hash(&empty);
|
||||||
|
assert_eq!(hashres.to_vec(), mine);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-256_1600.pdf
|
||||||
|
#[test]
|
||||||
|
fn nist_1600_example() {
|
||||||
|
let example = [0xA3; 200];
|
||||||
|
let hashres = [0x79,0xF3,0x8A,0xDE,0xC5,0xC2,0x03,0x07,
|
||||||
|
0xA9,0x8E,0xF7,0x6E,0x83,0x24,0xAF,0xBF,
|
||||||
|
0xD4,0x6C,0xFD,0x81,0xB2,0x2E,0x39,0x73,
|
||||||
|
0xC6,0x5F,0xA1,0xBD,0x9D,0xE3,0x17,0x87];
|
||||||
|
let mine = SHA3_256::hash(&example);
|
||||||
|
assert_eq!(hashres.to_vec(), mine);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn nist_test_vectors() {
|
||||||
|
let fname = "testdata/sha/nist_sha3_256.test";
|
||||||
|
run_test(fname.to_string(), 3, |case| {
|
||||||
|
let (negl, lbytes) = case.get("l").unwrap();
|
||||||
|
let (negm, mbytes) = case.get("m").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
|
||||||
|
assert!(!negl && !negm && !negd);
|
||||||
|
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||||
|
let digest = SHA3_256::hash(&msg);
|
||||||
|
assert_eq!(dbytes, &digest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The SHA3-384 hash. [BETTER]
|
||||||
|
///
|
||||||
|
/// To use, you can run it in incremental mode -- by calling new(),
|
||||||
|
/// update() zero or more times, and then finalize() -- or you can
|
||||||
|
/// just invoke the hash directly. For example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use simple_crypto::sha::{Hash,SHA3_384};
|
||||||
|
///
|
||||||
|
/// let empty = [0; 0];
|
||||||
|
/// // Do the hash using the incremental API
|
||||||
|
/// let mut hashf = SHA3_384::new();
|
||||||
|
/// hashf.update(&empty);
|
||||||
|
/// let result_incremental = hashf.finalize();
|
||||||
|
/// // Do the hash using the direct API
|
||||||
|
/// let result_direct = SHA3_384::hash(&empty);
|
||||||
|
/// // ... and they should be the same
|
||||||
|
/// assert_eq!(result_incremental,result_direct);
|
||||||
|
/// ```
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SHA3_384 {
|
||||||
|
state: Keccak
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for SHA3_384 {
|
||||||
|
fn new() -> Self
|
||||||
|
{
|
||||||
|
SHA3_384{ state: Keccak::new(1600 - 768) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, buffer: &[u8])
|
||||||
|
{
|
||||||
|
self.state.process(&buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
self.state.tag_and_pad(0x06);
|
||||||
|
self.state.squeeze(384 / 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_size() -> usize
|
||||||
|
{
|
||||||
|
832
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod sha384 {
|
||||||
|
use super::*;
|
||||||
|
use testing::run_test;
|
||||||
|
|
||||||
|
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-384_Msg0.pdf
|
||||||
|
#[test]
|
||||||
|
fn nist_empty_example() {
|
||||||
|
let empty = [0; 0];
|
||||||
|
let hashres = [0x0C,0x63,0xA7,0x5B,0x84,0x5E,0x4F,0x7D,
|
||||||
|
0x01,0x10,0x7D,0x85,0x2E,0x4C,0x24,0x85,
|
||||||
|
0xC5,0x1A,0x50,0xAA,0xAA,0x94,0xFC,0x61,
|
||||||
|
0x99,0x5E,0x71,0xBB,0xEE,0x98,0x3A,0x2A,
|
||||||
|
0xC3,0x71,0x38,0x31,0x26,0x4A,0xDB,0x47,
|
||||||
|
0xFB,0x6B,0xD1,0xE0,0x58,0xD5,0xF0,0x04];
|
||||||
|
let mine = SHA3_384::hash(&empty);
|
||||||
|
assert_eq!(hashres.to_vec(), mine);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-384_1600.pdf
|
||||||
|
#[test]
|
||||||
|
fn nist_1600_example() {
|
||||||
|
let example = [0xA3; 200];
|
||||||
|
let hashres = [0x18,0x81,0xDE,0x2C,0xA7,0xE4,0x1E,0xF9,
|
||||||
|
0x5D,0xC4,0x73,0x2B,0x8F,0x5F,0x00,0x2B,
|
||||||
|
0x18,0x9C,0xC1,0xE4,0x2B,0x74,0x16,0x8E,
|
||||||
|
0xD1,0x73,0x26,0x49,0xCE,0x1D,0xBC,0xDD,
|
||||||
|
0x76,0x19,0x7A,0x31,0xFD,0x55,0xEE,0x98,
|
||||||
|
0x9F,0x2D,0x70,0x50,0xDD,0x47,0x3E,0x8F];
|
||||||
|
let mine = SHA3_384::hash(&example);
|
||||||
|
assert_eq!(hashres.to_vec(), mine);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn nist_test_vectors() {
|
||||||
|
let fname = "testdata/sha/nist_sha3_384.test";
|
||||||
|
run_test(fname.to_string(), 3, |case| {
|
||||||
|
let (negl, lbytes) = case.get("l").unwrap();
|
||||||
|
let (negm, mbytes) = case.get("m").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
|
||||||
|
assert!(!negl && !negm && !negd);
|
||||||
|
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||||
|
let digest = SHA3_384::hash(&msg);
|
||||||
|
assert_eq!(dbytes, &digest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The SHA3-512 hash. [BEST]
|
||||||
|
///
|
||||||
|
/// To use, you can run it in incremental mode -- by calling new(),
|
||||||
|
/// update() zero or more times, and then finalize() -- or you can
|
||||||
|
/// just invoke the hash directly. For example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use simple_crypto::sha::{Hash,SHA3_512};
|
||||||
|
///
|
||||||
|
/// let empty = [0; 0];
|
||||||
|
/// // Do the hash using the incremental API
|
||||||
|
/// let mut hashf = SHA3_512::new();
|
||||||
|
/// hashf.update(&empty);
|
||||||
|
/// let result_incremental = hashf.finalize();
|
||||||
|
/// // Do the hash using the direct API
|
||||||
|
/// let result_direct = SHA3_512::hash(&empty);
|
||||||
|
/// // ... and they should be the same
|
||||||
|
/// assert_eq!(result_incremental,result_direct);
|
||||||
|
/// ```
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SHA3_512 {
|
||||||
|
state: Keccak
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for SHA3_512 {
|
||||||
|
fn new() -> Self
|
||||||
|
{
|
||||||
|
SHA3_512{ state: Keccak::new(1600 - 1024) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, buffer: &[u8])
|
||||||
|
{
|
||||||
|
self.state.process(&buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
self.state.tag_and_pad(0x06);
|
||||||
|
self.state.squeeze(512 / 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_size() -> usize
|
||||||
|
{
|
||||||
|
576
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod sha512 {
|
||||||
|
use super::*;
|
||||||
|
use testing::run_test;
|
||||||
|
|
||||||
|
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-512_Msg0.pdf
|
||||||
|
#[test]
|
||||||
|
fn nist_empty_example() {
|
||||||
|
let empty = [0; 0];
|
||||||
|
let hashres = [0xA6,0x9F,0x73,0xCC,0xA2,0x3A,0x9A,0xC5,
|
||||||
|
0xC8,0xB5,0x67,0xDC,0x18,0x5A,0x75,0x6E,
|
||||||
|
0x97,0xC9,0x82,0x16,0x4F,0xE2,0x58,0x59,
|
||||||
|
0xE0,0xD1,0xDC,0xC1,0x47,0x5C,0x80,0xA6,
|
||||||
|
0x15,0xB2,0x12,0x3A,0xF1,0xF5,0xF9,0x4C,
|
||||||
|
0x11,0xE3,0xE9,0x40,0x2C,0x3A,0xC5,0x58,
|
||||||
|
0xF5,0x00,0x19,0x9D,0x95,0xB6,0xD3,0xE3,
|
||||||
|
0x01,0x75,0x85,0x86,0x28,0x1D,0xCD,0x26];
|
||||||
|
let mine = SHA3_512::hash(&empty);
|
||||||
|
assert_eq!(hashres.to_vec(), mine);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-512_1600.pdf
|
||||||
|
#[test]
|
||||||
|
fn nist_1600_example() {
|
||||||
|
let example = [0xA3; 200];
|
||||||
|
let hashres = [0xE7,0x6D,0xFA,0xD2,0x20,0x84,0xA8,0xB1,
|
||||||
|
0x46,0x7F,0xCF,0x2F,0xFA,0x58,0x36,0x1B,
|
||||||
|
0xEC,0x76,0x28,0xED,0xF5,0xF3,0xFD,0xC0,
|
||||||
|
0xE4,0x80,0x5D,0xC4,0x8C,0xAE,0xEC,0xA8,
|
||||||
|
0x1B,0x7C,0x13,0xC3,0x0A,0xDF,0x52,0xA3,
|
||||||
|
0x65,0x95,0x84,0x73,0x9A,0x2D,0xF4,0x6B,
|
||||||
|
0xE5,0x89,0xC5,0x1C,0xA1,0xA4,0xA8,0x41,
|
||||||
|
0x6D,0xF6,0x54,0x5A,0x1C,0xE8,0xBA,0x00];
|
||||||
|
let mine = SHA3_512::hash(&example);
|
||||||
|
assert_eq!(hashres.to_vec(), mine);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn nist_test_vectors() {
|
||||||
|
let fname = "testdata/sha/nist_sha3_512.test";
|
||||||
|
run_test(fname.to_string(), 3, |case| {
|
||||||
|
let (negl, lbytes) = case.get("l").unwrap();
|
||||||
|
let (negm, mbytes) = case.get("m").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
|
||||||
|
assert!(!negl && !negm && !negd);
|
||||||
|
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||||
|
let digest = SHA3_512::hash(&msg);
|
||||||
|
assert_eq!(dbytes, &digest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
101
src/sha/shared.rs
Normal file
101
src/sha/shared.rs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
macro_rules! ch {
|
||||||
|
($x: expr, $y: expr, $z: expr) => {{
|
||||||
|
let xval = $x;
|
||||||
|
(xval & $y) ^ (!xval & $z)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! parity {
|
||||||
|
($x: expr, $y: expr, $z: expr) => {
|
||||||
|
$x ^ $y ^ $z
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! maj {
|
||||||
|
($x: expr, $y: expr, $z: expr) => {{
|
||||||
|
/* the original function is (x & y) ^ (x & z) ^ (y & z).
|
||||||
|
if you fire off truth tables, this is equivalent to
|
||||||
|
(x & y) | (x & z) | (y & z)
|
||||||
|
which you can then use distribution on:
|
||||||
|
(x & (y | z)) | (y & z)
|
||||||
|
which saves one operation */
|
||||||
|
let yval = $y;
|
||||||
|
let zval = $z;
|
||||||
|
($x & (yval | zval)) | (yval & zval)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! process_u32_block {
|
||||||
|
($buf: expr, $off: expr, $self: ident) => {{
|
||||||
|
let w00 = ($buf[$off+0] as u32) << 24 | ($buf[$off+1] as u32) << 16 |
|
||||||
|
($buf[$off+2] as u32) << 8 | ($buf[$off+3] as u32);
|
||||||
|
let w01 = ($buf[$off+4] as u32) << 24 | ($buf[$off+5] as u32) << 16 |
|
||||||
|
($buf[$off+6] as u32) << 8 | ($buf[$off+7] as u32);
|
||||||
|
let w02 = ($buf[$off+8] as u32) << 24 | ($buf[$off+9] as u32) << 16 |
|
||||||
|
($buf[$off+10] as u32) << 8 | ($buf[$off+11] as u32);
|
||||||
|
let w03 = ($buf[$off+12] as u32) << 24 | ($buf[$off+13] as u32) << 16 |
|
||||||
|
($buf[$off+14] as u32) << 8 | ($buf[$off+15] as u32);
|
||||||
|
let w04 = ($buf[$off+16] as u32) << 24 | ($buf[$off+17] as u32) << 16 |
|
||||||
|
($buf[$off+18] as u32) << 8 | ($buf[$off+19] as u32);
|
||||||
|
let w05 = ($buf[$off+20] as u32) << 24 | ($buf[$off+21] as u32) << 16 |
|
||||||
|
($buf[$off+22] as u32) << 8 | ($buf[$off+23] as u32);
|
||||||
|
let w06 = ($buf[$off+24] as u32) << 24 | ($buf[$off+25] as u32) << 16 |
|
||||||
|
($buf[$off+26] as u32) << 8 | ($buf[$off+27] as u32);
|
||||||
|
let w07 = ($buf[$off+28] as u32) << 24 | ($buf[$off+29] as u32) << 16 |
|
||||||
|
($buf[$off+30] as u32) << 8 | ($buf[$off+31] as u32);
|
||||||
|
let w08 = ($buf[$off+32] as u32) << 24 | ($buf[$off+33] as u32) << 16 |
|
||||||
|
($buf[$off+34] as u32) << 8 | ($buf[$off+35] as u32);
|
||||||
|
let w09 = ($buf[$off+36] as u32) << 24 | ($buf[$off+37] as u32) << 16 |
|
||||||
|
($buf[$off+38] as u32) << 8 | ($buf[$off+39] as u32);
|
||||||
|
let w10 = ($buf[$off+40] as u32) << 24 | ($buf[$off+41] as u32) << 16 |
|
||||||
|
($buf[$off+42] as u32) << 8 | ($buf[$off+43] as u32);
|
||||||
|
let w11 = ($buf[$off+44] as u32) << 24 | ($buf[$off+45] as u32) << 16 |
|
||||||
|
($buf[$off+46] as u32) << 8 | ($buf[$off+47] as u32);
|
||||||
|
let w12 = ($buf[$off+48] as u32) << 24 | ($buf[$off+49] as u32) << 16 |
|
||||||
|
($buf[$off+50] as u32) << 8 | ($buf[$off+51] as u32);
|
||||||
|
let w13 = ($buf[$off+52] as u32) << 24 | ($buf[$off+53] as u32) << 16 |
|
||||||
|
($buf[$off+54] as u32) << 8 | ($buf[$off+55] as u32);
|
||||||
|
let w14 = ($buf[$off+56] as u32) << 24 | ($buf[$off+57] as u32) << 16 |
|
||||||
|
($buf[$off+58] as u32) << 8 | ($buf[$off+59] as u32);
|
||||||
|
let w15 = ($buf[$off+60] as u32) << 24 | ($buf[$off+61] as u32) << 16 |
|
||||||
|
($buf[$off+62] as u32) << 8 | ($buf[$off+63] as u32);
|
||||||
|
$self.process(w00, w01, w02, w03, w04, w05, w06, w07,
|
||||||
|
w08, w09, w10, w11, w12, w13, w14, w15);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate the value `k` used in the padding for all the hashes, solving the
|
||||||
|
// equation (l + 1 + k) mod b = a.
|
||||||
|
pub fn calculate_k(a: usize, b: usize, l: usize) -> usize
|
||||||
|
{
|
||||||
|
(a - (l + 1)) % b
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
quickcheck!
|
||||||
|
{
|
||||||
|
fn maj_rewrite_ok(x: u64, y: u64, z: u64) -> bool
|
||||||
|
{
|
||||||
|
let orig = (x & y) ^ (x & z) ^ (y & z);
|
||||||
|
maj!(x, y, z) == orig
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note, these two laws hold because we hash with bytes as the atomic size,
|
||||||
|
// not bits. If we hashed true bit streams, we'd be in trouble.
|
||||||
|
fn sha1_k_plus_1_multiple_of_8(lbytes: usize) -> bool
|
||||||
|
{
|
||||||
|
let l = lbytes * 8;
|
||||||
|
(calculate_k(448,512,l) + 1) % 8 == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note, these two laws hold because we hash with bytes as the atomic size,
|
||||||
|
// not bits. If we hashed true bit streams, we'd be in trouble.
|
||||||
|
fn sha2_k_plus_1_multiple_of_8(lbytes: usize) -> bool
|
||||||
|
{
|
||||||
|
let l = lbytes * 8;
|
||||||
|
(calculate_k(896,1024,l) + 1) % 8 == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
215
src/shake.rs
Normal file
215
src/shake.rs
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
//! This module implements the SHAKE family of variable-length hash functions,
|
||||||
|
//! which NIST also referes to as Extendable-Output Functions (XOFs). They are
|
||||||
|
//! based on the same underlying hashing mechanism used in SHA3, but can be
|
||||||
|
//! tuned to output a variety of different hash lengths. One trick is that the
|
||||||
|
//! security of the hash is the minimum of the defined bit size (128 for
|
||||||
|
//! SHAKE128, or 256 for SHAKE256) and the output hash length, so if you use
|
||||||
|
//! shorter hashes you lose some amount of collision protection.
|
||||||
|
//!
|
||||||
|
//! Because the output is variable length, these don't quite fit into the
|
||||||
|
//! normal `Hash` trait. Instead, they implement the same basic functions,
|
||||||
|
//! but with `hash` and `finalize` functions extended with an additional
|
||||||
|
//! output length function. Usage is thus in the analagous way to normal
|
||||||
|
//! hashing:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use simple_crypto::shake::SHAKE128;
|
||||||
|
//!
|
||||||
|
//! // Use SHAKE incrementally
|
||||||
|
//! let empty = [0; 0];
|
||||||
|
//! let mut shakef = SHAKE128::new();
|
||||||
|
//! shakef.update(&empty);
|
||||||
|
//! let result_inc = shakef.finalize(384);
|
||||||
|
//! // Use SHAKE directly
|
||||||
|
//! let result_dir = SHAKE128::hash(&empty, 384);
|
||||||
|
//! // ... and the answers should be the same.
|
||||||
|
//! assert_eq!(result_inc, result_dir);
|
||||||
|
//! ```
|
||||||
|
use sha::Keccak;
|
||||||
|
|
||||||
|
/// The SHAKE128 variable-length hash.
|
||||||
|
///
|
||||||
|
/// This generates a variable-length hash value, although it's not necessarily as
|
||||||
|
/// strong as a hash of the same value. My understanding (which is admittedly
|
||||||
|
/// limited; I've never seen these used) is that this is more for convenience
|
||||||
|
/// when you want to fit into particularly-sized regions. The 128 is the
|
||||||
|
/// approximate maximum bit strength of the hash in bits; the true strength is
|
||||||
|
/// the minimum of the length of the output hash and 128.
|
||||||
|
///
|
||||||
|
/// `SHAKE128` does not implement `Hash`, because it is finalized differently,
|
||||||
|
/// but we've kept something of the flavor of the `Hash` interface for
|
||||||
|
/// familiarity.
|
||||||
|
///
|
||||||
|
/// Like the SHA3 variants, this can be used incrementally or directly, as per
|
||||||
|
/// usual:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use simple_crypto::shake::SHAKE128;
|
||||||
|
///
|
||||||
|
/// // Use SHAKE incrementally
|
||||||
|
/// let empty = [0; 0];
|
||||||
|
/// let mut shakef = SHAKE128::new();
|
||||||
|
/// shakef.update(&empty);
|
||||||
|
/// let result_inc = shakef.finalize(384);
|
||||||
|
/// // Use SHAKE directly
|
||||||
|
/// let result_dir = SHAKE128::hash(&empty, 384);
|
||||||
|
/// // ... and the answers should be the same.
|
||||||
|
/// assert_eq!(result_inc, result_dir);
|
||||||
|
/// ```
|
||||||
|
pub struct SHAKE128 {
|
||||||
|
state: Keccak
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SHAKE128 {
|
||||||
|
/// Create a fresh, new SHAKE128 instance for incremental use.
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
SHAKE128{
|
||||||
|
state: Keccak::new(1600 - 256)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add more data into the hash function for processing.
|
||||||
|
pub fn update(&mut self, buffer: &[u8])
|
||||||
|
{
|
||||||
|
self.state.process(&buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate the final hash. Because this is a variable-length hash,
|
||||||
|
/// you will need to provide the output size in bits. Note that this
|
||||||
|
/// output size *must* be a multiple of 8, and that the security
|
||||||
|
/// strength of the whole hash is approximately the minimum of this
|
||||||
|
/// length and 128 bits.
|
||||||
|
pub fn finalize(&mut self, outsize: usize) -> Vec<u8>
|
||||||
|
{
|
||||||
|
assert_eq!(outsize % 8, 0);
|
||||||
|
self.state.tag_and_pad(0x1F);
|
||||||
|
self.state.squeeze(outsize / 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Directly generate the SHAKE128 hash of the given buffer, returning
|
||||||
|
/// a hash value of the given size (in bits). Presently, the output
|
||||||
|
/// size *must* be a multiple of 8, although this may change in the
|
||||||
|
/// future.
|
||||||
|
pub fn hash(buffer: &[u8], outsize: usize) -> Vec<u8>
|
||||||
|
{
|
||||||
|
let mut x = Self::new();
|
||||||
|
x.update(&buffer);
|
||||||
|
x.finalize(outsize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use testing::run_test;
|
||||||
|
#[cfg(test)]
|
||||||
|
use cryptonum::unsigned::{Decoder,U192};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn shake128() {
|
||||||
|
let fname = "testdata/sha/shake128.test";
|
||||||
|
run_test(fname.to_string(), 4, |case| {
|
||||||
|
let (negl, lbytes) = case.get("l").unwrap();
|
||||||
|
let (negm, mbytes) = case.get("m").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
let (nego, obytes) = case.get("o").unwrap();
|
||||||
|
|
||||||
|
assert!(!negl && !negm && !negd && !nego);
|
||||||
|
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||||
|
let osize = usize::from(U192::from_bytes(obytes));
|
||||||
|
let digest = SHAKE128::hash(&msg, osize);;
|
||||||
|
assert_eq!(dbytes, &digest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The SHAKE256 variable-length hash.
|
||||||
|
///
|
||||||
|
/// This generates a variable-length hash value, although it's not necessarily as
|
||||||
|
/// strong as a hash of the same value. My understanding (which is admittedly
|
||||||
|
/// limited; I've never seen these used) is that this is more for convenience
|
||||||
|
/// when you want to fit into particularly-sized regions. The 256 is the
|
||||||
|
/// approximate maximum bit strength of the hash in bits; the true strength is
|
||||||
|
/// the minimum of the length of the output hash and 256.
|
||||||
|
///
|
||||||
|
/// `SHAKE256` does not implement `Hash`, because it is finalized differently,
|
||||||
|
/// but we've kept something of the flavor of the `Hash` interface for
|
||||||
|
/// familiarity.
|
||||||
|
///
|
||||||
|
/// Like the SHA3 variants, this can be used incrementally or directly, as per
|
||||||
|
/// usual:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use simple_crypto::shake::SHAKE256;
|
||||||
|
///
|
||||||
|
/// // Use SHAKE incrementally
|
||||||
|
/// let empty = [0; 0];
|
||||||
|
/// let mut shakef = SHAKE256::new();
|
||||||
|
/// shakef.update(&empty);
|
||||||
|
/// let result_inc = shakef.finalize(384);
|
||||||
|
/// // Use SHAKE directly
|
||||||
|
/// let result_dir = SHAKE256::hash(&empty, 384);
|
||||||
|
/// // ... and the answers should be the same.
|
||||||
|
/// assert_eq!(result_inc, result_dir);
|
||||||
|
/// ```
|
||||||
|
pub struct SHAKE256 {
|
||||||
|
state: Keccak
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SHAKE256 {
|
||||||
|
/// Create a fresh, new SHAKE256 instance for incremental use.
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
SHAKE256{
|
||||||
|
state: Keccak::new(1600 - 512)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add more data into the hash function for processing.
|
||||||
|
pub fn update(&mut self, buffer: &[u8])
|
||||||
|
{
|
||||||
|
self.state.process(&buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate the final hash. Because this is a variable-length hash,
|
||||||
|
/// you will need to provide the output size in bits. Note that this
|
||||||
|
/// output size *must* be a multiple of 8, and that the security
|
||||||
|
/// strength of the whole hash is approximately the minimum of this
|
||||||
|
/// length and 256 bits.
|
||||||
|
pub fn finalize(&mut self, outsize: usize) -> Vec<u8>
|
||||||
|
{
|
||||||
|
assert_eq!(outsize % 8, 0);
|
||||||
|
self.state.tag_and_pad(0x1F);
|
||||||
|
self.state.squeeze(outsize / 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Directly generate the SHAKE256 hash of the given buffer, returning
|
||||||
|
/// a hash value of the given size (in bits). Presently, the output
|
||||||
|
/// size *must* be a multiple of 8, although this may change in the
|
||||||
|
/// future.
|
||||||
|
pub fn hash(buffer: &[u8], outsize: usize) -> Vec<u8>
|
||||||
|
{
|
||||||
|
let mut x = Self::new();
|
||||||
|
x.update(&buffer);
|
||||||
|
x.finalize(outsize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn shake256() {
|
||||||
|
let fname = "testdata/sha/shake256.test";
|
||||||
|
run_test(fname.to_string(), 4, |case| {
|
||||||
|
let (negl, lbytes) = case.get("l").unwrap();
|
||||||
|
let (negm, mbytes) = case.get("m").unwrap();
|
||||||
|
let (negd, dbytes) = case.get("d").unwrap();
|
||||||
|
let (nego, obytes) = case.get("o").unwrap();
|
||||||
|
|
||||||
|
assert!(!negl && !negm && !negd && !nego);
|
||||||
|
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||||
|
let osize = usize::from(U192::from_bytes(obytes));
|
||||||
|
let digest = SHAKE256::hash(&msg, osize);;
|
||||||
|
assert_eq!(dbytes, &digest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
75
src/ssh/dsa.rs
Normal file
75
src/ssh/dsa.rs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
use cryptonum::unsigned::*;
|
||||||
|
use dsa::{DSAKeyPair,DSAParameters,DSAPublicKey,DSAPrivateKey,L1024N160};
|
||||||
|
use std::io::{Read,Write};
|
||||||
|
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||||
|
use ssh::frame::*;
|
||||||
|
use ssh::SSHKey;
|
||||||
|
|
||||||
|
impl SSHKey for DSAKeyPair<L1024N160> {
|
||||||
|
fn valid_keytype(s: &str) -> bool {
|
||||||
|
(s == "ssh-dss") || (s == "dss")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>
|
||||||
|
{
|
||||||
|
let pubkey_type = parse_openssh_string(inp)?;
|
||||||
|
if !Self::valid_keytype(&pubkey_type) {
|
||||||
|
return Err(SSHKeyParseError::UnknownKeyType(pubkey_type));
|
||||||
|
}
|
||||||
|
let pubp = parse_openssh_number(inp)?;
|
||||||
|
let pubq = parse_openssh_number(inp)?;
|
||||||
|
let pubg = parse_openssh_number(inp)?;
|
||||||
|
let pubparams = L1024N160::new(pubp, pubg, pubq);
|
||||||
|
let puby: U1024 = parse_openssh_number(inp)?;
|
||||||
|
for _ in inp.bytes() { return Err(SSHKeyParseError::UnknownTrailingData); }
|
||||||
|
Ok(DSAPublicKey::<L1024N160>::new(pubparams.clone(), puby.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>
|
||||||
|
{
|
||||||
|
let check1 = parse_openssh_u32(inp)?;
|
||||||
|
let check2 = parse_openssh_u32(inp)?;
|
||||||
|
if check1 != check2 {
|
||||||
|
return Err(SSHKeyParseError::PrivateKeyCorruption);
|
||||||
|
}
|
||||||
|
let privkey_type = parse_openssh_string(inp)?;
|
||||||
|
if !Self::valid_keytype(&privkey_type) {
|
||||||
|
return Err(SSHKeyParseError::InconsistentKeyTypes("ssh-dss".to_string(), privkey_type));
|
||||||
|
}
|
||||||
|
let privp = parse_openssh_number(inp)?;
|
||||||
|
let privq = parse_openssh_number(inp)?;
|
||||||
|
let privg = parse_openssh_number(inp)?;
|
||||||
|
let privparams = L1024N160::new(privp, privg, privq);
|
||||||
|
let _ = parse_openssh_buffer(inp)?; // a copy of y we don't need
|
||||||
|
let privx = parse_openssh_number(inp)?;
|
||||||
|
|
||||||
|
let privkey = DSAPrivateKey::<L1024N160>::new(privparams, privx);
|
||||||
|
let comment = parse_openssh_string(inp)?;
|
||||||
|
for (idx,byte) in inp.bytes().enumerate() {
|
||||||
|
if ((idx+1) as u8) != byte? {
|
||||||
|
return Err(SSHKeyParseError::InvalidPadding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((privkey,comment))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||||
|
{
|
||||||
|
render_openssh_string(out, "ssh-dss")?;
|
||||||
|
render_openssh_number(out, &self.public.params.p)?;
|
||||||
|
render_openssh_number(out, &self.public.params.q)?;
|
||||||
|
render_openssh_number(out, &self.public.params.g)?;
|
||||||
|
render_openssh_number(out, &self.public.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||||
|
{
|
||||||
|
render_openssh_string(out, "ssh-dss")?;
|
||||||
|
render_openssh_number(out, &self.private.params.p)?;
|
||||||
|
render_openssh_number(out, &self.private.params.q)?;
|
||||||
|
render_openssh_number(out, &self.private.params.g)?;
|
||||||
|
render_openssh_number(out, &self.public.y)?;
|
||||||
|
render_openssh_number(out, &self.private.x)
|
||||||
|
}
|
||||||
|
}
|
||||||
171
src/ssh/ecdsa.rs
Normal file
171
src/ssh/ecdsa.rs
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
use cryptonum::unsigned::*;
|
||||||
|
use ecdsa::{ECDSAPair,ECDSAPublic,ECCPublicKey,ECDSAPrivate,ECCPrivateKey};
|
||||||
|
use ecdsa::{EllipticCurve,P256,P384,P521};
|
||||||
|
use std::io::{Read,Write};
|
||||||
|
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||||
|
use ssh::frame::*;
|
||||||
|
use ssh::SSHKey;
|
||||||
|
|
||||||
|
impl SSHKey for ECDSAPair {
|
||||||
|
fn valid_keytype(s: &str) -> bool {
|
||||||
|
(s == "ssh-ecdsa") || (s == "ecdsa") || (s == "ecdsa-sha2-nistp256") ||
|
||||||
|
(s == "ecdsa-sha2-nistp384") || (s == "ecdsa-sha2-nistp521")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>
|
||||||
|
{
|
||||||
|
let pubkey_type = parse_openssh_string(inp)?;
|
||||||
|
if !Self::valid_keytype(&pubkey_type) {
|
||||||
|
return Err(SSHKeyParseError::UnknownKeyType(pubkey_type));
|
||||||
|
}
|
||||||
|
// this peaks a little under the cover a bit (it'd be nice to pretend
|
||||||
|
// that we didn't know the number format was the same as the buffer
|
||||||
|
// one), but we need to infer what kind of key this is, and this appears
|
||||||
|
// to be the easiest / fastest way.
|
||||||
|
let curve = parse_openssh_string(inp)?;
|
||||||
|
match curve.as_ref() {
|
||||||
|
"nistp256" => {
|
||||||
|
let val = parse_openssh_buffer(inp)?;
|
||||||
|
if val[0] != 4 || val.len() != 65 {
|
||||||
|
return Err(SSHKeyParseError::InvalidECPointCompression);
|
||||||
|
}
|
||||||
|
let x = U256::from_bytes(&val[1..33]);
|
||||||
|
let y = U256::from_bytes(&val[33..]);
|
||||||
|
let p = P256::new_point(x, y);
|
||||||
|
let pbl = ECCPublicKey::<P256>::new(p);
|
||||||
|
Ok(ECDSAPublic::P256(pbl))
|
||||||
|
}
|
||||||
|
"nistp384" => {
|
||||||
|
let val = parse_openssh_buffer(inp)?;
|
||||||
|
if val[0] != 4 || val.len() != 97 {
|
||||||
|
return Err(SSHKeyParseError::InvalidECPointCompression);
|
||||||
|
}
|
||||||
|
let x = U384::from_bytes(&val[1..49]);
|
||||||
|
let y = U384::from_bytes(&val[49..]);
|
||||||
|
let p = P384::new_point(x, y);
|
||||||
|
let pbl = ECCPublicKey::<P384>::new(p);
|
||||||
|
Ok(ECDSAPublic::P384(pbl))
|
||||||
|
}
|
||||||
|
"nistp521" => {
|
||||||
|
let val = parse_openssh_buffer(inp)?;
|
||||||
|
if val[0] != 4 || val.len() != 133 {
|
||||||
|
return Err(SSHKeyParseError::InvalidECPointCompression);
|
||||||
|
}
|
||||||
|
let x = U576::from_bytes(&val[1..67]);
|
||||||
|
let y = U576::from_bytes(&val[67..]);
|
||||||
|
let p = P521::new_point(x, y);
|
||||||
|
let pbl = ECCPublicKey::<P521>::new(p);
|
||||||
|
Ok(ECDSAPublic::P521(pbl))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(SSHKeyParseError::UnknownECDSACurve(curve))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>
|
||||||
|
{
|
||||||
|
let check1 = parse_openssh_u32(inp)?;
|
||||||
|
let check2 = parse_openssh_u32(inp)?;
|
||||||
|
if check1 != check2 {
|
||||||
|
return Err(SSHKeyParseError::PrivateKeyCorruption);
|
||||||
|
}
|
||||||
|
let res = match ECDSAPair::parse_ssh_public_info(inp)? {
|
||||||
|
ECDSAPublic::P192(_) => return Err(SSHKeyParseError::PrivateKeyCorruption),
|
||||||
|
ECDSAPublic::P224(_) => return Err(SSHKeyParseError::PrivateKeyCorruption),
|
||||||
|
ECDSAPublic::P256(_) => {
|
||||||
|
let mut dbytes = parse_openssh_buffer(inp)?;
|
||||||
|
while dbytes[0] == 0 { dbytes.remove(0); }
|
||||||
|
assert!(dbytes.len() <= 32);
|
||||||
|
let d = U256::from_bytes(&dbytes);
|
||||||
|
ECDSAPrivate::P256(ECCPrivateKey::<P256>::new(d))
|
||||||
|
}
|
||||||
|
ECDSAPublic::P384(_) => {
|
||||||
|
let mut dbytes = parse_openssh_buffer(inp)?;
|
||||||
|
while dbytes[0] == 0 { dbytes.remove(0); }
|
||||||
|
assert!(dbytes.len() <= 48);
|
||||||
|
let d = U384::from_bytes(&dbytes);
|
||||||
|
ECDSAPrivate::P384(ECCPrivateKey::<P384>::new(d))
|
||||||
|
}
|
||||||
|
ECDSAPublic::P521(_) => {
|
||||||
|
let mut dbytes = parse_openssh_buffer(inp)?;
|
||||||
|
while dbytes[0] == 0 { dbytes.remove(0); }
|
||||||
|
assert!(dbytes.len() <= 66);
|
||||||
|
let d = U576::from_bytes(&dbytes);
|
||||||
|
ECDSAPrivate::P521(ECCPrivateKey::<P521>::new(d))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let comment = parse_openssh_string(inp)?;
|
||||||
|
for (idx,byte) in inp.bytes().enumerate() {
|
||||||
|
if ((idx+1) as u8) != byte? {
|
||||||
|
return Err(SSHKeyParseError::InvalidPadding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((res, comment))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||||
|
{
|
||||||
|
render_openssh_string(out, "ssh-ecdsa")?;
|
||||||
|
match self {
|
||||||
|
ECDSAPair::P192(_,_) =>
|
||||||
|
return Err(SSHKeyRenderError::IllegalECDSAKeyType("P192".to_string())),
|
||||||
|
ECDSAPair::P224(_,_) =>
|
||||||
|
return Err(SSHKeyRenderError::IllegalECDSAKeyType("P224".to_string())),
|
||||||
|
ECDSAPair::P256(pu,_) => {
|
||||||
|
render_openssh_string(out, "nistp256")?;
|
||||||
|
let mut vec = Vec::with_capacity(66);
|
||||||
|
vec.write(&[4u8])?;
|
||||||
|
render_number(256, &mut vec, &U256::from(pu.q.x.clone()))?;
|
||||||
|
render_number(256, &mut vec, &U256::from(pu.q.y.clone()))?;
|
||||||
|
render_openssh_buffer(out, &vec)?;
|
||||||
|
}
|
||||||
|
ECDSAPair::P384(pu,_) => {
|
||||||
|
render_openssh_string(out, "nistp384")?;
|
||||||
|
let mut vec = Vec::with_capacity(66);
|
||||||
|
vec.write(&[4u8])?;
|
||||||
|
render_number(384, &mut vec, &U384::from(pu.q.x.clone()))?;
|
||||||
|
render_number(384, &mut vec, &U384::from(pu.q.y.clone()))?;
|
||||||
|
render_openssh_buffer(out, &vec)?;
|
||||||
|
}
|
||||||
|
ECDSAPair::P521(pu,_) => {
|
||||||
|
render_openssh_string(out, "nistp521")?;
|
||||||
|
let mut vec = Vec::with_capacity(66);
|
||||||
|
vec.write(&[4u8])?;
|
||||||
|
render_number(521, &mut vec, &U576::from(pu.q.x.clone()))?;
|
||||||
|
render_number(521, &mut vec, &U576::from(pu.q.y.clone()))?;
|
||||||
|
render_openssh_buffer(out, &vec)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||||
|
{
|
||||||
|
self.render_ssh_public_info(out)?;
|
||||||
|
match self {
|
||||||
|
ECDSAPair::P192(_,_) =>
|
||||||
|
return Err(SSHKeyRenderError::IllegalECDSAKeyType("P192".to_string())),
|
||||||
|
ECDSAPair::P224(_,_) =>
|
||||||
|
return Err(SSHKeyRenderError::IllegalECDSAKeyType("P224".to_string())),
|
||||||
|
ECDSAPair::P256(_,pr) => { render_openssh_u32(out, 256/8)?; render_number(256, out, &pr.d)?; }
|
||||||
|
ECDSAPair::P384(_,pr) => { render_openssh_u32(out, 384/8)?; render_number(384, out, &pr.d)?; }
|
||||||
|
ECDSAPair::P521(_,pr) => { render_openssh_u32(out, 528/8)?; render_number(521, out, &pr.d)?; }
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_number<O,N>(bitlen: usize, out: &mut O, val: &N) -> Result<(),SSHKeyRenderError>
|
||||||
|
where
|
||||||
|
O: Write,
|
||||||
|
N: Encoder
|
||||||
|
{
|
||||||
|
let mut outvec = Vec::new();
|
||||||
|
outvec.write(&val.to_bytes())?;
|
||||||
|
while outvec.len() < ((bitlen + 7) / 8) { outvec.insert(0,0); }
|
||||||
|
while outvec.len() > ((bitlen + 7) / 8) { outvec.remove(0); }
|
||||||
|
out.write(&outvec)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
58
src/ssh/ed25519.rs
Normal file
58
src/ssh/ed25519.rs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
use ed25519::{ED25519KeyPair,ED25519Private,ED25519Public};
|
||||||
|
use std::io::{Read,Write};
|
||||||
|
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||||
|
use ssh::frame::*;
|
||||||
|
use ssh::SSHKey;
|
||||||
|
|
||||||
|
impl SSHKey for ED25519KeyPair {
|
||||||
|
fn valid_keytype(s: &str) -> bool {
|
||||||
|
(s == "ssh-ed25519")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>
|
||||||
|
{
|
||||||
|
let pubkey_type = parse_openssh_string(inp)?;
|
||||||
|
if !Self::valid_keytype(&pubkey_type) {
|
||||||
|
return Err(SSHKeyParseError::UnknownKeyType(pubkey_type));
|
||||||
|
}
|
||||||
|
let pubkey_bytes = parse_openssh_buffer(inp)?;
|
||||||
|
Ok(ED25519Public::new(&pubkey_bytes)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>
|
||||||
|
{
|
||||||
|
let check1 = parse_openssh_u32(inp)?;
|
||||||
|
let check2 = parse_openssh_u32(inp)?;
|
||||||
|
if check1 != check2 {
|
||||||
|
return Err(SSHKeyParseError::PrivateKeyCorruption);
|
||||||
|
}
|
||||||
|
let public = ED25519KeyPair::parse_ssh_public_info(inp)?;
|
||||||
|
let private_bytes = parse_openssh_buffer(inp)?;
|
||||||
|
let private = ED25519Private::from_seed(&private_bytes[0..32]);
|
||||||
|
let comment = parse_openssh_string(inp)?;
|
||||||
|
for (idx,byte) in inp.bytes().enumerate() {
|
||||||
|
if ((idx+1) as u8) != byte? {
|
||||||
|
return Err(SSHKeyParseError::InvalidPadding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(public, ED25519Public::from(&private));
|
||||||
|
|
||||||
|
Ok((private, comment))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||||
|
{
|
||||||
|
render_openssh_string(out, "ssh-ed25519")?;
|
||||||
|
render_openssh_buffer(out, &self.public.to_bytes())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||||
|
{
|
||||||
|
self.render_ssh_public_info(out)?;
|
||||||
|
let mut private_bytes = self.private.to_bytes();
|
||||||
|
private_bytes.append(&mut self.public.to_bytes());
|
||||||
|
render_openssh_buffer(out, &private_bytes)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/ssh/errors.rs
Normal file
68
src/ssh/errors.rs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
use base64::DecodeError;
|
||||||
|
use ed25519::ED25519PublicImportError;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
/// A whole pile of errors that you can get when parsing an SSH key from
|
||||||
|
/// disk or memory.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SSHKeyParseError
|
||||||
|
{
|
||||||
|
DecodeError(DecodeError),
|
||||||
|
IOError(io::Error),
|
||||||
|
NoBeginBannerFound, NoEndBannerFound,
|
||||||
|
NoOpenSSHMagicHeader,
|
||||||
|
UnknownKeyCipher(String),
|
||||||
|
UnknownKDF(String), UnexpectedKDFOptions,
|
||||||
|
InvalidNumberOfKeys(u32),
|
||||||
|
UnknownTrailingData,
|
||||||
|
UnknownKeyType(String),
|
||||||
|
InvalidPublicKeyMaterial,
|
||||||
|
PrivateKeyCorruption,
|
||||||
|
InconsistentKeyTypes(String,String),
|
||||||
|
InconsistentPublicKeyValue,
|
||||||
|
InvalidPrivateKeyValue,
|
||||||
|
InvalidPadding,
|
||||||
|
InvalidPublicKeyType,
|
||||||
|
BrokenPublicKeyLine,
|
||||||
|
UnknownECDSACurve(String),
|
||||||
|
InvalidECPointCompression
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DecodeError> for SSHKeyParseError {
|
||||||
|
fn from(e: DecodeError) -> SSHKeyParseError {
|
||||||
|
SSHKeyParseError::DecodeError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for SSHKeyParseError {
|
||||||
|
fn from(e: io::Error) -> SSHKeyParseError {
|
||||||
|
SSHKeyParseError::IOError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ED25519PublicImportError> for SSHKeyParseError {
|
||||||
|
fn from(e: ED25519PublicImportError) -> SSHKeyParseError {
|
||||||
|
match e {
|
||||||
|
ED25519PublicImportError::WrongNumberOfBytes(_) =>
|
||||||
|
SSHKeyParseError::InvalidPublicKeyMaterial,
|
||||||
|
ED25519PublicImportError::InvalidPublicPoint =>
|
||||||
|
SSHKeyParseError::InvalidPublicKeyMaterial,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A much smaller set of errors you can get when rendering an SSH key into
|
||||||
|
/// a file or memory block.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SSHKeyRenderError {
|
||||||
|
IOError(io::Error),
|
||||||
|
StringTooLong,
|
||||||
|
BufferTooLarge,
|
||||||
|
IllegalECDSAKeyType(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for SSHKeyRenderError {
|
||||||
|
fn from(e: io::Error) -> SSHKeyRenderError {
|
||||||
|
SSHKeyRenderError::IOError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
320
src/ssh/frame.rs
Normal file
320
src/ssh/frame.rs
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
use base64::{decode,encode};
|
||||||
|
use byteorder::{BigEndian,ReadBytesExt,WriteBytesExt};
|
||||||
|
use cryptonum::unsigned::{Decoder,Encoder};
|
||||||
|
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||||
|
#[cfg(test)]
|
||||||
|
use std::io::Cursor;
|
||||||
|
#[cfg(test)]
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::iter::Iterator;
|
||||||
|
|
||||||
|
const OPENER: &'static str = "-----BEGIN OPENSSH PRIVATE KEY-----";
|
||||||
|
const CLOSER: &'static str = "-----END OPENSSH PRIVATE KEY-----";
|
||||||
|
|
||||||
|
/// Given a string defining an ASCII SSH key blob (one that starts with
|
||||||
|
/// "--BEGIN..."), decode the body of the blob and return it as binary
|
||||||
|
/// data.
|
||||||
|
pub fn parse_ssh_private_key_data(s: &str) -> Result<Vec<u8>,SSHKeyParseError>
|
||||||
|
{
|
||||||
|
if s.starts_with(OPENER) {
|
||||||
|
if let Some(endidx) = s.find(CLOSER) {
|
||||||
|
let b64str: String = s[OPENER.len()..endidx].chars().filter(|x| !x.is_whitespace()).collect();
|
||||||
|
let bytes = decode(&b64str)?;
|
||||||
|
Ok(bytes)
|
||||||
|
} else {
|
||||||
|
Err(SSHKeyParseError::NoEndBannerFound)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(SSHKeyParseError::NoBeginBannerFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Once you've figured out the binary data you want to produce for an SSH key
|
||||||
|
/// blob, use this routine to render it into its ASCII encoding.
|
||||||
|
pub fn render_ssh_private_key_data(bytes: &[u8]) -> String
|
||||||
|
{
|
||||||
|
let mut bytestr = encode(bytes);
|
||||||
|
let mut output = String::new();
|
||||||
|
|
||||||
|
output.push_str(OPENER);
|
||||||
|
#[cfg(target_os="windows")]
|
||||||
|
output.push_str("\r");
|
||||||
|
output.push_str("\n");
|
||||||
|
while bytestr.len() > 70 {
|
||||||
|
let rest = bytestr.split_off(70);
|
||||||
|
output.push_str(&bytestr);
|
||||||
|
#[cfg(target_os="windows")]
|
||||||
|
output.push_str("\r");
|
||||||
|
output.push_str("\n");
|
||||||
|
bytestr = rest;
|
||||||
|
}
|
||||||
|
output.push_str(&bytestr);
|
||||||
|
#[cfg(target_os="windows")]
|
||||||
|
output.push_str("\r");
|
||||||
|
output.push_str("\n");
|
||||||
|
output.push_str(CLOSER);
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const OPENSSH_MAGIC_HEADER: &'static str = "openssh-key-v1\0";
|
||||||
|
const OPENSSH_MAGIC_HEADER_LEN: usize = 15;
|
||||||
|
|
||||||
|
/// Parse the magic header in an SSH key file.
|
||||||
|
pub fn parse_openssh_header<R: Read>(input: &mut R) -> Result<(),SSHKeyParseError>
|
||||||
|
{
|
||||||
|
let mut limited_input_header = input.take(OPENSSH_MAGIC_HEADER_LEN as u64);
|
||||||
|
let mut header: [u8; OPENSSH_MAGIC_HEADER_LEN] = [0; OPENSSH_MAGIC_HEADER_LEN];
|
||||||
|
|
||||||
|
assert_eq!(OPENSSH_MAGIC_HEADER.len(), OPENSSH_MAGIC_HEADER_LEN);
|
||||||
|
limited_input_header.read_exact(&mut header)?;
|
||||||
|
|
||||||
|
for (left, right) in OPENSSH_MAGIC_HEADER.bytes().zip(header.iter()) {
|
||||||
|
if left != *right {
|
||||||
|
return Err(SSHKeyParseError::NoOpenSSHMagicHeader)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render the magic header in an SSH key file.
|
||||||
|
pub fn render_openssh_header<O: Write>(output: &mut O) -> Result<(),SSHKeyRenderError>
|
||||||
|
{
|
||||||
|
Ok(output.write_all(OPENSSH_MAGIC_HEADER.as_bytes())?)
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Parse an unsigned u32 from the SSH key stream. (This does the appropriate
|
||||||
|
/// conversion from network order to native order.)
|
||||||
|
pub fn parse_openssh_u32<I: Read>(input: &mut I) -> Result<u32,SSHKeyParseError>
|
||||||
|
{
|
||||||
|
let mut limited_input_header = input.take(4);
|
||||||
|
let res = limited_input_header.read_u32::<BigEndian>()?;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render an unsigned u32 from the SSH key stream. (This does the appropriate
|
||||||
|
/// conversion from network order to native order.)
|
||||||
|
pub fn render_openssh_u32<O: Write>(output: &mut O, val: u32) -> Result<(),SSHKeyRenderError>
|
||||||
|
{
|
||||||
|
Ok(output.write_u32::<BigEndian>(val)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Parse a string from the SSH key stream. This does some validation to ensure
|
||||||
|
/// that the data being read is actually in a form that Rust will recognize as
|
||||||
|
/// being a valid string.
|
||||||
|
pub fn parse_openssh_string<I: Read>(input: &mut I) -> Result<String,SSHKeyParseError>
|
||||||
|
{
|
||||||
|
let length = parse_openssh_u32(input)?;
|
||||||
|
let mut limited_input = input.take(length as u64);
|
||||||
|
let mut result = String::new();
|
||||||
|
limited_input.read_to_string(&mut result)?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render a string into the SSH key stream.
|
||||||
|
pub fn render_openssh_string<O: Write>(output: &mut O, v: &str) -> Result<(),SSHKeyRenderError>
|
||||||
|
{
|
||||||
|
let vbytes: Vec<u8> = v.bytes().collect();
|
||||||
|
let len = vbytes.len();
|
||||||
|
|
||||||
|
if len > 0xFFFFFFFF {
|
||||||
|
return Err(SSHKeyRenderError::StringTooLong);
|
||||||
|
}
|
||||||
|
|
||||||
|
render_openssh_u32(output, vbytes.len() as u32)?;
|
||||||
|
output.write_all(&vbytes)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Read a buffer from the SSH key stream.
|
||||||
|
pub fn parse_openssh_buffer<I: Read>(input: &mut I) -> Result<Vec<u8>,SSHKeyParseError>
|
||||||
|
{
|
||||||
|
let length = parse_openssh_u32(input)?;
|
||||||
|
let mut limited_input = input.take(length as u64);
|
||||||
|
let mut res = Vec::with_capacity(length as usize);
|
||||||
|
limited_input.read_to_end(&mut res)?;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render a buffer into the SSH key stream.
|
||||||
|
pub fn render_openssh_buffer<O: Write>(output: &mut O, b: &[u8]) -> Result<(),SSHKeyRenderError>
|
||||||
|
{
|
||||||
|
if b.len() > 0xFFFFFFFF {
|
||||||
|
return Err(SSHKeyRenderError::BufferTooLarge);
|
||||||
|
}
|
||||||
|
|
||||||
|
render_openssh_u32(output, b.len() as u32)?;
|
||||||
|
if b.len() > 0 {
|
||||||
|
output.write_all(b)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Parse a fixed-width number from the SSH key stream and return it.
|
||||||
|
pub fn parse_openssh_number<I,D>(input: &mut I) -> Result<D,SSHKeyParseError>
|
||||||
|
where
|
||||||
|
I: Read,
|
||||||
|
D: Decoder
|
||||||
|
{
|
||||||
|
let mut buffer = parse_openssh_buffer(input)?;
|
||||||
|
while buffer[0] == 0 { buffer.remove(0); }
|
||||||
|
Ok(D::from_bytes(&buffer))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render a fixed-width number into the SSH key stream.
|
||||||
|
pub fn render_openssh_number<O,D>(output: &mut O, n: &D) -> Result<(),SSHKeyRenderError>
|
||||||
|
where
|
||||||
|
O: Write,
|
||||||
|
D: Encoder
|
||||||
|
{
|
||||||
|
let bytes = n.to_bytes();
|
||||||
|
render_openssh_buffer(output, &bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use cryptonum::unsigned::{U192,U1024,U2048,U4096};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
quickcheck! {
|
||||||
|
fn bytes_roundtrip(x: Vec<u8>) -> bool {
|
||||||
|
let rendered = render_ssh_private_key_data(&x);
|
||||||
|
let returned = parse_ssh_private_key_data(&rendered).unwrap();
|
||||||
|
returned == x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blocks_formatted(x: Vec<u8>) -> bool {
|
||||||
|
let rendered = render_ssh_private_key_data(&x);
|
||||||
|
let mut is_ok = true;
|
||||||
|
|
||||||
|
for line in rendered.lines() {
|
||||||
|
let clean_line: String = line.chars().filter(|x| *x != '\r').collect();
|
||||||
|
is_ok &= clean_line.len() <= 70;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_ok
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u32s_roundtrip_rp(x: u32) -> bool {
|
||||||
|
let mut buffer = vec![];
|
||||||
|
render_openssh_u32(&mut buffer, x).unwrap();
|
||||||
|
let mut cursor = Cursor::new(buffer);
|
||||||
|
let check = parse_openssh_u32(&mut cursor).unwrap();
|
||||||
|
x == check
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u32s_roundtrip_pr(a: u8, b: u8, c: u8, d: u8) -> bool {
|
||||||
|
let block = [a,b,c,d];
|
||||||
|
let mut cursor = Cursor::new(block);
|
||||||
|
let base = parse_openssh_u32(&mut cursor).unwrap();
|
||||||
|
let mut rendered = vec![];
|
||||||
|
render_openssh_u32(&mut rendered, base).unwrap();
|
||||||
|
(block[0] == rendered[0]) &&
|
||||||
|
(block[1] == rendered[1]) &&
|
||||||
|
(block[2] == rendered[2]) &&
|
||||||
|
(block[3] == rendered[3])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn string_roundtrip(s: String) -> bool {
|
||||||
|
let mut buffer = vec![];
|
||||||
|
render_openssh_string(&mut buffer, &s).unwrap();
|
||||||
|
let mut cursor = Cursor::new(buffer);
|
||||||
|
let check = parse_openssh_string(&mut cursor).unwrap();
|
||||||
|
s == check
|
||||||
|
}
|
||||||
|
|
||||||
|
fn buffer(os: Vec<u8>) -> bool {
|
||||||
|
let mut buffer = vec![];
|
||||||
|
render_openssh_buffer(&mut buffer, &os).unwrap();
|
||||||
|
let mut cursor = Cursor::new(buffer);
|
||||||
|
let check = parse_openssh_buffer(&mut cursor).unwrap();
|
||||||
|
os == check
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u192(x: U192) -> bool {
|
||||||
|
let mut buffer = vec![];
|
||||||
|
render_openssh_number(&mut buffer, &x).unwrap();
|
||||||
|
let mut cursor = Cursor::new(buffer);
|
||||||
|
let check: U192 = parse_openssh_number(&mut cursor).unwrap();
|
||||||
|
check == x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u1024(x: U1024) -> bool {
|
||||||
|
let mut buffer = vec![];
|
||||||
|
render_openssh_number(&mut buffer, &x).unwrap();
|
||||||
|
let mut cursor = Cursor::new(buffer);
|
||||||
|
let check: U1024 = parse_openssh_number(&mut cursor).unwrap();
|
||||||
|
check == x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u2048(x: U2048) -> bool {
|
||||||
|
let mut buffer = vec![];
|
||||||
|
render_openssh_number(&mut buffer, &x).unwrap();
|
||||||
|
let mut cursor = Cursor::new(buffer);
|
||||||
|
let check: U2048 = parse_openssh_number(&mut cursor).unwrap();
|
||||||
|
check == x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u4096(x: U4096) -> bool {
|
||||||
|
let mut buffer = vec![];
|
||||||
|
render_openssh_number(&mut buffer, &x).unwrap();
|
||||||
|
let mut cursor = Cursor::new(buffer);
|
||||||
|
let check: U4096 = parse_openssh_number(&mut cursor).unwrap();
|
||||||
|
check == x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn pregenerated_reencode() {
|
||||||
|
let test_files = ["dsa1024-1", "dsa1024-2", "dsa1024-3",
|
||||||
|
"ecdsa256-1", "ecdsa256-2", "ecdsa256-3",
|
||||||
|
"ecdsa384-1", "ecdsa384-2", "ecdsa384-3",
|
||||||
|
"ecdsa521-1", "ecdsa521-2", "ecdsa521-3",
|
||||||
|
"ed25519-1", "ed25519-2", "ed25519-3",
|
||||||
|
"rsa1024-1", "rsa1024-2", "rsa1024-3",
|
||||||
|
"rsa2048-1", "rsa2048-2", "rsa2048-3",
|
||||||
|
"rsa3072-1", "rsa3072-2", "rsa3072-3",
|
||||||
|
"rsa4096-1", "rsa4096-2", "rsa4096-3",
|
||||||
|
"rsa8192-1", "rsa8192-2", "rsa8192-3" ];
|
||||||
|
|
||||||
|
for file in test_files.iter() {
|
||||||
|
let path = format!("testdata/ssh/{}",file);
|
||||||
|
let mut fd = File::open(path).unwrap();
|
||||||
|
let mut contents = String::new();
|
||||||
|
fd.read_to_string(&mut contents).unwrap();
|
||||||
|
let parsed = parse_ssh_private_key_data(&contents).unwrap();
|
||||||
|
let rendered = render_ssh_private_key_data(&parsed);
|
||||||
|
// we remove white space in this to avoid a couple issues with files
|
||||||
|
// generated in Windows or not, as well as trailing white space that
|
||||||
|
// doesn't really matter.
|
||||||
|
let cleaned_orig: String = contents.chars().filter(|x| !x.is_whitespace()).collect();
|
||||||
|
let cleaned_rend: String = rendered.chars().filter(|x| !x.is_whitespace()).collect();
|
||||||
|
assert_eq!(cleaned_orig, cleaned_rend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn header_roundtrips() {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
assert!(render_openssh_header(&mut vec).is_ok());
|
||||||
|
let mut cursor = Cursor::new(vec);
|
||||||
|
assert!(parse_openssh_header(&mut cursor).is_ok());
|
||||||
|
}
|
||||||
428
src/ssh/mod.rs
Normal file
428
src/ssh/mod.rs
Normal file
@@ -0,0 +1,428 @@
|
|||||||
|
//! Most of the routines you want are exported from this module as functions,
|
||||||
|
//! not as structs, macros, enums, or what have you. In particular, you
|
||||||
|
//! probably want the `decode` or `encode` functions, or one of the functions
|
||||||
|
//! that `load`s data from disk or `write`s it. Here's some example code
|
||||||
|
//! to get you started, using a generated ED25519 key for fun:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use simple_crypto::ed25519::ED25519KeyPair;
|
||||||
|
//! use simple_crypto::ssh::*;
|
||||||
|
//!
|
||||||
|
//! // Generate a new ED25519 key
|
||||||
|
//! let mut rng = rand::rngs::OsRng::new().unwrap();
|
||||||
|
//! let kp = ED25519KeyPair::generate(&mut rng);
|
||||||
|
//!
|
||||||
|
//! // Now that we have it, we can encode it as a handy ASCII string in memory,
|
||||||
|
//! // using a totally fake email address for fun:
|
||||||
|
//! let ascii_rep = encode_ssh(&kp, "fake@email.addr").expect("Encode failure!");
|
||||||
|
//!
|
||||||
|
//! // As usual, we should be able to decode anything we encode, and the
|
||||||
|
//! // keys should match:
|
||||||
|
//! let (kp2, addr2) = decode_ssh(&ascii_rep).expect("Decode failure!");
|
||||||
|
//! assert_eq!(kp, kp2);
|
||||||
|
//! assert_eq!(&addr2, "fake@email.addr");
|
||||||
|
//!
|
||||||
|
//! // If you want to write this to a file, you can just do so directly:
|
||||||
|
//! write_ssh_keyfile("test.ed25519", &kp, "fake@email.addr").expect("write error");
|
||||||
|
//! // And then load it back:
|
||||||
|
//! let (kp3, addr3) = load_ssh_keyfile("test.ed25519").expect("load error");
|
||||||
|
//! // And, of course, it should be the same.
|
||||||
|
//! assert_eq!(kp, kp3);
|
||||||
|
//! assert_eq!(addr2, addr3);
|
||||||
|
//! ```
|
||||||
|
mod dsa;
|
||||||
|
mod ecdsa;
|
||||||
|
mod ed25519;
|
||||||
|
mod errors;
|
||||||
|
pub mod frame;
|
||||||
|
mod rsa;
|
||||||
|
|
||||||
|
pub use self::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||||
|
|
||||||
|
use base64::decode;
|
||||||
|
use self::frame::*;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Cursor,Read,Write};
|
||||||
|
use std::path::Path;
|
||||||
|
use super::KeyPair;
|
||||||
|
|
||||||
|
/// A trait defining keys that can be parsed / rendered by this library. Note
|
||||||
|
/// that you probably don't want to use these routines directly; they're mostly
|
||||||
|
/// used by the internal functions. Perhaps the only reason to use them is to
|
||||||
|
/// implement them, because you've got another kind of key you want to parse that
|
||||||
|
/// isn't already part of the library. (In that case, though ... maybe send a
|
||||||
|
/// patch?)
|
||||||
|
pub trait SSHKey: Sized + KeyPair {
|
||||||
|
/// Return true if the given string is a valid key type identifier for this
|
||||||
|
/// key type. (i.e., "ssh-ed25519" is the identifier for ED25519, and "dss"
|
||||||
|
/// and "ssh-dss" are both valid identifiers for DSA keys.)
|
||||||
|
fn valid_keytype(s: &str) -> bool;
|
||||||
|
|
||||||
|
/// Parse the public blob info within an SSH blob. I strongly recommend
|
||||||
|
/// using the functions in `ssh::frame` for this.
|
||||||
|
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>;
|
||||||
|
/// Parse the private blob info within an SSH blob. I strongly recommend
|
||||||
|
/// using the functions in `ssh::frame` for this.
|
||||||
|
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>;
|
||||||
|
|
||||||
|
/// Render the public blob info within an SSH blob. I strongly recommend
|
||||||
|
/// using the functions in `ssh::frame` for this.
|
||||||
|
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>;
|
||||||
|
/// Render the private blob info within an SSH blob. I strongly recommend
|
||||||
|
/// using the functions in `ssh::frame` for this.
|
||||||
|
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decode a string containing a private key into the appropriate key type and
|
||||||
|
/// the comment associated with it, usually an email address or similar.
|
||||||
|
pub fn decode_ssh<KP: SSHKey>(x: &str) -> Result<(KP, String),SSHKeyParseError>
|
||||||
|
{
|
||||||
|
let bytes = parse_ssh_private_key_data(x)?;
|
||||||
|
let data_size = bytes.len() as u64;
|
||||||
|
let mut byte_cursor = Cursor::new(bytes);
|
||||||
|
|
||||||
|
parse_openssh_header(&mut byte_cursor)?;
|
||||||
|
let ciphername = parse_openssh_string(&mut byte_cursor)?;
|
||||||
|
if ciphername != "none" {
|
||||||
|
return Err(SSHKeyParseError::UnknownKeyCipher(ciphername));
|
||||||
|
}
|
||||||
|
let kdfname = parse_openssh_string(&mut byte_cursor)?;
|
||||||
|
if kdfname != "none" {
|
||||||
|
return Err(SSHKeyParseError::UnknownKeyCipher(kdfname));
|
||||||
|
}
|
||||||
|
let kdfoptions = parse_openssh_buffer(&mut byte_cursor)?;
|
||||||
|
if kdfoptions.len() > 0 {
|
||||||
|
return Err(SSHKeyParseError::UnexpectedKDFOptions);
|
||||||
|
}
|
||||||
|
let numkeys = parse_openssh_u32(&mut byte_cursor)?;
|
||||||
|
if numkeys != 1 {
|
||||||
|
return Err(SSHKeyParseError::InvalidNumberOfKeys(numkeys));
|
||||||
|
}
|
||||||
|
let pubkey0 = parse_openssh_buffer(&mut byte_cursor)?;
|
||||||
|
let privkeys = parse_openssh_buffer(&mut byte_cursor)?;
|
||||||
|
if byte_cursor.position() < data_size {
|
||||||
|
return Err(SSHKeyParseError::UnknownTrailingData);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut pubcursor = Cursor::new(pubkey0);
|
||||||
|
let public = KP::parse_ssh_public_info(&mut pubcursor)?;
|
||||||
|
let mut privcursor = Cursor::new(privkeys);
|
||||||
|
let (private, comment) = KP::parse_ssh_private_info(&mut privcursor)?;
|
||||||
|
|
||||||
|
Ok((KP::new(public, private), comment))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decode a string containing a public key into an appropriate key type and
|
||||||
|
/// the comment associated with it, usually an email address or similar.
|
||||||
|
pub fn decode_ssh_pubkey<KP: SSHKey>(s: &str) -> Result<(KP::Public, String),SSHKeyParseError>
|
||||||
|
{
|
||||||
|
let mut splitter = s.split_whitespace();
|
||||||
|
|
||||||
|
match (splitter.next(), splitter.next(), splitter.next(), splitter.next()) {
|
||||||
|
(Some(keytype), Some(keymaterial), Some(comment), None) => {
|
||||||
|
if !KP::valid_keytype(keytype) {
|
||||||
|
return Err(SSHKeyParseError::InvalidPublicKeyType);
|
||||||
|
}
|
||||||
|
|
||||||
|
let bytes = decode(keymaterial)?;
|
||||||
|
let mut byte_cursor = Cursor::new(bytes);
|
||||||
|
let key = KP::parse_ssh_public_info(&mut byte_cursor)?;
|
||||||
|
|
||||||
|
Ok((key, comment.to_string()))
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(SSHKeyParseError::BrokenPublicKeyLine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load an SSH private key file, returning the appropriate key type and the
|
||||||
|
/// comment associated with it.
|
||||||
|
pub fn load_ssh_keyfile<KP,P>(path: P) -> Result<(KP, String),SSHKeyParseError>
|
||||||
|
where
|
||||||
|
KP: SSHKey,
|
||||||
|
P: AsRef<Path>
|
||||||
|
{
|
||||||
|
let mut file = File::open(path)?;
|
||||||
|
let mut contents = String::new();
|
||||||
|
file.read_to_string(&mut contents)?;
|
||||||
|
decode_ssh(&contents)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load all the public keys from a file into memory.
|
||||||
|
pub fn load_ssh_pubkeys<KP,P>(path: P) -> Result<Vec<(KP::Public, String)>,SSHKeyParseError>
|
||||||
|
where
|
||||||
|
KP: SSHKey,
|
||||||
|
P: AsRef<Path>
|
||||||
|
{
|
||||||
|
let mut file = File::open(path)?;
|
||||||
|
let mut contents = String::new();
|
||||||
|
file.read_to_string(&mut contents)?;
|
||||||
|
let mut result = Vec::new();
|
||||||
|
|
||||||
|
for line in contents.lines() {
|
||||||
|
result.push( decode_ssh_pubkey::<KP>(line)? );
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode a supported key into its ASCII SSH format, with the given comment.
|
||||||
|
pub fn encode_ssh<KP: SSHKey>(x: &KP, comment: &str) -> Result<String,SSHKeyRenderError>
|
||||||
|
{
|
||||||
|
let mut pubkeybin = Vec::with_capacity(8192);
|
||||||
|
let mut privkeybin = Vec::with_capacity(8192);
|
||||||
|
let mut binary = Vec::with_capacity(16384);
|
||||||
|
|
||||||
|
// create the public key bits
|
||||||
|
x.render_ssh_public_info(&mut pubkeybin)?;
|
||||||
|
// create the private key bits
|
||||||
|
render_openssh_u32(&mut privkeybin, 0xDEADBEEF)?; // FIXME: Any reason for this to be random?
|
||||||
|
render_openssh_u32(&mut privkeybin, 0xDEADBEEF)?; // ditto
|
||||||
|
x.render_ssh_private_info(&mut privkeybin)?;
|
||||||
|
render_openssh_string(&mut privkeybin, comment)?;
|
||||||
|
// add some padding (not quite sure why)
|
||||||
|
let mut i = comment.len();
|
||||||
|
while (i % 16) != 0 {
|
||||||
|
privkeybin.write(&[(i - comment.len() + 1) as u8])?;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
// render a bunch of the framing stuff
|
||||||
|
render_openssh_header(&mut binary)?;
|
||||||
|
render_openssh_string(&mut binary, "none")?; // ciphername
|
||||||
|
render_openssh_string(&mut binary, "none")?; // kdfname
|
||||||
|
render_openssh_buffer(&mut binary, &[])?; // kdfoptions
|
||||||
|
render_openssh_u32(&mut binary, 1)?; // numkeys
|
||||||
|
render_openssh_buffer(&mut binary, &pubkeybin)?;
|
||||||
|
render_openssh_buffer(&mut binary, &privkeybin)?;
|
||||||
|
Ok(render_ssh_private_key_data(&binary))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode a supported key into the given file, with the given comment.
|
||||||
|
pub fn write_ssh_keyfile<KP,P>(path: P, x: &KP, comment: &str) -> Result<(),SSHKeyRenderError>
|
||||||
|
where
|
||||||
|
KP: SSHKey,
|
||||||
|
P: AsRef<Path>
|
||||||
|
{
|
||||||
|
let mut file = File::create(path)?;
|
||||||
|
let contents = encode_ssh(x, comment)?;
|
||||||
|
let bytes = contents.into_bytes();
|
||||||
|
file.write_all(&bytes)?;
|
||||||
|
file.sync_all()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use dsa::{DSAKeyPair,DSAPublicKey,L1024N160};
|
||||||
|
#[cfg(test)]
|
||||||
|
use ecdsa::ECDSAPair;
|
||||||
|
#[cfg(test)]
|
||||||
|
use ed25519::ED25519KeyPair;
|
||||||
|
#[cfg(test)]
|
||||||
|
use rsa::{RSAPair,RSAPublic,SIGNING_HASH_SHA256};
|
||||||
|
#[cfg(test)]
|
||||||
|
use sha::SHA256;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn dsa_examples() {
|
||||||
|
let test_files = ["dsa1024-1", "dsa1024-2", "dsa1024-3"];
|
||||||
|
|
||||||
|
for file in test_files.iter() {
|
||||||
|
let path = format!("testdata/ssh/{}",file);
|
||||||
|
let mkeypair = load_ssh_keyfile(path);
|
||||||
|
match mkeypair {
|
||||||
|
Err(e) => assert!(false, format!("reading error: {:?}", e)),
|
||||||
|
Ok((keypair, comment)) => {
|
||||||
|
let buffer = [0,1,2,3,4,6,2];
|
||||||
|
let _ : DSAKeyPair<L1024N160> = keypair;
|
||||||
|
let sig = keypair.private.sign::<SHA256>(&buffer);
|
||||||
|
assert!(keypair.public.verify::<SHA256>(&buffer, &sig));
|
||||||
|
let buffer2 = [0,1,2,3,4,6,5];
|
||||||
|
assert!(!keypair.public.verify::<SHA256>(&buffer2, &sig));
|
||||||
|
match encode_ssh(&keypair, &comment) {
|
||||||
|
Err(e2) => assert!(false, format!("render error: {:?}", e2)),
|
||||||
|
Ok(encodedstr) => {
|
||||||
|
match decode_ssh(&encodedstr) {
|
||||||
|
Err(e3) => assert!(false, format!("reparse error: {:?}", e3)),
|
||||||
|
Ok((keypair2,comment2)) => {
|
||||||
|
let _ : DSAKeyPair<L1024N160> = keypair2;
|
||||||
|
assert_eq!(keypair.public.params.p,keypair2.public.params.p,"failed to reparse key pair (p)");
|
||||||
|
assert_eq!(keypair.public.params.q,keypair2.public.params.q,"failed to reparse key pair (q)");
|
||||||
|
assert_eq!(keypair.public.params.g,keypair2.public.params.g,"failed to reparse key pair (g)");
|
||||||
|
assert_eq!(keypair.private.params.p,keypair2.private.params.p,"failed to reparse key pair (p)");
|
||||||
|
assert_eq!(keypair.private.params.q,keypair2.private.params.q,"failed to reparse key pair (q)");
|
||||||
|
assert_eq!(keypair.private.params.g,keypair2.private.params.g,"failed to reparse key pair (g)");
|
||||||
|
assert_eq!(keypair.public.y,keypair2.public.y,"failed to reparse key pair (y)");
|
||||||
|
assert_eq!(keypair.private.x,keypair2.private.x,"failed to reparse key pair (x)");
|
||||||
|
assert_eq!(comment,comment2,"failed to reparse comment");
|
||||||
|
let ppath = format!("testdata/ssh/{}.pub",file);
|
||||||
|
match load_ssh_pubkeys::<DSAKeyPair<L1024N160>,String>(ppath) {
|
||||||
|
Err(e4) => assert!(false, format!("pubkey error: {:?}", e4)),
|
||||||
|
Ok(pubkeys) => {
|
||||||
|
let _ : Vec<(DSAPublicKey<L1024N160>,String)> = pubkeys;
|
||||||
|
for (pubkey, comment3) in pubkeys {
|
||||||
|
assert_eq!(pubkey.params.p, keypair.public.params.p, "public key check (p)");
|
||||||
|
assert_eq!(pubkey.params.q, keypair.public.params.q, "public key check (q)");
|
||||||
|
assert_eq!(pubkey.params.g, keypair.public.params.g, "public key check (g)");
|
||||||
|
assert_eq!(pubkey.y, keypair.public.y, "public key check (y)");
|
||||||
|
assert_eq!(comment, comment3, "public key check comment")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn rsa_examples() {
|
||||||
|
let test_files = ["rsa1024-1", "rsa1024-2", "rsa1024-3",
|
||||||
|
"rsa2048-1", "rsa2048-2", "rsa2048-3",
|
||||||
|
"rsa3072-1", "rsa3072-2", "rsa3072-3",
|
||||||
|
"rsa4096-1", "rsa4096-2", "rsa4096-3",
|
||||||
|
"rsa8192-1", "rsa8192-2", "rsa8192-3"];
|
||||||
|
|
||||||
|
for file in test_files.iter() {
|
||||||
|
let path = format!("testdata/ssh/{}",file);
|
||||||
|
let mkeypair = load_ssh_keyfile::<RSAPair,String>(path);
|
||||||
|
match mkeypair {
|
||||||
|
Err(e) => assert!(false, format!("reading error: {:?}", e)),
|
||||||
|
Ok((keypair, comment)) => {
|
||||||
|
let buffer = [0,1,2,3,4,6,2];
|
||||||
|
let sig = keypair.sign(&SIGNING_HASH_SHA256, &buffer);
|
||||||
|
assert!(keypair.verify(&SIGNING_HASH_SHA256, &buffer, &sig));
|
||||||
|
match encode_ssh(&keypair, &comment) {
|
||||||
|
Err(e2) => assert!(false, format!("render error: {:?}", e2)),
|
||||||
|
Ok(encodedstr) => {
|
||||||
|
match decode_ssh(&encodedstr) {
|
||||||
|
Err(e3) => assert!(false, format!("reparse error: {:?}", e3)),
|
||||||
|
Ok((keypair2,comment2)) => {
|
||||||
|
assert_eq!(keypair,keypair2,"failed to reparse key pair");
|
||||||
|
assert_eq!(comment,comment2,"failed to reparse comment");
|
||||||
|
let ppath = format!("testdata/ssh/{}.pub",file);
|
||||||
|
match load_ssh_pubkeys::<RSAPair,String>(ppath) {
|
||||||
|
Err(e4) => assert!(false, format!("pubkey error: {:?}", e4)),
|
||||||
|
Ok(pubkeys) => {
|
||||||
|
let _ : Vec<(RSAPublic,String)> = pubkeys;
|
||||||
|
for (pubkey, comment3) in pubkeys {
|
||||||
|
assert_eq!(pubkey, keypair.public(), "public key check");
|
||||||
|
assert_eq!(comment, comment3, "public key check comment");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn ecdsa_examples() {
|
||||||
|
let test_files = ["ecdsa256-1", "ecdsa256-2", "ecdsa256-3",
|
||||||
|
"ecdsa384-1", "ecdsa384-2", "ecdsa384-3",
|
||||||
|
"ecdsa521-1", "ecdsa521-2", "ecdsa521-3"];
|
||||||
|
|
||||||
|
for file in test_files.iter() {
|
||||||
|
let path = format!("testdata/ssh/{}",file);
|
||||||
|
match load_ssh_keyfile::<ECDSAPair,String>(path) {
|
||||||
|
Err(e) =>
|
||||||
|
assert!(false, "SSH ECDSA parse error: {:?}", e),
|
||||||
|
Ok((keypair,comment)) => {
|
||||||
|
// first see if this roundtrips
|
||||||
|
let buffer = vec![0,1,2,4,5,6,9];
|
||||||
|
match keypair {
|
||||||
|
ECDSAPair::P192(_,_) =>
|
||||||
|
assert!(false, "Somehow got a P192 in read test"),
|
||||||
|
ECDSAPair::P224(_,_) =>
|
||||||
|
assert!(false, "Somehow got a P224 in read test"),
|
||||||
|
ECDSAPair::P256(ref pu, ref pr) => {
|
||||||
|
let sig = pr.sign::<SHA256>(&buffer);
|
||||||
|
assert!(pu.verify::<SHA256>(&buffer, &sig));
|
||||||
|
}
|
||||||
|
ECDSAPair::P384(ref pu, ref pr) => {
|
||||||
|
let sig = pr.sign::<SHA256>(&buffer);
|
||||||
|
assert!(pu.verify::<SHA256>(&buffer, &sig));
|
||||||
|
}
|
||||||
|
ECDSAPair::P521(ref pu, ref pr) => {
|
||||||
|
let sig = pr.sign::<SHA256>(&buffer);
|
||||||
|
assert!(pu.verify::<SHA256>(&buffer, &sig));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// encode this, parse it again
|
||||||
|
match encode_ssh(&keypair, &comment) {
|
||||||
|
Err(e) =>
|
||||||
|
assert!(false, "SSH ECDSA encoding error: {:?}", e),
|
||||||
|
Ok(coded) => {
|
||||||
|
match (decode_ssh(&coded), keypair) {
|
||||||
|
(Err(e), _) =>
|
||||||
|
assert!(false, "SSSH ECDSA redecoding error: {:?}", e),
|
||||||
|
(Ok((ECDSAPair::P256(pu2, pr2), comment2)), ECDSAPair::P256(pu,pr)) => {
|
||||||
|
assert_eq!(pu, pu2, "public key mismatch");
|
||||||
|
assert_eq!(pr, pr2, "public key mismatch");
|
||||||
|
assert_eq!(comment, comment2, "comment mismatch");
|
||||||
|
}
|
||||||
|
(Ok((ECDSAPair::P384(pu2, pr2), comment2)), ECDSAPair::P384(pu,pr)) => {
|
||||||
|
assert_eq!(pu, pu2, "public key mismatch");
|
||||||
|
assert_eq!(pr, pr2, "public key mismatch");
|
||||||
|
assert_eq!(comment, comment2, "comment mismatch");
|
||||||
|
}
|
||||||
|
(Ok((ECDSAPair::P521(pu2, pr2), comment2)), ECDSAPair::P521(pu,pr)) => {
|
||||||
|
assert_eq!(pu, pu2, "public key mismatch");
|
||||||
|
assert_eq!(pr, pr2, "public key mismatch");
|
||||||
|
assert_eq!(comment, comment2, "comment mismatch");
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
assert!(false, "Failed to accurately re-parse key")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn ed25519_examples() {
|
||||||
|
let test_files = ["ed25519-1", "ed25519-2", "ed25519-3"];
|
||||||
|
|
||||||
|
for file in test_files.iter() {
|
||||||
|
let path = format!("testdata/ssh/{}",file);
|
||||||
|
match load_ssh_keyfile::<ED25519KeyPair,String>(path) {
|
||||||
|
Err(e) =>
|
||||||
|
assert!(false, "SSH ED25519 parse error: {:?}", e),
|
||||||
|
Ok((keypair,comment)) => {
|
||||||
|
// first see if this roundtrips
|
||||||
|
let buffer = vec![0,1,2,4,5,6,9];
|
||||||
|
let sig = keypair.private.sign(&buffer);
|
||||||
|
assert!(keypair.public.verify(&buffer, &sig));
|
||||||
|
match encode_ssh(&keypair, &comment) {
|
||||||
|
Err(e) =>
|
||||||
|
assert!(false, "SSH ED25519 encoding error: {:?}", e),
|
||||||
|
Ok(coded) => {
|
||||||
|
match decode_ssh(&coded) {
|
||||||
|
Err(e) =>
|
||||||
|
assert!(false, "SSSH ECDSA redecoding error: {:?}", e),
|
||||||
|
Ok((keypair2, comment2)) => {
|
||||||
|
let _ : ED25519KeyPair = keypair2;
|
||||||
|
assert_eq!(keypair.public, keypair2.public, "public key mismatch");
|
||||||
|
assert_eq!(keypair.private, keypair2.private, "public key mismatch");
|
||||||
|
assert_eq!(comment, comment2, "comment mismatch");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
201
src/ssh/rsa.rs
Normal file
201
src/ssh/rsa.rs
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
use cryptonum::unsigned::*;
|
||||||
|
use rsa::{RSAPair,RSAPublic,RSAPublicKey,RSAPrivate,RSAPrivateKey};
|
||||||
|
use std::io::{Read,Write};
|
||||||
|
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||||
|
use ssh::frame::*;
|
||||||
|
use ssh::SSHKey;
|
||||||
|
|
||||||
|
impl SSHKey for RSAPair {
|
||||||
|
fn valid_keytype(s: &str) -> bool {
|
||||||
|
(s == "ssh-rsa") || (s == "rsa")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>
|
||||||
|
{
|
||||||
|
let pubkey_type = parse_openssh_string(inp)?;
|
||||||
|
if !Self::valid_keytype(&pubkey_type) {
|
||||||
|
return Err(SSHKeyParseError::UnknownKeyType(pubkey_type));
|
||||||
|
}
|
||||||
|
// this peaks a little under the cover a bit (it'd be nice to pretend
|
||||||
|
// that we didn't know the number format was the same as the buffer
|
||||||
|
// one), but we need to infer what kind of key this is, and this appears
|
||||||
|
// to be the easiest / fastest way.
|
||||||
|
let mut ebuf = parse_openssh_buffer(inp)?;
|
||||||
|
let mut nbuf = parse_openssh_buffer(inp)?;
|
||||||
|
|
||||||
|
while ebuf[0] == 0 { ebuf.remove(0); }
|
||||||
|
while nbuf[0] == 0 { nbuf.remove(0); }
|
||||||
|
|
||||||
|
if nbuf.len() > (8192 / 8) {
|
||||||
|
let e = U15360::from_bytes(&ebuf);
|
||||||
|
let n = U15360::from_bytes(&nbuf);
|
||||||
|
Ok(RSAPublic::Key15360(RSAPublicKey::<U15360>::new(n, e)))
|
||||||
|
} else if nbuf.len() > (4096 / 8) {
|
||||||
|
let e = U8192::from_bytes(&ebuf);
|
||||||
|
let n = U8192::from_bytes(&nbuf);
|
||||||
|
Ok(RSAPublic::Key8192(RSAPublicKey::<U8192>::new(n, e)))
|
||||||
|
} else if nbuf.len() > (3072 / 8) {
|
||||||
|
let e = U4096::from_bytes(&ebuf);
|
||||||
|
let n = U4096::from_bytes(&nbuf);
|
||||||
|
Ok(RSAPublic::Key4096(RSAPublicKey::<U4096>::new(n, e)))
|
||||||
|
} else if nbuf.len() > (2048 / 8) {
|
||||||
|
let e = U3072::from_bytes(&ebuf);
|
||||||
|
let n = U3072::from_bytes(&nbuf);
|
||||||
|
Ok(RSAPublic::Key3072(RSAPublicKey::<U3072>::new(n, e)))
|
||||||
|
} else if nbuf.len() > (1024 / 8) {
|
||||||
|
let e = U2048::from_bytes(&ebuf);
|
||||||
|
let n = U2048::from_bytes(&nbuf);
|
||||||
|
Ok(RSAPublic::Key2048(RSAPublicKey::<U2048>::new(n, e)))
|
||||||
|
} else if nbuf.len() > (512 / 8) {
|
||||||
|
let e = U1024::from_bytes(&ebuf);
|
||||||
|
let n = U1024::from_bytes(&nbuf);
|
||||||
|
Ok(RSAPublic::Key1024(RSAPublicKey::<U1024>::new(n, e)))
|
||||||
|
} else {
|
||||||
|
let e = U512::from_bytes(&ebuf);
|
||||||
|
let n = U512::from_bytes(&nbuf);
|
||||||
|
Ok(RSAPublic::Key512(RSAPublicKey::<U512>::new(n, e)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>
|
||||||
|
{
|
||||||
|
let check1 = parse_openssh_u32(inp)?;
|
||||||
|
let check2 = parse_openssh_u32(inp)?;
|
||||||
|
if check1 != check2 {
|
||||||
|
return Err(SSHKeyParseError::PrivateKeyCorruption);
|
||||||
|
}
|
||||||
|
let privkey_type = parse_openssh_string(inp)?;
|
||||||
|
if !Self::valid_keytype(&privkey_type) {
|
||||||
|
return Err(SSHKeyParseError::InconsistentKeyTypes("ssh-rsa".to_string(), privkey_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
// See the comment in the public key section.
|
||||||
|
let mut nbuf = parse_openssh_buffer(inp)?;
|
||||||
|
let _ebuf = parse_openssh_buffer(inp)?;
|
||||||
|
let mut dbuf = parse_openssh_buffer(inp)?;
|
||||||
|
let _iqmp = parse_openssh_buffer(inp)?;
|
||||||
|
let _pbuf = parse_openssh_buffer(inp)?;
|
||||||
|
let _qbuf = parse_openssh_buffer(inp)?;
|
||||||
|
let comment = parse_openssh_string(inp)?;
|
||||||
|
for (idx,byte) in inp.bytes().enumerate() {
|
||||||
|
if ((idx+1) as u8) != byte? {
|
||||||
|
return Err(SSHKeyParseError::InvalidPadding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while dbuf[0] == 0 { dbuf.remove(0); }
|
||||||
|
while nbuf[0] == 0 { nbuf.remove(0); }
|
||||||
|
|
||||||
|
if nbuf.len() > (8192 / 8) {
|
||||||
|
let d = U15360::from_bytes(&dbuf);
|
||||||
|
let n = U15360::from_bytes(&nbuf);
|
||||||
|
Ok((RSAPrivate::Key15360(RSAPrivateKey::<U15360>::new(n, d)), comment))
|
||||||
|
} else if nbuf.len() > (4096 / 8) {
|
||||||
|
let d = U8192::from_bytes(&dbuf);
|
||||||
|
let n = U8192::from_bytes(&nbuf);
|
||||||
|
Ok((RSAPrivate::Key8192(RSAPrivateKey::<U8192>::new(n, d)), comment))
|
||||||
|
} else if nbuf.len() > (3072 / 8) {
|
||||||
|
let d = U4096::from_bytes(&dbuf);
|
||||||
|
let n = U4096::from_bytes(&nbuf);
|
||||||
|
Ok((RSAPrivate::Key4096(RSAPrivateKey::<U4096>::new(n, d)), comment))
|
||||||
|
} else if nbuf.len() > (2048 / 8) {
|
||||||
|
let d = U3072::from_bytes(&dbuf);
|
||||||
|
let n = U3072::from_bytes(&nbuf);
|
||||||
|
Ok((RSAPrivate::Key3072(RSAPrivateKey::<U3072>::new(n, d)), comment))
|
||||||
|
} else if nbuf.len() > (1024 / 8) {
|
||||||
|
let d = U2048::from_bytes(&dbuf);
|
||||||
|
let n = U2048::from_bytes(&nbuf);
|
||||||
|
Ok((RSAPrivate::Key2048(RSAPrivateKey::<U2048>::new(n, d)), comment))
|
||||||
|
} else if nbuf.len() > (512 / 8) {
|
||||||
|
let d = U1024::from_bytes(&dbuf);
|
||||||
|
let n = U1024::from_bytes(&nbuf);
|
||||||
|
Ok((RSAPrivate::Key1024(RSAPrivateKey::<U1024>::new(n, d)), comment))
|
||||||
|
} else {
|
||||||
|
let d = U512::from_bytes(&dbuf);
|
||||||
|
let n = U512::from_bytes(&nbuf);
|
||||||
|
Ok((RSAPrivate::Key512(RSAPrivateKey::<U512>::new(n, d)), comment))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||||
|
{
|
||||||
|
render_openssh_string(out, "ssh-rsa")?;
|
||||||
|
match self {
|
||||||
|
RSAPair::R512(pbl,_) => {
|
||||||
|
render_openssh_number(out, &pbl.e)?;
|
||||||
|
render_openssh_number(out, &pbl.n)?;
|
||||||
|
}
|
||||||
|
RSAPair::R1024(pbl,_) => {
|
||||||
|
render_openssh_number(out, &pbl.e)?;
|
||||||
|
render_openssh_number(out, &pbl.n)?;
|
||||||
|
}
|
||||||
|
RSAPair::R2048(pbl,_) => {
|
||||||
|
render_openssh_number(out, &pbl.e)?;
|
||||||
|
render_openssh_number(out, &pbl.n)?;
|
||||||
|
}
|
||||||
|
RSAPair::R3072(pbl,_) => {
|
||||||
|
render_openssh_number(out, &pbl.e)?;
|
||||||
|
render_openssh_number(out, &pbl.n)?;
|
||||||
|
}
|
||||||
|
RSAPair::R4096(pbl,_) => {
|
||||||
|
render_openssh_number(out, &pbl.e)?;
|
||||||
|
render_openssh_number(out, &pbl.n)?;
|
||||||
|
}
|
||||||
|
RSAPair::R8192(pbl,_) => {
|
||||||
|
render_openssh_number(out, &pbl.e)?;
|
||||||
|
render_openssh_number(out, &pbl.n)?;
|
||||||
|
}
|
||||||
|
RSAPair::R15360(pbl,_) => {
|
||||||
|
render_openssh_number(out, &pbl.e)?;
|
||||||
|
render_openssh_number(out, &pbl.n)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||||
|
{
|
||||||
|
render_openssh_string(out, "ssh-rsa")?;
|
||||||
|
match self {
|
||||||
|
RSAPair::R512(pbl,prv) => {
|
||||||
|
render_openssh_number(out, &pbl.n)?;
|
||||||
|
render_openssh_number(out, &pbl.e)?;
|
||||||
|
render_openssh_number(out, &prv.d)?;
|
||||||
|
}
|
||||||
|
RSAPair::R1024(pbl,prv) => {
|
||||||
|
render_openssh_number(out, &pbl.n)?;
|
||||||
|
render_openssh_number(out, &pbl.e)?;
|
||||||
|
render_openssh_number(out, &prv.d)?;
|
||||||
|
}
|
||||||
|
RSAPair::R2048(pbl,prv) => {
|
||||||
|
render_openssh_number(out, &pbl.n)?;
|
||||||
|
render_openssh_number(out, &pbl.e)?;
|
||||||
|
render_openssh_number(out, &prv.d)?;
|
||||||
|
}
|
||||||
|
RSAPair::R3072(pbl,prv) => {
|
||||||
|
render_openssh_number(out, &pbl.n)?;
|
||||||
|
render_openssh_number(out, &pbl.e)?;
|
||||||
|
render_openssh_number(out, &prv.d)?;
|
||||||
|
}
|
||||||
|
RSAPair::R4096(pbl,prv) => {
|
||||||
|
render_openssh_number(out, &pbl.n)?;
|
||||||
|
render_openssh_number(out, &pbl.e)?;
|
||||||
|
render_openssh_number(out, &prv.d)?;
|
||||||
|
}
|
||||||
|
RSAPair::R8192(pbl,prv) => {
|
||||||
|
render_openssh_number(out, &pbl.n)?;
|
||||||
|
render_openssh_number(out, &pbl.e)?;
|
||||||
|
render_openssh_number(out, &prv.d)?;
|
||||||
|
}
|
||||||
|
RSAPair::R15360(pbl,prv) => {
|
||||||
|
render_openssh_number(out, &pbl.n)?;
|
||||||
|
render_openssh_number(out, &pbl.e)?;
|
||||||
|
render_openssh_number(out, &prv.d)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* iqmp */ render_openssh_buffer(out, &vec![])?;
|
||||||
|
/* p */ render_openssh_buffer(out, &vec![])?;
|
||||||
|
/* q */ render_openssh_buffer(out, &vec![])?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,11 +23,11 @@ fn next_value_set(line: &str) -> (String, bool, Vec<u8>)
|
|||||||
while let Some(c1) = nibble_iter.next() {
|
while let Some(c1) = nibble_iter.next() {
|
||||||
match nibble_iter.next() {
|
match nibble_iter.next() {
|
||||||
None => {
|
None => {
|
||||||
val.push( c1.to_digit(16).unwrap() as u8 );
|
val.push( c1.to_digit(16).expect(&format!("Unexpected character: |{}|", c1)) as u8 );
|
||||||
}
|
}
|
||||||
Some(c2) => {
|
Some(c2) => {
|
||||||
let b1 = c1.to_digit(16).unwrap() as u8;
|
let b1 = c1.to_digit(16).expect(&format!("Unexpected character: |{}|", c1)) as u8;
|
||||||
let b2 = c2.to_digit(16).unwrap() as u8;
|
let b2 = c2.to_digit(16).expect(&format!("Unexpected character: |{}|", c2)) as u8;
|
||||||
val.push( (b2 << 4) | b1 );
|
val.push( (b2 << 4) | b1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,28 @@ use num::BigUint;
|
|||||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
|
||||||
use x509::error::X509ParseError;
|
use x509::error::X509ParseError;
|
||||||
|
|
||||||
|
/// A supported x509 hash algorithm
|
||||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||||
pub enum HashAlgorithm { SHA1, SHA224, SHA256, SHA384, SHA512 }
|
pub enum HashAlgorithm { SHA1, SHA224, SHA256, SHA384, SHA512 }
|
||||||
|
|
||||||
|
/// A supported x509 asymmetric crypto algorithm
|
||||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||||
pub enum PublicKeyInfo { RSA, DSA, ECDSA }
|
pub enum PublicKeyInfo { RSA, DSA, ECDSA }
|
||||||
|
|
||||||
|
/// The algorithm used, either in a certificate or as part of the signing
|
||||||
|
/// process. We only actually support a subset of the possible values,
|
||||||
|
/// here, although we try to catch them all.
|
||||||
|
///
|
||||||
|
/// Specifically, this library supports:
|
||||||
|
///
|
||||||
|
/// | | *RSA* | *DSA* | *ECDSA* |
|
||||||
|
/// |----------|-------|-------|---------|
|
||||||
|
/// | *SHA1* | X | X | X |
|
||||||
|
/// | *SHA224* | X | X | X |
|
||||||
|
/// | *SHA256* | X | X | X |
|
||||||
|
/// | *SHA384* | X | | X |
|
||||||
|
/// | *SHA512* | X | | X |
|
||||||
|
///
|
||||||
#[derive(Clone,Debug,PartialEq)]
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
pub struct AlgorithmIdentifier {
|
pub struct AlgorithmIdentifier {
|
||||||
pub hash: HashAlgorithm,
|
pub hash: HashAlgorithm,
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
use x509::error::X509ParseError;
|
use x509::error::X509ParseError;
|
||||||
use x509::name::X520Name;
|
pub use x509::name::X520Name;
|
||||||
|
|
||||||
|
/// All of the various bits of information that are encoded within an x.509
|
||||||
|
/// certificate.
|
||||||
#[derive(Clone,Debug)]
|
#[derive(Clone,Debug)]
|
||||||
pub struct InfoBlock {
|
pub struct InfoBlock {
|
||||||
fields: Vec<AttributeTypeValue>
|
pub fields: Vec<AttributeTypeValue>
|
||||||
}
|
}
|
||||||
|
|
||||||
const EMPTY_STRING: &'static str = "";
|
const EMPTY_STRING: &'static str = "";
|
||||||
@@ -116,11 +118,11 @@ impl ToASN1 for InfoBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An attribute within an x.509 key and its associated string value.
|
||||||
#[derive(Clone,Debug,PartialEq)]
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
struct AttributeTypeValue {
|
pub struct AttributeTypeValue {
|
||||||
attrtype: X520Name,
|
pub attrtype: X520Name,
|
||||||
value: String
|
pub value: String
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_attribute_type_value(x: &ASN1Block)
|
fn decode_attribute_type_value(x: &ASN1Block)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use num::bigint::ToBigInt;
|
|||||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
||||||
use x509::error::X509ParseError;
|
use x509::error::X509ParseError;
|
||||||
|
|
||||||
|
/// Which version of x.509 certificate this is.
|
||||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||||
pub enum X509Version { V1, V2, V3 }
|
pub enum X509Version { V1, V2, V3 }
|
||||||
|
|
||||||
@@ -65,6 +66,7 @@ impl ToASN1 for X509Version {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/// The serial number for this certificate.
|
||||||
#[derive(Clone,Debug,PartialEq)]
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
pub struct X509Serial {
|
pub struct X509Serial {
|
||||||
num: BigUint
|
num: BigUint
|
||||||
|
|||||||
106
src/x509/mod.rs
106
src/x509/mod.rs
@@ -6,19 +6,19 @@ mod name;
|
|||||||
mod publickey;
|
mod publickey;
|
||||||
mod validity;
|
mod validity;
|
||||||
|
|
||||||
use dsa::{DSAPublic,DSAPublicKey};
|
use dsa::DSAPublic;
|
||||||
use ecdsa::{ECDSAPublic,ECCPublicKey};
|
use ecdsa::ECDSAPublic;
|
||||||
use rsa::{SIGNING_HASH_SHA1,SIGNING_HASH_SHA224,SIGNING_HASH_SHA256,SIGNING_HASH_SHA384,SIGNING_HASH_SHA512};
|
use rsa::{SIGNING_HASH_SHA1,SIGNING_HASH_SHA224,SIGNING_HASH_SHA256,SIGNING_HASH_SHA384,SIGNING_HASH_SHA512};
|
||||||
use sha1::Sha1;
|
use sha::{SHA1,SHA224,SHA256,SHA384,SHA512};
|
||||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
|
||||||
use simple_asn1::{ASN1Block,FromASN1,der_decode,from_der};
|
use simple_asn1::{ASN1Block,FromASN1,der_decode,from_der};
|
||||||
use x509::validity::Validity;
|
pub use x509::validity::Validity;
|
||||||
use x509::algident::{AlgorithmIdentifier,HashAlgorithm,PublicKeyInfo,
|
pub use x509::algident::{AlgorithmIdentifier,HashAlgorithm,PublicKeyInfo};
|
||||||
decode_algorithm_ident};
|
use x509::algident::{decode_algorithm_ident};
|
||||||
use x509::atv::InfoBlock;
|
pub use x509::atv::InfoBlock;
|
||||||
use x509::error::X509ParseError;
|
use x509::error::X509ParseError;
|
||||||
use x509::misc::{X509Serial,X509Version,decode_signature};
|
pub use x509::misc::{X509Serial,X509Version};
|
||||||
use x509::publickey::X509PublicKey;
|
use x509::misc::{decode_signature};
|
||||||
|
pub use x509::publickey::X509PublicKey;
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
*
|
*
|
||||||
@@ -88,6 +88,8 @@ fn decode_certificate(x: &ASN1Block)
|
|||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
/// Parse an X.590 certificate in memory into a generic certificate that can
|
||||||
|
/// be used by a program.
|
||||||
pub fn parse_x509(buffer: &[u8]) -> Result<GenericCertificate,X509ParseError> {
|
pub fn parse_x509(buffer: &[u8]) -> Result<GenericCertificate,X509ParseError> {
|
||||||
let blocks = from_der(&buffer[..])?;
|
let blocks = from_der(&buffer[..])?;
|
||||||
match blocks.first() {
|
match blocks.first() {
|
||||||
@@ -134,10 +136,10 @@ fn check_signature(alg: &AlgorithmIdentifier,
|
|||||||
let dsa_sig = der_decode(&sig)?;
|
let dsa_sig = der_decode(&sig)?;
|
||||||
match alg.hash {
|
match alg.hash {
|
||||||
HashAlgorithm::SHA1
|
HashAlgorithm::SHA1
|
||||||
if key.verify::<Sha1>(block, &dsa_sig) => Ok(()),
|
if key.verify::<SHA1>(block, &dsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA224
|
HashAlgorithm::SHA224
|
||||||
if key.verify::<Sha224>(block, &dsa_sig) => Ok(()),
|
if key.verify::<SHA224>(block, &dsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &dsa_sig) =>
|
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &dsa_sig) =>
|
||||||
Ok(()),
|
Ok(()),
|
||||||
_ =>
|
_ =>
|
||||||
Err(X509ParseError::InvalidSignatureHash)
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
@@ -147,10 +149,10 @@ fn check_signature(alg: &AlgorithmIdentifier,
|
|||||||
let dsa_sig = der_decode(&sig)?;
|
let dsa_sig = der_decode(&sig)?;
|
||||||
match alg.hash {
|
match alg.hash {
|
||||||
HashAlgorithm::SHA1
|
HashAlgorithm::SHA1
|
||||||
if key.verify::<Sha1>(block, &dsa_sig) => Ok(()),
|
if key.verify::<SHA1>(block, &dsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA224
|
HashAlgorithm::SHA224
|
||||||
if key.verify::<Sha224>(block, &dsa_sig) => Ok(()),
|
if key.verify::<SHA224>(block, &dsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &dsa_sig) =>
|
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &dsa_sig) =>
|
||||||
Ok(()),
|
Ok(()),
|
||||||
_ =>
|
_ =>
|
||||||
Err(X509ParseError::InvalidSignatureHash)
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
@@ -160,10 +162,10 @@ fn check_signature(alg: &AlgorithmIdentifier,
|
|||||||
let dsa_sig = der_decode(&sig)?;
|
let dsa_sig = der_decode(&sig)?;
|
||||||
match alg.hash {
|
match alg.hash {
|
||||||
HashAlgorithm::SHA1
|
HashAlgorithm::SHA1
|
||||||
if key.verify::<Sha1>(block, &dsa_sig) => Ok(()),
|
if key.verify::<SHA1>(block, &dsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA224
|
HashAlgorithm::SHA224
|
||||||
if key.verify::<Sha224>(block, &dsa_sig) => Ok(()),
|
if key.verify::<SHA224>(block, &dsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &dsa_sig) =>
|
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &dsa_sig) =>
|
||||||
Ok(()),
|
Ok(()),
|
||||||
_ =>
|
_ =>
|
||||||
Err(X509ParseError::InvalidSignatureHash)
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
@@ -173,71 +175,71 @@ fn check_signature(alg: &AlgorithmIdentifier,
|
|||||||
let dsa_sig = der_decode(&sig)?;
|
let dsa_sig = der_decode(&sig)?;
|
||||||
match alg.hash {
|
match alg.hash {
|
||||||
HashAlgorithm::SHA1
|
HashAlgorithm::SHA1
|
||||||
if key.verify::<Sha1>(block, &dsa_sig) => Ok(()),
|
if key.verify::<SHA1>(block, &dsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA224
|
HashAlgorithm::SHA224
|
||||||
if key.verify::<Sha224>(block, &dsa_sig) => Ok(()),
|
if key.verify::<SHA224>(block, &dsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA256 if key.verify::<Sha256>(block, &dsa_sig) =>
|
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &dsa_sig) =>
|
||||||
Ok(()),
|
Ok(()),
|
||||||
_ =>
|
_ =>
|
||||||
Err(X509ParseError::InvalidSignatureHash)
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP192(ref key))) => {
|
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P192(ref key))) => {
|
||||||
let ecdsa_sig = der_decode(&sig)?;
|
let ecdsa_sig = der_decode(&sig)?;
|
||||||
match alg.hash {
|
match alg.hash {
|
||||||
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA224 if key.verify::<Sha224>(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::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
|
||||||
_ =>
|
_ =>
|
||||||
Err(X509ParseError::InvalidSignatureHash)
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP224(ref key))) => {
|
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P224(ref key))) => {
|
||||||
let ecdsa_sig = der_decode(&sig)?;
|
let ecdsa_sig = der_decode(&sig)?;
|
||||||
match alg.hash {
|
match alg.hash {
|
||||||
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA224 if key.verify::<Sha224>(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::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
|
||||||
_ =>
|
_ =>
|
||||||
Err(X509ParseError::InvalidSignatureHash)
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP256(ref key))) => {
|
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P256(ref key))) => {
|
||||||
let ecdsa_sig = der_decode(&sig)?;
|
let ecdsa_sig = der_decode(&sig)?;
|
||||||
match alg.hash {
|
match alg.hash {
|
||||||
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA224 if key.verify::<Sha224>(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::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
|
||||||
_ =>
|
_ =>
|
||||||
Err(X509ParseError::InvalidSignatureHash)
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP384(ref key))) => {
|
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P384(ref key))) => {
|
||||||
let ecdsa_sig = der_decode(&sig)?;
|
let ecdsa_sig = der_decode(&sig)?;
|
||||||
match alg.hash {
|
match alg.hash {
|
||||||
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA224 if key.verify::<Sha224>(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::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
|
||||||
_ =>
|
_ =>
|
||||||
Err(X509ParseError::InvalidSignatureHash)
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::ECCPublicP521(ref key))) => {
|
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P521(ref key))) => {
|
||||||
let ecdsa_sig = der_decode(&sig)?;
|
let ecdsa_sig = der_decode(&sig)?;
|
||||||
match alg.hash {
|
match alg.hash {
|
||||||
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA224 if key.verify::<Sha224>(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::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA384 if key.verify::<Sha384>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
|
||||||
HashAlgorithm::SHA512 if key.verify::<Sha512>(block, &ecdsa_sig) => Ok(()),
|
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
|
||||||
_ =>
|
_ =>
|
||||||
Err(X509ParseError::InvalidSignatureHash)
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ use num::BigUint;
|
|||||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
|
||||||
use x509::error::X509ParseError;
|
use x509::error::X509ParseError;
|
||||||
|
|
||||||
|
/// One of the various attributes that can be encoded within an x.509 name. To
|
||||||
|
/// see one of these paired with its value, consider `AttributeTypeValue`.
|
||||||
#[derive(Copy,Clone,Debug,Eq,Hash,PartialEq)]
|
#[derive(Copy,Clone,Debug,Eq,Hash,PartialEq)]
|
||||||
pub enum X520Name {
|
pub enum X520Name {
|
||||||
Name, Surname, GivenName, Initials, GenerationQualifier, CommonName,
|
Name, Surname, GivenName, Initials, GenerationQualifier, CommonName,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use cryptonum::unsigned::{U3072,U2048,U1024,U256,U192};
|
use cryptonum::unsigned::{U3072,U2048,U1024,U256,U192};
|
||||||
use dsa::{DSAPublic,DSAPublicKey,DSAPubKey,DSAParameters};
|
use dsa::{DSAPublic,DSAPublicKey,DSAParameters};
|
||||||
use dsa::{L3072N256,L2048N256,L2048N224,L1024N160};
|
use dsa::{L3072N256,L2048N256,L2048N224,L1024N160};
|
||||||
use ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPubKey};
|
use ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPublicKey};
|
||||||
use ecdsa::curve::{P192,P224,P256,P384,P521};
|
use ecdsa::{P192,P224,P256,P384,P521};
|
||||||
use num::BigUint;
|
use num::BigUint;
|
||||||
use rsa::RSAPublic;
|
use rsa::RSAPublic;
|
||||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1,
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1,
|
||||||
@@ -10,6 +10,8 @@ use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1,
|
|||||||
use utils::TranslateNums;
|
use utils::TranslateNums;
|
||||||
use x509::error::X509ParseError;
|
use x509::error::X509ParseError;
|
||||||
|
|
||||||
|
/// A general type that includes all the supported public key types that we
|
||||||
|
/// could read in an x.509 certificate.
|
||||||
pub enum X509PublicKey {
|
pub enum X509PublicKey {
|
||||||
DSA(DSAPublic),
|
DSA(DSAPublic),
|
||||||
RSA(RSAPublic),
|
RSA(RSAPublic),
|
||||||
@@ -174,7 +176,7 @@ fn decode_dsa_key(info: ASN1Block, key: &ASN1Block) -> Result<DSAPublic,X509Pars
|
|||||||
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||||
let y = U3072::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
let y = U3072::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
let key = DSAPubKey::<L3072N256,U3072>::new(params, y);
|
let key = DSAPublicKey::<L3072N256>::new(params, y);
|
||||||
let reskey = DSAPublic::DSAPublicL3072N256(key);
|
let reskey = DSAPublic::DSAPublicL3072N256(key);
|
||||||
return Ok(reskey);
|
return Ok(reskey);
|
||||||
}
|
}
|
||||||
@@ -195,7 +197,7 @@ fn decode_dsa_key(info: ASN1Block, key: &ASN1Block) -> Result<DSAPublic,X509Pars
|
|||||||
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||||
let y = U2048::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
let y = U2048::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
let key = DSAPubKey::<L2048N256,U2048>::new(params, y);
|
let key = DSAPublicKey::<L2048N256>::new(params, y);
|
||||||
let reskey = DSAPublic::DSAPublicL2048N256(key);
|
let reskey = DSAPublic::DSAPublicL2048N256(key);
|
||||||
return Ok(reskey);
|
return Ok(reskey);
|
||||||
}
|
}
|
||||||
@@ -213,7 +215,7 @@ fn decode_dsa_key(info: ASN1Block, key: &ASN1Block) -> Result<DSAPublic,X509Pars
|
|||||||
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||||
let y = U2048::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
let y = U2048::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
let key = DSAPubKey::<L2048N224,U2048>::new(params, y);
|
let key = DSAPublicKey::<L2048N224>::new(params, y);
|
||||||
let reskey = DSAPublic::DSAPublicL2048N224(key);
|
let reskey = DSAPublic::DSAPublicL2048N224(key);
|
||||||
return Ok(reskey);
|
return Ok(reskey);
|
||||||
}
|
}
|
||||||
@@ -233,7 +235,7 @@ fn decode_dsa_key(info: ASN1Block, key: &ASN1Block) -> Result<DSAPublic,X509Pars
|
|||||||
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||||
let y = U1024::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
let y = U1024::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||||
let key = DSAPubKey::<L1024N160,U1024>::new(params, y);
|
let key = DSAPublicKey::<L1024N160>::new(params, y);
|
||||||
let reskey = DSAPublic::DSAPublicL1024N160(key);
|
let reskey = DSAPublic::DSAPublicL1024N160(key);
|
||||||
return Ok(reskey);
|
return Ok(reskey);
|
||||||
}
|
}
|
||||||
@@ -255,11 +257,11 @@ fn encode_ecdsa_key(c: ASN1Class, x: &ECDSAPublic) -> Result<ASN1Block,ECDSAEnco
|
|||||||
{
|
{
|
||||||
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,10045,2,1));
|
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,10045,2,1));
|
||||||
let (base_curve_oid, mut keyvec) = match x {
|
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::P192(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::P224(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::P256(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::P384(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)?),
|
ECDSAPublic::P521(k) => (oid!(1,3,132,0,35), k.to_asn1_class(c)?),
|
||||||
};
|
};
|
||||||
let curve_oid = ASN1Block::ObjectIdentifier(c, 0, base_curve_oid);
|
let curve_oid = ASN1Block::ObjectIdentifier(c, 0, base_curve_oid);
|
||||||
let header = ASN1Block::Sequence(c, 0, vec![objoid, curve_oid]);
|
let header = ASN1Block::Sequence(c, 0, vec![objoid, curve_oid]);
|
||||||
@@ -271,28 +273,28 @@ fn decode_ecdsa_key(info: ASN1Block, keybls: &[ASN1Block]) -> Result<ECDSAPublic
|
|||||||
{
|
{
|
||||||
if let ASN1Block::ObjectIdentifier(_, _, oid) = info {
|
if let ASN1Block::ObjectIdentifier(_, _, oid) = info {
|
||||||
if oid == oid!(1,2,840,10045,3,1,1) {
|
if oid == oid!(1,2,840,10045,3,1,1) {
|
||||||
let (res, _) = ECCPubKey::<P192>::from_asn1(keybls)?;
|
let (res, _) = ECCPublicKey::<P192>::from_asn1(keybls)?;
|
||||||
return Ok(ECDSAPublic::ECCPublicP192(res));
|
return Ok(ECDSAPublic::P192(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
if oid == oid!(1,3,132,0,33) {
|
if oid == oid!(1,3,132,0,33) {
|
||||||
let (res, _) = ECCPubKey::<P224>::from_asn1(keybls)?;
|
let (res, _) = ECCPublicKey::<P224>::from_asn1(keybls)?;
|
||||||
return Ok(ECDSAPublic::ECCPublicP224(res));
|
return Ok(ECDSAPublic::P224(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
if oid == oid!(1,2,840,10045,3,1,7) {
|
if oid == oid!(1,2,840,10045,3,1,7) {
|
||||||
let (res, _) = ECCPubKey::<P256>::from_asn1(keybls)?;
|
let (res, _) = ECCPublicKey::<P256>::from_asn1(keybls)?;
|
||||||
return Ok(ECDSAPublic::ECCPublicP256(res));
|
return Ok(ECDSAPublic::P256(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
if oid == oid!(1,3,132,0,34) {
|
if oid == oid!(1,3,132,0,34) {
|
||||||
let (res, _) = ECCPubKey::<P384>::from_asn1(keybls)?;
|
let (res, _) = ECCPublicKey::<P384>::from_asn1(keybls)?;
|
||||||
return Ok(ECDSAPublic::ECCPublicP384(res));
|
return Ok(ECDSAPublic::P384(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
if oid == oid!(1,3,132,0,35) {
|
if oid == oid!(1,3,132,0,35) {
|
||||||
let (res, _) = ECCPubKey::<P521>::from_asn1(keybls)?;
|
let (res, _) = ECCPublicKey::<P521>::from_asn1(keybls)?;
|
||||||
return Ok(ECDSAPublic::ECCPublicP521(res));
|
return Ok(ECDSAPublic::P521(res));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ use chrono::{DateTime,Utc};
|
|||||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
||||||
use x509::error::X509ParseError;
|
use x509::error::X509ParseError;
|
||||||
|
|
||||||
|
/// The range of dates in which this certificate is valid.
|
||||||
#[derive(Clone,Debug,PartialEq)]
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
pub struct Validity {
|
pub struct Validity {
|
||||||
not_before: DateTime<Utc>,
|
pub not_before: DateTime<Utc>,
|
||||||
not_after: DateTime<Utc>
|
pub not_after: DateTime<Utc>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_validity_data(bs: &ASN1Block) -> Result<Validity,X509ParseError> {
|
fn decode_validity_data(bs: &ASN1Block) -> Result<Validity,X509ParseError> {
|
||||||
|
|||||||
@@ -11,11 +11,9 @@ import Data.ByteString.Lazy(ByteString)
|
|||||||
import qualified Data.ByteString.Lazy as BSL
|
import qualified Data.ByteString.Lazy as BSL
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import Math(showX,showBin)
|
import Math(showX,showBin)
|
||||||
import Task(Task(..),Test)
|
import Task(Task(..),liftTest)
|
||||||
import Utils(HashAlg(..),generateHash,showHash)
|
import Utils(HashAlg(..),generateHash,showHash)
|
||||||
|
|
||||||
import Debug.Trace
|
|
||||||
|
|
||||||
dsaSizes :: [(ParameterSizes, Int)]
|
dsaSizes :: [(ParameterSizes, Int)]
|
||||||
dsaSizes = [(L1024_N160, 400),
|
dsaSizes = [(L1024_N160, 400),
|
||||||
(L2048_N224, 100),
|
(L2048_N224, 100),
|
||||||
@@ -38,27 +36,26 @@ signTest :: ParameterSizes -> Int -> Task
|
|||||||
signTest sz cnt = Task {
|
signTest sz cnt = Task {
|
||||||
taskName = "DSA " ++ show sz ++ " signing",
|
taskName = "DSA " ++ show sz ++ " signing",
|
||||||
taskFile = "../testdata/dsa/sign" ++ showParam sz ++ ".test",
|
taskFile = "../testdata/dsa/sign" ++ showParam sz ++ ".test",
|
||||||
taskTest = go,
|
taskTest = liftTest go,
|
||||||
taskCount = cnt
|
taskCount = cnt
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
go :: Test
|
|
||||||
go (memory, drg0) =
|
go (memory, drg0) =
|
||||||
case generateProbablePrimes sz drg0 sha256 Nothing of
|
case generateProbablePrimes sz drg0 sha256 Nothing of
|
||||||
Left _ -> trace "generate primes" $ goAdvance memory drg0
|
Left _ -> goAdvance memory drg0
|
||||||
Right (p, q, _, drg1) ->
|
Right (p, q, _, drg1) ->
|
||||||
case generateUnverifiableGenerator p q of
|
case generateUnverifiableGenerator p q of
|
||||||
Nothing -> trace "generate g" $ goAdvance memory drg1
|
Nothing -> goAdvance memory drg1
|
||||||
Just g ->
|
Just g ->
|
||||||
let params = Params p g q
|
let params = Params p g q
|
||||||
in case generateKeyPairWithParams params drg1 of
|
in case generateKeyPairWithParams params drg1 of
|
||||||
Left _ -> trace "generate key" $ goAdvance memory drg1
|
Left _ -> goAdvance memory drg1
|
||||||
Right (pub, priv, drg2) ->
|
Right (pub, priv, drg2) ->
|
||||||
let (msg, drg3) = withDRG drg2 $ getRandomBytes =<< ((fromIntegral . BS.head) `fmap` getRandomBytes 1)
|
let (msg, drg3) = withDRG drg2 $ getRandomBytes =<< ((fromIntegral . BS.head) `fmap` getRandomBytes 1)
|
||||||
(hashf, drg4) = withDRG drg3 generateHash
|
(hashf, drg4) = withDRG drg3 generateHash
|
||||||
in case signMessage' (translateHash hashf) kViaRFC6979 drg4 priv (BSL.fromStrict msg) of
|
in case signMessage' (translateHash hashf) kViaRFC6979 drg4 priv (BSL.fromStrict msg) of
|
||||||
Left _ ->
|
Left _ ->
|
||||||
trace "sign failure" $ go (memory, drg4)
|
go (memory, drg4)
|
||||||
Right (sig, drg5) ->
|
Right (sig, drg5) ->
|
||||||
let res = Map.fromList [("p", showX p),
|
let res = Map.fromList [("p", showX p),
|
||||||
("q", showX q),
|
("q", showX q),
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import qualified Data.ByteString as S
|
|||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import Math(showX,showBin)
|
import Math(showX,showBin)
|
||||||
import RFC6979(generateKStream)
|
import RFC6979(generateKStream)
|
||||||
import Task(Task(..))
|
import Task(Task(..),liftTest)
|
||||||
import Utils(HashAlg(..),generateHash,runHash,showHash)
|
import Utils(HashAlg(..),generateHash,runHash,showHash)
|
||||||
|
|
||||||
curves :: [(String, Curve)]
|
curves :: [(String, Curve)]
|
||||||
@@ -29,7 +29,7 @@ negateTest :: String -> Curve -> Task
|
|||||||
negateTest name curve = Task {
|
negateTest name curve = Task {
|
||||||
taskName = name ++ " point negation",
|
taskName = name ++ " point negation",
|
||||||
taskFile = "../testdata/ecc/negate/" ++ name ++ ".test",
|
taskFile = "../testdata/ecc/negate/" ++ name ++ ".test",
|
||||||
taskTest = go,
|
taskTest = liftTest go,
|
||||||
taskCount = 1000
|
taskCount = 1000
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
@@ -49,7 +49,7 @@ doubleTest :: String -> Curve -> Task
|
|||||||
doubleTest name curve = Task {
|
doubleTest name curve = Task {
|
||||||
taskName = name ++ " point doubling",
|
taskName = name ++ " point doubling",
|
||||||
taskFile = "../testdata/ecc/double/" ++ name ++ ".test",
|
taskFile = "../testdata/ecc/double/" ++ name ++ ".test",
|
||||||
taskTest = go,
|
taskTest = liftTest go,
|
||||||
taskCount = 1000
|
taskCount = 1000
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
@@ -69,7 +69,7 @@ addTest :: String -> Curve -> Task
|
|||||||
addTest name curve = Task {
|
addTest name curve = Task {
|
||||||
taskName = name ++ " point addition",
|
taskName = name ++ " point addition",
|
||||||
taskFile = "../testdata/ecc/add/" ++ name ++ ".test",
|
taskFile = "../testdata/ecc/add/" ++ name ++ ".test",
|
||||||
taskTest = go,
|
taskTest = liftTest go,
|
||||||
taskCount = 1000
|
taskCount = 1000
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
@@ -92,7 +92,7 @@ scaleTest :: String -> Curve -> Task
|
|||||||
scaleTest name curve = Task {
|
scaleTest name curve = Task {
|
||||||
taskName = name ++ " point scaling",
|
taskName = name ++ " point scaling",
|
||||||
taskFile = "../testdata/ecc/scale/" ++ name ++ ".test",
|
taskFile = "../testdata/ecc/scale/" ++ name ++ ".test",
|
||||||
taskTest = go,
|
taskTest = liftTest go,
|
||||||
taskCount = 1000
|
taskCount = 1000
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
@@ -117,7 +117,7 @@ addScaleTest :: String -> Curve -> Task
|
|||||||
addScaleTest name curve = Task {
|
addScaleTest name curve = Task {
|
||||||
taskName = name ++ " point addition of two scalings",
|
taskName = name ++ " point addition of two scalings",
|
||||||
taskFile = "../testdata/ecc/add_scale2/" ++ name ++ ".test",
|
taskFile = "../testdata/ecc/add_scale2/" ++ name ++ ".test",
|
||||||
taskTest = go,
|
taskTest = liftTest go,
|
||||||
taskCount = 1000
|
taskCount = 1000
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
@@ -144,7 +144,7 @@ signTest :: String -> Curve -> Task
|
|||||||
signTest name curve = Task {
|
signTest name curve = Task {
|
||||||
taskName = name ++ " curve signing",
|
taskName = name ++ " curve signing",
|
||||||
taskFile = "../testdata/ecc/sign/" ++ name ++ ".test",
|
taskFile = "../testdata/ecc/sign/" ++ name ++ ".test",
|
||||||
taskTest = go,
|
taskTest = liftTest go,
|
||||||
taskCount = 1000
|
taskCount = 1000
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
|
|||||||
735
test-generator/ED25519.hs
Normal file
735
test-generator/ED25519.hs
Normal file
@@ -0,0 +1,735 @@
|
|||||||
|
{-# LANGUAGE PackageImports #-}
|
||||||
|
module ED25519(ed25519Tasks)
|
||||||
|
where
|
||||||
|
|
||||||
|
import Control.Monad(unless)
|
||||||
|
import Crypto.Error(CryptoFailable(CryptoPassed))
|
||||||
|
import "crypto-api" Crypto.Random(SystemRandom)
|
||||||
|
import "cryptonite" Crypto.Random(getRandomBytes,withDRG)
|
||||||
|
import Crypto.PubKey.Ed25519
|
||||||
|
import Data.ByteArray(convert)
|
||||||
|
import Data.ByteString(ByteString,pack,useAsCString)
|
||||||
|
import qualified Data.ByteString as BS
|
||||||
|
import Data.Int(Int32)
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
import Data.Word(Word8,Word32,Word64)
|
||||||
|
import ED25519.PrecompPoints
|
||||||
|
import Foreign.C.Types(CChar)
|
||||||
|
import Foreign.Marshal.Alloc(alloca)
|
||||||
|
import Foreign.Marshal.Array(allocaArray,peekArray,pokeArray)
|
||||||
|
import Foreign.Ptr(Ptr,castPtr)
|
||||||
|
import Foreign.Storable(Storable(..))
|
||||||
|
import Math(showX,showBin)
|
||||||
|
import Task(Task(..))
|
||||||
|
|
||||||
|
cTEST_COUNT :: Int
|
||||||
|
cTEST_COUNT = 1000
|
||||||
|
|
||||||
|
ed25519Tasks :: [Task]
|
||||||
|
ed25519Tasks = [ loadTests, byteTests, addsubTests, mulTests,
|
||||||
|
squaringTests, inversionTests, negateTests,
|
||||||
|
cmovTests, isTests, square2Tests,
|
||||||
|
pow22523Tests, fbvTests, conversionTests,
|
||||||
|
ptDoubleTests, maddsubTests, ptAddSubTests,
|
||||||
|
scalarMultBaseTests, slideTests, scalarMultTests,
|
||||||
|
reduceTests, muladdTests, pubPrivTests,
|
||||||
|
signTest ]
|
||||||
|
|
||||||
|
loadTests :: Task
|
||||||
|
loadTests = Task {
|
||||||
|
taskName = "ed25519 byte loading",
|
||||||
|
taskFile = "../testdata/ed25519/load.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
do let (bytes, drg1) = withDRG drg0 (getRandomBytes 4)
|
||||||
|
res3 <- useAsCString bytes (\ptr -> load_3 ptr)
|
||||||
|
res4 <- useAsCString bytes (\ptr -> load_4 ptr)
|
||||||
|
let res = Map.fromList [("x", showBin bytes), ("a", showX res3), ("b", showX res4)]
|
||||||
|
return (res, fromIntegral res4, (memory0, drg1))
|
||||||
|
|
||||||
|
byteTests :: Task
|
||||||
|
byteTests = Task {
|
||||||
|
taskName = "ed25519 byte / element conversion",
|
||||||
|
taskFile = "../testdata/ed25519/bytes.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomPackedBytes drg0 $ \ ptra drg1 ->
|
||||||
|
alloca $ \ ptrc ->
|
||||||
|
allocaArray 32 $ \ rptr ->
|
||||||
|
do clearSpace ptrc
|
||||||
|
pokeArray (rptr :: Ptr Word8) (replicate 32 0)
|
||||||
|
fe_frombytes ptrc ptra
|
||||||
|
b <- convertFE ptrc
|
||||||
|
fe_tobytes (castPtr rptr) ptrc
|
||||||
|
start <- peek ptra
|
||||||
|
end <- peek (castPtr rptr)
|
||||||
|
unless (start == end) $
|
||||||
|
fail "field element tobytes/frombytes doesn't round trip"
|
||||||
|
bytes' <- pack `fmap` peekArray 32 (castPtr ptra :: Ptr Word8)
|
||||||
|
let res = Map.fromList [("a", showBin bytes'),
|
||||||
|
("b", showBin b)]
|
||||||
|
return (res, toNumber b, (memory0, drg1))
|
||||||
|
|
||||||
|
addsubTests :: Task
|
||||||
|
addsubTests = Task {
|
||||||
|
taskName = "ed25519 addition/subtraction tests",
|
||||||
|
taskFile = "../testdata/ed25519/addsub.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomElement drg0 $ \ ptrel1 drg1 ->
|
||||||
|
randomElement drg1 $ \ ptrel2 drg2 ->
|
||||||
|
alloca $ \ ptrc ->
|
||||||
|
alloca $ \ ptrd ->
|
||||||
|
do fe_add ptrc ptrel1 ptrel2
|
||||||
|
fe_sub ptrd ptrel1 ptrel2
|
||||||
|
[a, b, c, d] <- mapM convertFE [ptrel1, ptrel2, ptrc, ptrd]
|
||||||
|
let res = Map.fromList [("a", showBin a),
|
||||||
|
("b", showBin b),
|
||||||
|
("c", showBin c),
|
||||||
|
("d", showBin d)]
|
||||||
|
return (res, toNumber c, (memory0, drg2))
|
||||||
|
|
||||||
|
mulTests :: Task
|
||||||
|
mulTests = Task {
|
||||||
|
taskName = "ed25519 multiplication tests",
|
||||||
|
taskFile = "../testdata/ed25519/mul.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomElement drg0 $ \ ptrel1 drg1 ->
|
||||||
|
randomElement drg1 $ \ ptrel2 drg2 ->
|
||||||
|
alloca $ \ ptrc ->
|
||||||
|
do fe_mul ptrc ptrel1 ptrel2
|
||||||
|
[a, b, c] <- mapM convertFE [ptrel1, ptrel2, ptrc]
|
||||||
|
let res = Map.fromList [("a", showBin a),
|
||||||
|
("b", showBin b),
|
||||||
|
("c", showBin c)]
|
||||||
|
return (res, toNumber c, (memory0, drg2))
|
||||||
|
|
||||||
|
squaringTests :: Task
|
||||||
|
squaringTests = Task {
|
||||||
|
taskName = "ed25519 squaring tests",
|
||||||
|
taskFile = "../testdata/ed25519/square.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomElement drg0 $ \ ptrel drg1 ->
|
||||||
|
alloca $ \ ptrc ->
|
||||||
|
do fe_square ptrc ptrel
|
||||||
|
[a, c] <- mapM convertFE [ptrel, ptrc]
|
||||||
|
let res = Map.fromList [("a", showBin a),
|
||||||
|
("c", showBin c)]
|
||||||
|
return (res, toNumber c, (memory0, drg1))
|
||||||
|
|
||||||
|
inversionTests :: Task
|
||||||
|
inversionTests = Task {
|
||||||
|
taskName = "ed25519 inversion tests",
|
||||||
|
taskFile = "../testdata/ed25519/invert.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomElement drg0 $ \ ptrel drg1 ->
|
||||||
|
alloca $ \ ptrc ->
|
||||||
|
do fe_invert ptrc ptrel
|
||||||
|
a <- convertFE ptrel
|
||||||
|
c <- convertFE ptrc
|
||||||
|
let res = Map.fromList [("a", showBin a),
|
||||||
|
("c", showBin c)]
|
||||||
|
return (res, toNumber a, (memory0, drg1))
|
||||||
|
|
||||||
|
negateTests :: Task
|
||||||
|
negateTests = Task {
|
||||||
|
taskName = "ed25519 negation tests",
|
||||||
|
taskFile = "../testdata/ed25519/negate.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomElement drg0 $ \ ptrel drg1 ->
|
||||||
|
alloca $ \ ptrc ->
|
||||||
|
do fe_negate ptrc ptrel
|
||||||
|
a <- convertFE ptrel
|
||||||
|
c <- convertFE ptrc
|
||||||
|
let res = Map.fromList [("a", showBin a),
|
||||||
|
("c", showBin c)]
|
||||||
|
return (res, toNumber a, (memory0, drg1))
|
||||||
|
|
||||||
|
cmovTests :: Task
|
||||||
|
cmovTests = Task {
|
||||||
|
taskName = "ed25519 conditional mov tests",
|
||||||
|
taskFile = "../testdata/ed25519/cmov.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomElement drg0 $ \ aelptr drg1 ->
|
||||||
|
do let (bbytes, drg2) = withDRG drg1 (getRandomBytes 1)
|
||||||
|
b = even (BS.head bbytes)
|
||||||
|
bvalLib = if b then 0 else 1
|
||||||
|
bvalOut = if b then 0 else 0xFFFFFF :: Word32
|
||||||
|
alloca $ \ celptr ->
|
||||||
|
do clearSpace celptr
|
||||||
|
fe_cmov celptr aelptr bvalLib
|
||||||
|
a <- convertFE aelptr
|
||||||
|
c <- convertFE celptr
|
||||||
|
let res = Map.fromList [("a", showBin a),
|
||||||
|
("b", showX bvalOut),
|
||||||
|
("c", showBin c)]
|
||||||
|
return (res, toNumber a, (memory0, drg2))
|
||||||
|
|
||||||
|
isTests :: Task
|
||||||
|
isTests = Task {
|
||||||
|
taskName = "ed25519 predicate tests",
|
||||||
|
taskFile = "../testdata/ed25519/istests.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomElement drg0 $ \ aptr drg1 ->
|
||||||
|
do a <- convertFE aptr
|
||||||
|
z <- fe_isnonzero aptr
|
||||||
|
n <- fe_isnegative aptr
|
||||||
|
let res = Map.fromList [("a", showBin a),
|
||||||
|
("z", showX (if z == 0 then 0 :: Word32 else 0xFFFFFF)),
|
||||||
|
("n", showX (if n == 0 then 0 :: Word32 else 0xFFFFFF))]
|
||||||
|
return (res, toNumber a, (memory0, drg1))
|
||||||
|
|
||||||
|
square2Tests :: Task
|
||||||
|
square2Tests = Task {
|
||||||
|
taskName = "ed25519 square2 tests",
|
||||||
|
taskFile = "../testdata/ed25519/square2.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomElement drg0 $ \ aptr drg1 ->
|
||||||
|
alloca $ \ cptr ->
|
||||||
|
do clearSpace cptr
|
||||||
|
fe_square2 cptr aptr
|
||||||
|
a <- convertFE aptr
|
||||||
|
c <- convertFE cptr
|
||||||
|
let res = Map.fromList [("a", showBin a), ("c", showBin c)]
|
||||||
|
return (res, toNumber a, (memory0, drg1))
|
||||||
|
|
||||||
|
pow22523Tests :: Task
|
||||||
|
pow22523Tests = Task {
|
||||||
|
taskName = "ed25519 pow22523 tests",
|
||||||
|
taskFile = "../testdata/ed25519/pow22523.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomElement drg0 $ \ aptr drg1 ->
|
||||||
|
alloca $ \ cptr ->
|
||||||
|
do clearSpace cptr
|
||||||
|
fe_pow22523 cptr aptr
|
||||||
|
a <- convertFE aptr
|
||||||
|
c <- convertFE cptr
|
||||||
|
let res = Map.fromList [("a", showBin a), ("c", showBin c)]
|
||||||
|
return (res, toNumber a, (memory0, drg1))
|
||||||
|
|
||||||
|
fbvTests :: Task
|
||||||
|
fbvTests = Task {
|
||||||
|
taskName = "ed25519 from bytes (vartime) tests",
|
||||||
|
taskFile = "../testdata/ed25519/fbv.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
do let (abytes, drg1) = withDRG drg0 (getRandomBytes 32)
|
||||||
|
useAsCString abytes $ \ aptr ->
|
||||||
|
do let aptr' = castPtr aptr :: Ptr PackedBytes
|
||||||
|
curve25519_scalar_mask aptr'
|
||||||
|
alloca $ \ dest ->
|
||||||
|
do clearSpace dest
|
||||||
|
ok <- point_frombytes dest aptr'
|
||||||
|
a <- pack `fmap` peekArray 32 (castPtr aptr)
|
||||||
|
c <- pack `fmap` peekArray (4 * 10 * 4) (castPtr dest)
|
||||||
|
let c' | ok = c
|
||||||
|
| otherwise = BS.empty
|
||||||
|
let res = Map.fromList [("a", showBin a),
|
||||||
|
("b", showBin c'),
|
||||||
|
("c", showBin c)]
|
||||||
|
return (res, if ok then (toNumber abytes) else 0, (memory0, drg1))
|
||||||
|
|
||||||
|
conversionTests :: Task
|
||||||
|
conversionTests = Task {
|
||||||
|
taskName = "ed25519 point form conversion tests",
|
||||||
|
taskFile = "../testdata/ed25519/conversion.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomPoint3 drg0 $ \ ptr3 drg' ->
|
||||||
|
alloca $ \ ptrCached ->
|
||||||
|
alloca $ \ ptr2 ->
|
||||||
|
alloca $ \ ptrP1P1 ->
|
||||||
|
alloca $ \ ptr2' ->
|
||||||
|
alloca $ \ ptr3' ->
|
||||||
|
do clearSpace ptrCached
|
||||||
|
clearSpace ptr2
|
||||||
|
clearSpace ptrP1P1
|
||||||
|
clearSpace ptr2'
|
||||||
|
clearSpace ptr3'
|
||||||
|
p3_to_cached ptrCached ptr3
|
||||||
|
ge_p3_to_p2 ptr2 ptr3
|
||||||
|
ge_p3_dbl ptrP1P1 ptr3
|
||||||
|
p1p1_to_p2 ptr2' ptrP1P1
|
||||||
|
p1p1_to_p3 ptr3' ptrP1P1
|
||||||
|
a <- convertPoint ptr3
|
||||||
|
c <- convertPoint ptrCached
|
||||||
|
t <- convertPoint ptr2
|
||||||
|
o <- convertPoint ptrP1P1
|
||||||
|
d <- convertPoint ptr2'
|
||||||
|
b <- convertPoint ptr3'
|
||||||
|
let res = Map.fromList [("a", showBin a), ("c", showBin c),
|
||||||
|
("t", showBin t), ("o", showBin o),
|
||||||
|
("d", showBin d), ("b", showBin b)]
|
||||||
|
return (res, toNumber a, (memory0, drg'))
|
||||||
|
|
||||||
|
ptDoubleTests :: Task
|
||||||
|
ptDoubleTests = Task {
|
||||||
|
taskName = "ed25519 point doubling tests",
|
||||||
|
taskFile = "../testdata/ed25519/pt_double.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomPoint3 drg0 $ \ ptra drg1 ->
|
||||||
|
randomPoint2 drg1 $ \ ptrc drg2 ->
|
||||||
|
alloca $ \ ptrb ->
|
||||||
|
alloca $ \ ptrd ->
|
||||||
|
do clearSpace ptrb
|
||||||
|
clearSpace ptrd
|
||||||
|
ge_p3_dbl ptrb ptra
|
||||||
|
ge_p2_dbl ptrd ptrc
|
||||||
|
a <- convertPoint ptra
|
||||||
|
b <- convertPoint ptrb
|
||||||
|
c <- convertPoint ptrc
|
||||||
|
d <- convertPoint ptrd
|
||||||
|
let res = Map.fromList [("a", showBin a), ("b", showBin b),
|
||||||
|
("c", showBin c), ("d", showBin d)]
|
||||||
|
return (res, toNumber a, (memory0, drg2))
|
||||||
|
|
||||||
|
maddsubTests :: Task
|
||||||
|
maddsubTests = Task {
|
||||||
|
taskName = "ed25519 point madd/msub tests",
|
||||||
|
taskFile = "../testdata/ed25519/maddsub.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomPoint3 drg0 $ \ ptra drg1 ->
|
||||||
|
randomPointPrecomp drg1 $ \ ptrc drg2 ->
|
||||||
|
alloca $ \ ptrb ->
|
||||||
|
alloca $ \ ptrd ->
|
||||||
|
do clearSpace ptrb
|
||||||
|
clearSpace ptrd
|
||||||
|
ge_madd ptrb ptra ptrc
|
||||||
|
ge_msub ptrd ptra ptrc
|
||||||
|
a <- convertPoint ptra
|
||||||
|
b <- convertPoint ptrb
|
||||||
|
c <- convertPoint ptrc
|
||||||
|
d <- convertPoint ptrd
|
||||||
|
let res = Map.fromList [("a", showBin a), ("b", showBin b),
|
||||||
|
("c", showBin c), ("d", showBin d)]
|
||||||
|
return (res, toNumber a, (memory0, drg2))
|
||||||
|
|
||||||
|
ptAddSubTests :: Task
|
||||||
|
ptAddSubTests = Task {
|
||||||
|
taskName = "ed25519 point add/sub tests",
|
||||||
|
taskFile = "../testdata/ed25519/ptaddsub.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomPoint3 drg0 $ \ ptra drg1 ->
|
||||||
|
randomPointCached drg1 $ \ ptrc drg2 ->
|
||||||
|
alloca $ \ ptrb ->
|
||||||
|
alloca $ \ ptrd ->
|
||||||
|
do clearSpace ptrb
|
||||||
|
clearSpace ptrd
|
||||||
|
ge_add ptrb ptra ptrc
|
||||||
|
ge_sub ptrd ptra ptrc
|
||||||
|
a <- convertPoint ptra
|
||||||
|
b <- convertPoint ptrb
|
||||||
|
c <- convertPoint ptrc
|
||||||
|
d <- convertPoint ptrd
|
||||||
|
let res = Map.fromList [("a", showBin a), ("b", showBin b),
|
||||||
|
("c", showBin c), ("d", showBin d)]
|
||||||
|
return (res, toNumber a, (memory0, drg2))
|
||||||
|
|
||||||
|
scalarMultBaseTests :: Task
|
||||||
|
scalarMultBaseTests = Task {
|
||||||
|
taskName = "ed25519 point add/sub tests",
|
||||||
|
taskFile = "../testdata/ed25519/scalar_mult.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomPackedBytes drg0 $ \ ptra drg1 ->
|
||||||
|
alloca $ \ ptrb ->
|
||||||
|
do clearSpace ptrb
|
||||||
|
x25519_ge_scalarmult_base ptrb ptra
|
||||||
|
PB abytes <- peek ptra
|
||||||
|
let a = pack abytes
|
||||||
|
b <- convertPoint ptrb
|
||||||
|
let res = Map.fromList [("a", showBin a), ("b", showBin b)]
|
||||||
|
return (res, toNumber a, (memory0, drg1))
|
||||||
|
|
||||||
|
slideTests :: Task
|
||||||
|
slideTests = Task {
|
||||||
|
taskName = "ed25519 slide helper function tests",
|
||||||
|
taskFile = "../testdata/ed25519/slide.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomPackedBytes drg0 $ \ ptra drg1 ->
|
||||||
|
allocaArray 256 $ \ ptrb ->
|
||||||
|
do pokeArray ptrb (replicate 256 0)
|
||||||
|
slide ptrb ptra
|
||||||
|
a <- pack `fmap` peekArray 32 (castPtr ptra)
|
||||||
|
b <- pack `fmap` peekArray 356 ptrb
|
||||||
|
let res = Map.fromList [("a", showBin a), ("b", showBin b)]
|
||||||
|
return (res, toNumber a, (memory0, drg1))
|
||||||
|
|
||||||
|
scalarMultTests :: Task
|
||||||
|
scalarMultTests = Task {
|
||||||
|
taskName = "ed25519 point general scalar multiplication tests",
|
||||||
|
taskFile = "../testdata/ed25519/scalar_mult_gen.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomPackedBytes drg0 $ \ ptra drg1 ->
|
||||||
|
randomPoint3 drg1 $ \ ptrb drg2 ->
|
||||||
|
randomPackedBytes drg2 $ \ ptrc drg3 ->
|
||||||
|
alloca $ \ ptrd ->
|
||||||
|
do clearSpace ptrd
|
||||||
|
ge_double_scalarmult_vartime ptrd ptra ptrb ptrc
|
||||||
|
PB abytes <- peek ptra
|
||||||
|
let a = pack abytes
|
||||||
|
b <- convertPoint ptrb
|
||||||
|
PB cbytes <- peek ptrc
|
||||||
|
let c = pack cbytes
|
||||||
|
d <- convertPoint ptrd
|
||||||
|
let res = Map.fromList [("a", showBin a), ("b", showBin b),
|
||||||
|
("c", showBin c), ("d", showBin d)]
|
||||||
|
return (res, toNumber a, (memory0, drg3))
|
||||||
|
|
||||||
|
reduceTests :: Task
|
||||||
|
reduceTests = Task {
|
||||||
|
taskName = "ed25519 reduce tests",
|
||||||
|
taskFile = "../testdata/ed25519/reduce.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
do let (a, drg1) = withDRG drg0 (getRandomBytes 64)
|
||||||
|
allocaArray 64 $ \ target ->
|
||||||
|
do pokeArray target (BS.unpack a)
|
||||||
|
sc_reduce target
|
||||||
|
b <- pack `fmap` peekArray 32 target
|
||||||
|
let res = Map.fromList [("a", showBin a), ("b", showBin b)]
|
||||||
|
return (res, toNumber a, (memory0, drg1))
|
||||||
|
|
||||||
|
muladdTests :: Task
|
||||||
|
muladdTests = Task {
|
||||||
|
taskName = "ed25519 multiplication+addition tests",
|
||||||
|
taskFile = "../testdata/ed25519/muladd.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomPackedBytes drg0 $ \ ptra drg1 ->
|
||||||
|
randomPackedBytes drg1 $ \ ptrb drg2 ->
|
||||||
|
randomPackedBytes drg2 $ \ ptrc drg3 ->
|
||||||
|
alloca $ \ ptrd ->
|
||||||
|
do clearSpace ptrd
|
||||||
|
sc_muladd ptrd ptra ptrb ptrc
|
||||||
|
a <- repackBytes ptra
|
||||||
|
b <- repackBytes ptrb
|
||||||
|
c <- repackBytes ptrc
|
||||||
|
d <- repackBytes ptrd
|
||||||
|
let res = Map.fromList [("a", showBin a), ("b", showBin b),
|
||||||
|
("c", showBin c), ("d", showBin d)]
|
||||||
|
return (res, toNumber a, (memory0, drg3))
|
||||||
|
|
||||||
|
pubPrivTests :: Task
|
||||||
|
pubPrivTests = Task {
|
||||||
|
taskName = "ed25519 private -> public conversion tests",
|
||||||
|
taskFile = "../testdata/ed25519/pubfrompriv.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
randomPackedBytes drg0 $ \ ptra drg1 ->
|
||||||
|
alloca $ \ ptrb ->
|
||||||
|
do clearSpace ptrb
|
||||||
|
public_from_private ptrb ptra
|
||||||
|
a <- repackBytes ptra
|
||||||
|
b <- repackBytes ptrb
|
||||||
|
let res = Map.fromList [("a", showBin a), ("b", showBin b)]
|
||||||
|
return (res, toNumber a, (memory0, drg1))
|
||||||
|
|
||||||
|
signTest :: Task
|
||||||
|
signTest = Task {
|
||||||
|
taskName = "ed25519 signing tests",
|
||||||
|
taskFile = "../testdata/ed25519/sign.test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = cTEST_COUNT
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
let (priv, drg1) = withDRG drg0 generateSecretKey
|
||||||
|
(msg, drg2) = withDRG drg1 $ getRandomBytes =<< ((fromIntegral . BS.head) `fmap` getRandomBytes 1)
|
||||||
|
pub = toPublic priv
|
||||||
|
privBytes = convert priv
|
||||||
|
pubBytes = convert pub
|
||||||
|
sig = convert (sign priv pub msg)
|
||||||
|
res = Map.fromList [("u", showBin pubBytes), ("r", showBin privBytes),
|
||||||
|
("m", showBin msg), ("s", showBin sig)]
|
||||||
|
in return (res, toNumber privBytes, (memory0, drg2))
|
||||||
|
|
||||||
|
|
||||||
|
data PackedBytes = PB [Word8]
|
||||||
|
deriving (Eq)
|
||||||
|
|
||||||
|
instance Storable PackedBytes where
|
||||||
|
sizeOf _ = 32
|
||||||
|
alignment _ = 8
|
||||||
|
peek p = PB `fmap` peekArray 32 (castPtr p)
|
||||||
|
poke p (PB v) = pokeArray (castPtr p) v
|
||||||
|
|
||||||
|
randomPackedBytes :: SystemRandom -> (Ptr PackedBytes -> SystemRandom -> IO a) -> IO a
|
||||||
|
randomPackedBytes drg action =
|
||||||
|
do let (bytes, drg') = withDRG drg (getRandomBytes 32)
|
||||||
|
useAsCString bytes $ \ ptr ->
|
||||||
|
do let ptr' = castPtr ptr :: Ptr PackedBytes
|
||||||
|
curve25519_scalar_mask ptr'
|
||||||
|
action ptr' drg'
|
||||||
|
|
||||||
|
repackBytes :: Ptr PackedBytes -> IO ByteString
|
||||||
|
repackBytes ptr =
|
||||||
|
do PB xs <- peek ptr
|
||||||
|
return (pack xs)
|
||||||
|
|
||||||
|
data Element = FE [Int32]
|
||||||
|
|
||||||
|
instance Storable Element where
|
||||||
|
sizeOf _ = 10 * sizeOf (undefined :: Int32)
|
||||||
|
alignment _ = 8
|
||||||
|
peek p = FE `fmap` peekArray 10 (castPtr p)
|
||||||
|
poke p (FE v) = pokeArray (castPtr p) v
|
||||||
|
|
||||||
|
randomElement :: SystemRandom -> (Ptr Element -> SystemRandom -> IO a) -> IO a
|
||||||
|
randomElement drg action =
|
||||||
|
randomPackedBytes drg $ \ ptrpb drg' -> alloca $ \ ptrel ->
|
||||||
|
do clearSpace ptrel
|
||||||
|
fe_frombytes ptrel ptrpb
|
||||||
|
action ptrel drg'
|
||||||
|
|
||||||
|
data Point3 = P3 [Element]
|
||||||
|
|
||||||
|
instance Storable Point3 where
|
||||||
|
sizeOf _ = 4 * sizeOf (undefined :: Element)
|
||||||
|
alignment _ = 8
|
||||||
|
peek p = P3 `fmap` peekArray 4 (castPtr p)
|
||||||
|
poke p (P3 v) = pokeArray (castPtr p) v
|
||||||
|
|
||||||
|
randomPoint3 :: SystemRandom -> (Ptr Point3 -> SystemRandom -> IO a) -> IO a
|
||||||
|
randomPoint3 drg0 action = allocaArray (4 * 10) (go drg0)
|
||||||
|
where
|
||||||
|
go drg dest =
|
||||||
|
do mres <- randomPackedBytes drg $ \ aptr drg' ->
|
||||||
|
do clearSpace dest
|
||||||
|
worked <- point_frombytes dest aptr
|
||||||
|
if worked
|
||||||
|
then Right `fmap` action (castPtr dest) drg'
|
||||||
|
else return (Left drg')
|
||||||
|
case mres of
|
||||||
|
Right x -> return x
|
||||||
|
Left drg' -> go drg' dest
|
||||||
|
|
||||||
|
data PointCached = PC [Element]
|
||||||
|
|
||||||
|
instance Storable PointCached where
|
||||||
|
sizeOf _ = 4 * sizeOf (undefined :: Element)
|
||||||
|
alignment _ = 8
|
||||||
|
peek p = PC `fmap` peekArray 4 (castPtr p)
|
||||||
|
poke p (PC v) = pokeArray (castPtr p) v
|
||||||
|
|
||||||
|
randomPointCached :: SystemRandom -> (Ptr PointCached -> SystemRandom -> IO a) -> IO a
|
||||||
|
randomPointCached drg action =
|
||||||
|
randomPoint3 drg $ \ ptr drg' ->
|
||||||
|
allocaArray (4 * 10) $ \ dest ->
|
||||||
|
do pokeArray (castPtr dest :: Ptr Int32) (replicate (4 * 10) 0)
|
||||||
|
p3_to_cached dest ptr
|
||||||
|
action (castPtr dest) drg'
|
||||||
|
|
||||||
|
data Point2 = P2 [Element]
|
||||||
|
|
||||||
|
instance Storable Point2 where
|
||||||
|
sizeOf _ = 3 * sizeOf (undefined :: Element)
|
||||||
|
alignment _ = 8
|
||||||
|
peek p = P2 `fmap` peekArray 3 (castPtr p)
|
||||||
|
poke p (P2 v) = pokeArray (castPtr p) v
|
||||||
|
|
||||||
|
randomPoint2 :: SystemRandom -> (Ptr Point2 -> SystemRandom -> IO a) -> IO a
|
||||||
|
randomPoint2 drg action =
|
||||||
|
randomPoint3 drg $ \ ptr3 drg' ->
|
||||||
|
allocaArray (3 * 10) $ \ dest ->
|
||||||
|
do pokeArray (castPtr dest :: Ptr Int32) (replicate (3 * 10) 0)
|
||||||
|
ge_p3_to_p2 dest ptr3
|
||||||
|
action (castPtr dest) drg'
|
||||||
|
|
||||||
|
data PointP1P1 = P1P1 [Element]
|
||||||
|
|
||||||
|
instance Storable PointP1P1 where
|
||||||
|
sizeOf _ = 4 * sizeOf (undefined :: Element)
|
||||||
|
alignment _ = 8
|
||||||
|
peek p = P1P1 `fmap` peekArray 4 (castPtr p)
|
||||||
|
poke p (P1P1 v) = pokeArray (castPtr p) v
|
||||||
|
|
||||||
|
_randomPointP1P1 :: SystemRandom -> (Ptr PointP1P1 -> SystemRandom -> IO a) -> IO a
|
||||||
|
_randomPointP1P1 drg action =
|
||||||
|
randomPoint3 drg $ \ ptr3 drg' ->
|
||||||
|
allocaArray (4 * 10) $ \ dest ->
|
||||||
|
do pokeArray (castPtr dest :: Ptr Int32) (replicate (4 * 10) 0)
|
||||||
|
ge_p3_dbl dest ptr3
|
||||||
|
action (castPtr dest) drg'
|
||||||
|
|
||||||
|
data PointPrecomp = PP [Element]
|
||||||
|
|
||||||
|
instance Storable PointPrecomp where
|
||||||
|
sizeOf _ = 4 * sizeOf (undefined :: Element)
|
||||||
|
alignment _ = 8
|
||||||
|
peek p = PP `fmap` peekArray 4 (castPtr p)
|
||||||
|
poke p (PP v) = pokeArray (castPtr p) v
|
||||||
|
|
||||||
|
randomPointPrecomp :: SystemRandom -> (Ptr PointPrecomp -> SystemRandom -> IO a) -> IO a
|
||||||
|
randomPointPrecomp drg action =
|
||||||
|
do let ([a,b,c,d], drg') = withDRG drg (BS.unpack `fmap` getRandomBytes 4)
|
||||||
|
mix = fromIntegral a + fromIntegral b + fromIntegral c + fromIntegral d
|
||||||
|
idx = mix `mod` (length precompPoints)
|
||||||
|
val = PP (map FE (precompPoints !! idx))
|
||||||
|
alloca $ \ ptr ->
|
||||||
|
do poke ptr val
|
||||||
|
action ptr drg'
|
||||||
|
|
||||||
|
clearSpace :: Storable a => Ptr a -> IO ()
|
||||||
|
clearSpace x = meh x undefined
|
||||||
|
where
|
||||||
|
meh :: Storable a => Ptr a -> a -> IO ()
|
||||||
|
meh p v = pokeArray (castPtr p) (replicate (sizeOf v) (0 :: Word8))
|
||||||
|
|
||||||
|
convertFE :: Ptr Element -> IO ByteString
|
||||||
|
convertFE feptr = pack `fmap` peekArray 40 (castPtr feptr :: Ptr Word8)
|
||||||
|
|
||||||
|
convertPoint :: Storable a => Ptr a -> IO ByteString
|
||||||
|
convertPoint x = meh x undefined
|
||||||
|
where
|
||||||
|
meh :: Storable a => Ptr a -> a -> IO ByteString
|
||||||
|
meh p v = pack `fmap` peekArray (sizeOf v) (castPtr p)
|
||||||
|
|
||||||
|
toNumber :: ByteString -> Integer
|
||||||
|
toNumber = BS.foldr (\ x a -> fromIntegral x + a) 0
|
||||||
|
|
||||||
|
foreign import ccall unsafe "load_3"
|
||||||
|
load_3 :: Ptr CChar -> IO Word64
|
||||||
|
foreign import ccall unsafe "load_4"
|
||||||
|
load_4 :: Ptr CChar -> IO Word64
|
||||||
|
foreign import ccall unsafe "GFp_curve25519_scalar_mask"
|
||||||
|
curve25519_scalar_mask :: Ptr PackedBytes -> IO ()
|
||||||
|
foreign import ccall unsafe "fe_frombytes"
|
||||||
|
fe_frombytes :: Ptr Element -> Ptr PackedBytes -> IO ()
|
||||||
|
foreign import ccall unsafe "GFp_fe_tobytes"
|
||||||
|
fe_tobytes :: Ptr PackedBytes -> Ptr Element -> IO ()
|
||||||
|
foreign import ccall unsafe "fe_add"
|
||||||
|
fe_add :: Ptr Element -> Ptr Element -> Ptr Element -> IO ()
|
||||||
|
foreign import ccall unsafe "fe_sub"
|
||||||
|
fe_sub :: Ptr Element -> Ptr Element -> Ptr Element -> IO ()
|
||||||
|
foreign import ccall unsafe "GFp_fe_mul"
|
||||||
|
fe_mul :: Ptr Element -> Ptr Element -> Ptr Element -> IO ()
|
||||||
|
foreign import ccall unsafe "fe_sq"
|
||||||
|
fe_square :: Ptr Element -> Ptr Element -> IO ()
|
||||||
|
foreign import ccall unsafe "GFp_fe_invert"
|
||||||
|
fe_invert :: Ptr Element -> Ptr Element -> IO ()
|
||||||
|
foreign import ccall unsafe "fe_neg"
|
||||||
|
fe_negate :: Ptr Element -> Ptr Element -> IO ()
|
||||||
|
foreign import ccall unsafe "fe_cmov"
|
||||||
|
fe_cmov :: Ptr Element -> Ptr Element -> Word32 -> IO ()
|
||||||
|
foreign import ccall unsafe "fe_isnonzero"
|
||||||
|
fe_isnonzero :: Ptr Element -> IO Int32
|
||||||
|
foreign import ccall unsafe "GFp_fe_isnegative"
|
||||||
|
fe_isnegative :: Ptr Element -> IO Word8
|
||||||
|
foreign import ccall unsafe "fe_sq2"
|
||||||
|
fe_square2 :: Ptr Element -> Ptr Element -> IO ()
|
||||||
|
foreign import ccall unsafe "fe_pow22523"
|
||||||
|
fe_pow22523 :: Ptr Element -> Ptr Element -> IO ()
|
||||||
|
foreign import ccall unsafe "GFp_x25519_ge_frombytes_vartime"
|
||||||
|
point_frombytes :: Ptr Point3 -> Ptr PackedBytes -> IO Bool
|
||||||
|
foreign import ccall unsafe "x25519_ge_p3_to_cached"
|
||||||
|
p3_to_cached :: Ptr PointCached -> Ptr Point3 -> IO ()
|
||||||
|
foreign import ccall unsafe "x25519_ge_p1p1_to_p2"
|
||||||
|
p1p1_to_p2 :: Ptr Point2 -> Ptr PointP1P1 -> IO ()
|
||||||
|
foreign import ccall unsafe "x25519_ge_p1p1_to_p3"
|
||||||
|
p1p1_to_p3 :: Ptr Point3 -> Ptr PointP1P1 -> IO ()
|
||||||
|
foreign import ccall unsafe "ge_p2_dbl"
|
||||||
|
ge_p2_dbl :: Ptr PointP1P1 -> Ptr Point2 -> IO ()
|
||||||
|
foreign import ccall unsafe "ge_p3_dbl"
|
||||||
|
ge_p3_dbl :: Ptr PointP1P1 -> Ptr Point3 -> IO ()
|
||||||
|
foreign import ccall unsafe "ge_p3_to_p2"
|
||||||
|
ge_p3_to_p2 :: Ptr Point2 -> Ptr Point3 -> IO ()
|
||||||
|
foreign import ccall unsafe "ge_madd"
|
||||||
|
ge_madd :: Ptr PointP1P1 -> Ptr Point3 -> Ptr PointPrecomp -> IO ()
|
||||||
|
foreign import ccall unsafe "ge_msub"
|
||||||
|
ge_msub :: Ptr PointP1P1 -> Ptr Point3 -> Ptr PointPrecomp -> IO ()
|
||||||
|
foreign import ccall unsafe "x25519_ge_add"
|
||||||
|
ge_add :: Ptr PointP1P1 -> Ptr Point3 -> Ptr PointCached -> IO ()
|
||||||
|
foreign import ccall unsafe "x25519_ge_sub"
|
||||||
|
ge_sub :: Ptr PointP1P1 -> Ptr Point3 -> Ptr PointCached -> IO ()
|
||||||
|
foreign import ccall unsafe "GFp_x25519_ge_scalarmult_base"
|
||||||
|
x25519_ge_scalarmult_base :: Ptr Point3 -> Ptr PackedBytes -> IO ()
|
||||||
|
foreign import ccall unsafe "slide"
|
||||||
|
slide :: Ptr Word8 -> Ptr PackedBytes -> IO ()
|
||||||
|
foreign import ccall unsafe "GFp_ge_double_scalarmult_vartime"
|
||||||
|
ge_double_scalarmult_vartime :: Ptr Point2 -> Ptr PackedBytes -> Ptr Point3 -> Ptr PackedBytes -> IO ()
|
||||||
|
foreign import ccall unsafe "GFp_x25519_sc_reduce"
|
||||||
|
sc_reduce :: Ptr Word8 -> IO ()
|
||||||
|
foreign import ccall unsafe "GFp_x25519_sc_muladd"
|
||||||
|
sc_muladd :: Ptr PackedBytes -> Ptr PackedBytes -> Ptr PackedBytes -> Ptr PackedBytes -> IO ()
|
||||||
|
foreign import ccall unsafe "GFp_x25519_public_from_private"
|
||||||
|
public_from_private :: Ptr PackedBytes -> Ptr PackedBytes -> IO ()
|
||||||
2120
test-generator/ED25519/PrecompPoints.hs
Normal file
2120
test-generator/ED25519/PrecompPoints.hs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@ import Control.Monad(replicateM_,void)
|
|||||||
import "crypto-api" Crypto.Random(CryptoRandomGen(..),SystemRandom)
|
import "crypto-api" Crypto.Random(CryptoRandomGen(..),SystemRandom)
|
||||||
import DSA(dsaTasks)
|
import DSA(dsaTasks)
|
||||||
import ECDSATesting(ecdsaTasks)
|
import ECDSATesting(ecdsaTasks)
|
||||||
|
import ED25519(ed25519Tasks)
|
||||||
import GHC.Conc(getNumCapabilities)
|
import GHC.Conc(getNumCapabilities)
|
||||||
import RFC6979(rfcTasks)
|
import RFC6979(rfcTasks)
|
||||||
import RSA(rsaTasks)
|
import RSA(rsaTasks)
|
||||||
@@ -38,6 +39,6 @@ main = displayConsoleRegions $
|
|||||||
do
|
do
|
||||||
executors <- getNumCapabilities
|
executors <- getNumCapabilities
|
||||||
done <- newChan
|
done <- newChan
|
||||||
tasks <- newMVar (dsaTasks ++ ecdsaTasks ++ rfcTasks ++ rsaTasks)
|
tasks <- newMVar (dsaTasks ++ ecdsaTasks ++ rfcTasks ++ rsaTasks ++ ed25519Tasks)
|
||||||
replicateM_ executors (spawnExecutor tasks done)
|
replicateM_ executors (spawnExecutor tasks done)
|
||||||
replicateM_ executors (void $ readChan done)
|
replicateM_ executors (void $ readChan done)
|
||||||
@@ -15,7 +15,7 @@ import qualified Data.ByteString as S
|
|||||||
import Data.Char(toUpper)
|
import Data.Char(toUpper)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import Math(showBin,showX)
|
import Math(showBin,showX)
|
||||||
import Task(Task(..))
|
import Task(Task(..),liftTest)
|
||||||
import Utils(HashAlg(..), runHash)
|
import Utils(HashAlg(..), runHash)
|
||||||
|
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ rfc6979Test :: HashAlg -> Task
|
|||||||
rfc6979Test alg = Task {
|
rfc6979Test alg = Task {
|
||||||
taskName = name ++ " RFC 6979 deterministic k-generation",
|
taskName = name ++ " RFC 6979 deterministic k-generation",
|
||||||
taskFile = "../testdata/rfc6979/" ++ name ++ ".test",
|
taskFile = "../testdata/rfc6979/" ++ name ++ ".test",
|
||||||
taskTest = go,
|
taskTest = liftTest go,
|
||||||
taskCount = 1000
|
taskCount = 1000
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import Data.Maybe(fromMaybe,isJust)
|
|||||||
import Data.Word(Word8)
|
import Data.Word(Word8)
|
||||||
import Database(Database)
|
import Database(Database)
|
||||||
import Math(barrett,computeK,showX,showBin)
|
import Math(barrett,computeK,showX,showBin)
|
||||||
import Task(Task(..))
|
import Task(Task(..),liftTest)
|
||||||
import Utils(HashAlg(..),generateHash,showHash)
|
import Utils(HashAlg(..),generateHash,showHash)
|
||||||
|
|
||||||
rsaSizes :: [(Int, Int)]
|
rsaSizes :: [(Int, Int)]
|
||||||
@@ -40,7 +40,7 @@ signTest :: Int -> Int -> Task
|
|||||||
signTest sz cnt = Task {
|
signTest sz cnt = Task {
|
||||||
taskName = "RSA " ++ show sz ++ " signing",
|
taskName = "RSA " ++ show sz ++ " signing",
|
||||||
taskFile = "../testdata/rsa/sign" ++ show sz ++ ".test",
|
taskFile = "../testdata/rsa/sign" ++ show sz ++ ".test",
|
||||||
taskTest = go,
|
taskTest = liftTest go,
|
||||||
taskCount = cnt
|
taskCount = cnt
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
@@ -78,7 +78,7 @@ encryptTest :: Int -> Int -> Task
|
|||||||
encryptTest sz cnt = Task {
|
encryptTest sz cnt = Task {
|
||||||
taskName = "RSA " ++ show sz ++ " encryption",
|
taskName = "RSA " ++ show sz ++ " encryption",
|
||||||
taskFile = "../testdata/rsa/encrypt" ++ show sz ++ ".test",
|
taskFile = "../testdata/rsa/encrypt" ++ show sz ++ ".test",
|
||||||
taskTest = go,
|
taskTest = liftTest go,
|
||||||
taskCount = cnt
|
taskCount = cnt
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
module Task(
|
module Task(
|
||||||
Test,
|
Test,
|
||||||
Task(..),
|
Task(..),
|
||||||
runTask
|
runTask,
|
||||||
|
liftTest
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@@ -15,7 +16,7 @@ import System.Directory(createDirectoryIfMissing,doesFileExist)
|
|||||||
import System.FilePath(takeDirectory)
|
import System.FilePath(takeDirectory)
|
||||||
import System.IO(Handle,IOMode(..),hPutStrLn,withFile)
|
import System.IO(Handle,IOMode(..),hPutStrLn,withFile)
|
||||||
|
|
||||||
type Test = Database -> (Map.Map String String, Integer, Database)
|
type Test = Database -> IO (Map.Map String String, Integer, Database)
|
||||||
|
|
||||||
data Task = Task {
|
data Task = Task {
|
||||||
taskName :: String,
|
taskName :: String,
|
||||||
@@ -24,6 +25,10 @@ data Task = Task {
|
|||||||
taskCount :: Int
|
taskCount :: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
liftTest :: (Database -> (Map.Map String String, Integer, Database)) ->
|
||||||
|
(Database -> IO (Map.Map String String, Integer, Database))
|
||||||
|
liftTest f db = return (f db)
|
||||||
|
|
||||||
runTask :: SystemRandom -> Task -> IO SystemRandom
|
runTask :: SystemRandom -> Task -> IO SystemRandom
|
||||||
runTask gen task =
|
runTask gen task =
|
||||||
do createDirectoryIfMissing True (takeDirectory (taskFile task))
|
do createDirectoryIfMissing True (takeDirectory (taskFile task))
|
||||||
@@ -40,8 +45,8 @@ runTask gen task =
|
|||||||
where
|
where
|
||||||
writer :: Handle -> ProgressBar -> Test -> Database -> Int -> IO Database
|
writer :: Handle -> ProgressBar -> Test -> Database -> Int -> IO Database
|
||||||
writer hndl pg runner db x =
|
writer hndl pg runner db x =
|
||||||
do let (output, key, acc@(db',gen')) = runner db
|
do (output, key, acc@(db',gen')) <- runner db
|
||||||
before = Map.findWithDefault [] "RESULT" db'
|
let before = Map.findWithDefault [] "RESULT" db'
|
||||||
if length (filter (== key) before) >= 10
|
if length (filter (== key) before) >= 10
|
||||||
then writer hndl pg runner acc x
|
then writer hndl pg runner acc x
|
||||||
else do forM_ (Map.toList output) $ \ (outkey, val) ->
|
else do forM_ (Map.toList output) $ \ (outkey, val) ->
|
||||||
|
|||||||
96
test-generator/cbits/GFp/aes.h
Normal file
96
test-generator/cbits/GFp/aes.h
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
* Copyright (c) 2002-2006 The OpenSSL Project. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this
|
||||||
|
* software must display the following acknowledgment:
|
||||||
|
* "This product includes software developed by the OpenSSL Project
|
||||||
|
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||||
|
*
|
||||||
|
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||||
|
* endorse or promote products derived from this software without
|
||||||
|
* prior written permission. For written permission, please contact
|
||||||
|
* openssl-core@openssl.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "OpenSSL"
|
||||||
|
* nor may "OpenSSL" appear in their names without prior written
|
||||||
|
* permission of the OpenSSL Project.
|
||||||
|
*
|
||||||
|
* 6. Redistributions of any form whatsoever must retain the following
|
||||||
|
* acknowledgment:
|
||||||
|
* "This product includes software developed by the OpenSSL Project
|
||||||
|
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||||
|
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
* ==================================================================== */
|
||||||
|
|
||||||
|
#ifndef OPENSSL_HEADER_AES_H
|
||||||
|
#define OPENSSL_HEADER_AES_H
|
||||||
|
|
||||||
|
#include <GFp/base.h>
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Raw AES functions. */
|
||||||
|
|
||||||
|
|
||||||
|
#define AES_ENCRYPT 1
|
||||||
|
#define AES_DECRYPT 0
|
||||||
|
|
||||||
|
/* AES_MAXNR is the maximum number of AES rounds. */
|
||||||
|
#define AES_MAXNR 14
|
||||||
|
|
||||||
|
#define AES_BLOCK_SIZE 16
|
||||||
|
|
||||||
|
/* aes_key_st should be an opaque type, but EVP requires that the size be
|
||||||
|
* known. */
|
||||||
|
struct aes_key_st {
|
||||||
|
uint32_t rd_key[4 * (AES_MAXNR + 1)];
|
||||||
|
unsigned rounds;
|
||||||
|
};
|
||||||
|
typedef struct aes_key_st AES_KEY;
|
||||||
|
|
||||||
|
/* GFp_AES_set_encrypt_key configures |aeskey| to encrypt with the |bits|-bit
|
||||||
|
* key, |key|.
|
||||||
|
*
|
||||||
|
* WARNING: unlike other OpenSSL functions, this returns zero on success and a
|
||||||
|
* negative number on error. */
|
||||||
|
OPENSSL_EXPORT int GFp_AES_set_encrypt_key(const uint8_t *key, unsigned bits,
|
||||||
|
AES_KEY *aeskey);
|
||||||
|
|
||||||
|
/* AES_encrypt encrypts a single block from |in| to |out| with |key|. The |in|
|
||||||
|
* and |out| pointers may overlap. */
|
||||||
|
OPENSSL_EXPORT void GFp_AES_encrypt(const uint8_t *in, uint8_t *out,
|
||||||
|
const AES_KEY *key);
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern C */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* OPENSSL_HEADER_AES_H */
|
||||||
123
test-generator/cbits/GFp/arm_arch.h
Normal file
123
test-generator/cbits/GFp/arm_arch.h
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
* Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this
|
||||||
|
* software must display the following acknowledgment:
|
||||||
|
* "This product includes software developed by the OpenSSL Project
|
||||||
|
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||||
|
*
|
||||||
|
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||||
|
* endorse or promote products derived from this software without
|
||||||
|
* prior written permission. For written permission, please contact
|
||||||
|
* openssl-core@openssl.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "OpenSSL"
|
||||||
|
* nor may "OpenSSL" appear in their names without prior written
|
||||||
|
* permission of the OpenSSL Project.
|
||||||
|
*
|
||||||
|
* 6. Redistributions of any form whatsoever must retain the following
|
||||||
|
* acknowledgment:
|
||||||
|
* "This product includes software developed by the OpenSSL Project
|
||||||
|
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||||
|
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This product includes cryptographic software written by Eric Young
|
||||||
|
* (eay@cryptsoft.com). This product includes software written by Tim
|
||||||
|
* Hudson (tjh@cryptsoft.com). */
|
||||||
|
|
||||||
|
#ifndef OPENSSL_HEADER_ARM_ARCH_H
|
||||||
|
#define OPENSSL_HEADER_ARM_ARCH_H
|
||||||
|
|
||||||
|
#if !defined(__ARM_ARCH__)
|
||||||
|
# if defined(__CC_ARM)
|
||||||
|
# define __ARM_ARCH__ __TARGET_ARCH_ARM
|
||||||
|
# if defined(__BIG_ENDIAN)
|
||||||
|
# define __ARMEB__
|
||||||
|
# else
|
||||||
|
# define __ARMEL__
|
||||||
|
# endif
|
||||||
|
# elif defined(__GNUC__)
|
||||||
|
# if defined(__aarch64__)
|
||||||
|
# define __ARM_ARCH__ 8
|
||||||
|
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||||
|
# define __ARMEB__
|
||||||
|
# else
|
||||||
|
# define __ARMEL__
|
||||||
|
# endif
|
||||||
|
/* Why doesn't gcc define __ARM_ARCH__? Instead it defines
|
||||||
|
* bunch of below macros. See all_architectires[] table in
|
||||||
|
* gcc/config/arm/arm.c. On a side note it defines
|
||||||
|
* __ARMEL__/__ARMEB__ for little-/big-endian. */
|
||||||
|
# elif defined(__ARM_ARCH)
|
||||||
|
# define __ARM_ARCH__ __ARM_ARCH
|
||||||
|
# elif defined(__ARM_ARCH_8A__)
|
||||||
|
# define __ARM_ARCH__ 8
|
||||||
|
# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
|
||||||
|
defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__) || \
|
||||||
|
defined(__ARM_ARCH_7EM__)
|
||||||
|
# define __ARM_ARCH__ 7
|
||||||
|
# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
|
||||||
|
defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__) || \
|
||||||
|
defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__) || \
|
||||||
|
defined(__ARM_ARCH_6T2__)
|
||||||
|
# define __ARM_ARCH__ 6
|
||||||
|
# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \
|
||||||
|
defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__) || \
|
||||||
|
defined(__ARM_ARCH_5TEJ__)
|
||||||
|
# define __ARM_ARCH__ 5
|
||||||
|
# elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
|
||||||
|
# define __ARM_ARCH__ 4
|
||||||
|
# else
|
||||||
|
# error "unsupported ARM architecture"
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Even when building for 32-bit ARM, support for aarch64 crypto instructions
|
||||||
|
* will be included. */
|
||||||
|
#if !defined(__ARM_MAX_ARCH__)
|
||||||
|
#define __ARM_MAX_ARCH__ 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ARMV7_NEON is true when a NEON unit is present in the current CPU. */
|
||||||
|
#define ARMV7_NEON (1 << 0)
|
||||||
|
|
||||||
|
/* ARMV8_AES indicates support for hardware AES instructions. */
|
||||||
|
#define ARMV8_AES (1 << 2)
|
||||||
|
|
||||||
|
/* ARMV8_SHA1 indicates support for hardware SHA-1 instructions. */
|
||||||
|
#define ARMV8_SHA1 (1 << 3)
|
||||||
|
|
||||||
|
/* ARMV8_SHA256 indicates support for hardware SHA-256 instructions. */
|
||||||
|
#define ARMV8_SHA256 (1 << 4)
|
||||||
|
|
||||||
|
/* ARMV8_PMULL indicates support for carryless multiplication. */
|
||||||
|
#define ARMV8_PMULL (1 << 5)
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* OPENSSL_HEADER_ARM_ARCH_H */
|
||||||
122
test-generator/cbits/GFp/base.h
Normal file
122
test-generator/cbits/GFp/base.h
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
* Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this
|
||||||
|
* software must display the following acknowledgment:
|
||||||
|
* "This product includes software developed by the OpenSSL Project
|
||||||
|
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||||
|
*
|
||||||
|
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||||
|
* endorse or promote products derived from this software without
|
||||||
|
* prior written permission. For written permission, please contact
|
||||||
|
* openssl-core@openssl.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "OpenSSL"
|
||||||
|
* nor may "OpenSSL" appear in their names without prior written
|
||||||
|
* permission of the OpenSSL Project.
|
||||||
|
*
|
||||||
|
* 6. Redistributions of any form whatsoever must retain the following
|
||||||
|
* acknowledgment:
|
||||||
|
* "This product includes software developed by the OpenSSL Project
|
||||||
|
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||||
|
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This product includes cryptographic software written by Eric Young
|
||||||
|
* (eay@cryptsoft.com). This product includes software written by Tim
|
||||||
|
* Hudson (tjh@cryptsoft.com). */
|
||||||
|
|
||||||
|
#ifndef OPENSSL_HEADER_BASE_H
|
||||||
|
#define OPENSSL_HEADER_BASE_H
|
||||||
|
|
||||||
|
|
||||||
|
/* This file should be the first included by all BoringSSL headers. */
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64)
|
||||||
|
#define OPENSSL_64_BIT
|
||||||
|
#define OPENSSL_X86_64
|
||||||
|
#elif defined(__x86) || defined(__i386) || defined(__i386__) || defined(_M_IX86)
|
||||||
|
#define OPENSSL_32_BIT
|
||||||
|
#define OPENSSL_X86
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
#define OPENSSL_64_BIT
|
||||||
|
#define OPENSSL_AARCH64
|
||||||
|
#elif defined(__arm) || defined(__arm__) || defined(_M_ARM)
|
||||||
|
#define OPENSSL_32_BIT
|
||||||
|
#define OPENSSL_ARM
|
||||||
|
#elif (defined(__PPC64__) || defined(__powerpc64__)) && defined(_LITTLE_ENDIAN)
|
||||||
|
#define OPENSSL_64_BIT
|
||||||
|
#define OPENSSL_PPC64LE
|
||||||
|
#elif defined(__mips__) && !defined(__LP64__)
|
||||||
|
#define OPENSSL_32_BIT
|
||||||
|
#define OPENSSL_MIPS
|
||||||
|
#elif defined(__mips__) && defined(__LP64__)
|
||||||
|
#define OPENSSL_64_BIT
|
||||||
|
#define OPENSSL_MIPS64
|
||||||
|
#elif defined(__pnacl__)
|
||||||
|
#define OPENSSL_32_BIT
|
||||||
|
#define OPENSSL_PNACL
|
||||||
|
#elif defined(__myriad2__)
|
||||||
|
#define OPENSSL_32_BIT
|
||||||
|
#else
|
||||||
|
#error "Unknown target CPU"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#define OPENSSL_APPLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define OPENSSL_WINDOWS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define OPENSSL_IS_BORINGSSL
|
||||||
|
#define OPENSSL_IS_RING
|
||||||
|
#define OPENSSL_VERSION_NUMBER 0x10002000
|
||||||
|
|
||||||
|
/* *ring* doesn't support the `BORINGSSL_SHARED_LIBRARY` configuration, so
|
||||||
|
* the default (usually "hidden") visibility is always used, even for exported
|
||||||
|
* items. */
|
||||||
|
#define OPENSSL_EXPORT
|
||||||
|
|
||||||
|
typedef struct bignum_st BIGNUM;
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern C */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* OPENSSL_HEADER_BASE_H */
|
||||||
256
test-generator/cbits/GFp/bn.h
Normal file
256
test-generator/cbits/GFp/bn.h
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This package is an SSL implementation written
|
||||||
|
* by Eric Young (eay@cryptsoft.com).
|
||||||
|
* The implementation was written so as to conform with Netscapes SSL.
|
||||||
|
*
|
||||||
|
* This library is free for commercial and non-commercial use as long as
|
||||||
|
* the following conditions are aheared to. The following conditions
|
||||||
|
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||||
|
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||||
|
* included with this distribution is covered by the same copyright terms
|
||||||
|
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||||
|
*
|
||||||
|
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||||
|
* the code are not to be removed.
|
||||||
|
* If this package is used in a product, Eric Young should be given attribution
|
||||||
|
* as the author of the parts of the library used.
|
||||||
|
* This can be in the form of a textual message at program startup or
|
||||||
|
* in documentation (online or textual) provided with the package.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* "This product includes cryptographic software written by
|
||||||
|
* Eric Young (eay@cryptsoft.com)"
|
||||||
|
* The word 'cryptographic' can be left out if the rouines from the library
|
||||||
|
* being used are not cryptographic related :-).
|
||||||
|
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||||
|
* the apps directory (application code) you must include an acknowledgement:
|
||||||
|
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The licence and distribution terms for any publically available version or
|
||||||
|
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||||
|
* copied and put under another distribution licence
|
||||||
|
* [including the GNU Public Licence.]
|
||||||
|
*/
|
||||||
|
/* ====================================================================
|
||||||
|
* Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this
|
||||||
|
* software must display the following acknowledgment:
|
||||||
|
* "This product includes software developed by the OpenSSL Project
|
||||||
|
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||||
|
*
|
||||||
|
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||||
|
* endorse or promote products derived from this software without
|
||||||
|
* prior written permission. For written permission, please contact
|
||||||
|
* openssl-core@openssl.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "OpenSSL"
|
||||||
|
* nor may "OpenSSL" appear in their names without prior written
|
||||||
|
* permission of the OpenSSL Project.
|
||||||
|
*
|
||||||
|
* 6. Redistributions of any form whatsoever must retain the following
|
||||||
|
* acknowledgment:
|
||||||
|
* "This product includes software developed by the OpenSSL Project
|
||||||
|
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||||
|
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This product includes cryptographic software written by Eric Young
|
||||||
|
* (eay@cryptsoft.com). This product includes software written by Tim
|
||||||
|
* Hudson (tjh@cryptsoft.com).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* ====================================================================
|
||||||
|
* Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
|
||||||
|
*
|
||||||
|
* Portions of the attached software ("Contribution") are developed by
|
||||||
|
* SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
|
||||||
|
*
|
||||||
|
* The Contribution is licensed pursuant to the Eric Young open source
|
||||||
|
* license provided above.
|
||||||
|
*
|
||||||
|
* The binary polynomial arithmetic software is originally written by
|
||||||
|
* Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
|
||||||
|
* Laboratories. */
|
||||||
|
|
||||||
|
#ifndef OPENSSL_HEADER_BN_H
|
||||||
|
#define OPENSSL_HEADER_BN_H
|
||||||
|
|
||||||
|
#include <GFp/base.h>
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* BN provides support for working with arbitrary sized integers. For example,
|
||||||
|
* although the largest integer supported by the compiler might be 64 bits, BN
|
||||||
|
* will allow you to work with numbers until you run out of memory. */
|
||||||
|
|
||||||
|
|
||||||
|
/* BN_ULONG is the native word size when working with big integers.
|
||||||
|
*
|
||||||
|
* Note: on some platforms, inttypes.h does not define print format macros in
|
||||||
|
* C++ unless |__STDC_FORMAT_MACROS| defined. As this is a public header, bn.h
|
||||||
|
* does not define |__STDC_FORMAT_MACROS| itself. C++ source files which use the
|
||||||
|
* FMT macros must define it externally. */
|
||||||
|
#if defined(OPENSSL_64_BIT)
|
||||||
|
#define BN_ULONG uint64_t
|
||||||
|
#define BN_BITS2 64
|
||||||
|
#elif defined(OPENSSL_32_BIT)
|
||||||
|
#define BN_ULONG uint32_t
|
||||||
|
#define BN_BITS2 32
|
||||||
|
#else
|
||||||
|
#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Allocation and freeing. */
|
||||||
|
|
||||||
|
/* GFp_BN_init initialises a stack allocated |BIGNUM|. */
|
||||||
|
OPENSSL_EXPORT void GFp_BN_init(BIGNUM *bn);
|
||||||
|
|
||||||
|
/* GFp_BN_free frees the data referenced by |bn| and, if |bn| was originally
|
||||||
|
* allocated on the heap, frees |bn| also. */
|
||||||
|
OPENSSL_EXPORT void GFp_BN_free(BIGNUM *bn);
|
||||||
|
|
||||||
|
/* GFp_BN_copy sets |dest| equal to |src| and returns one on success or zero on
|
||||||
|
* failure. */
|
||||||
|
OPENSSL_EXPORT int GFp_BN_copy(BIGNUM *dest, const BIGNUM *src);
|
||||||
|
|
||||||
|
|
||||||
|
/* Basic functions. */
|
||||||
|
|
||||||
|
/* GFp_BN_zero sets |bn| to zero. */
|
||||||
|
OPENSSL_EXPORT void GFp_BN_zero(BIGNUM *bn);
|
||||||
|
|
||||||
|
|
||||||
|
/* Internal functions.
|
||||||
|
*
|
||||||
|
* These functions are useful for code that is doing low-level manipulations of
|
||||||
|
* BIGNUM values. However, be sure that no other function in this file does
|
||||||
|
* what you want before turning to these. */
|
||||||
|
|
||||||
|
/* bn_correct_top decrements |bn->top| until |bn->d[top-1]| is non-zero or
|
||||||
|
* until |top| is zero. */
|
||||||
|
OPENSSL_EXPORT void GFp_bn_correct_top(BIGNUM *bn);
|
||||||
|
|
||||||
|
/* bn_wexpand ensures that |bn| has at least |words| works of space without
|
||||||
|
* altering its value. It returns one on success and zero on allocation
|
||||||
|
* failure. */
|
||||||
|
OPENSSL_EXPORT int GFp_bn_wexpand(BIGNUM *bn, size_t words);
|
||||||
|
|
||||||
|
|
||||||
|
/* Simple arithmetic */
|
||||||
|
|
||||||
|
/* GFp_BN_mul_no_alias sets |r| = |a| * |b|, where |r| must not be the same pointer
|
||||||
|
* as |a| or |b|. Returns one on success and zero otherwise. */
|
||||||
|
OPENSSL_EXPORT int GFp_BN_mul_no_alias(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
|
||||||
|
|
||||||
|
|
||||||
|
/* Comparison functions */
|
||||||
|
|
||||||
|
/* GFp_BN_is_odd returns one if |bn| is odd and zero otherwise. */
|
||||||
|
OPENSSL_EXPORT int GFp_BN_is_odd(const BIGNUM *bn);
|
||||||
|
|
||||||
|
|
||||||
|
/* Bitwise operations. */
|
||||||
|
|
||||||
|
/* GFp_BN_is_bit_set returns the value of the |n|th, least-significant bit in
|
||||||
|
* |a|, or zero if the bit doesn't exist. */
|
||||||
|
OPENSSL_EXPORT int GFp_BN_is_bit_set(const BIGNUM *a, int n);
|
||||||
|
|
||||||
|
|
||||||
|
/* Modulo arithmetic. */
|
||||||
|
|
||||||
|
/* GFp_BN_mod_mul_mont set |r| equal to |a| * |b|, in the Montgomery domain.
|
||||||
|
* Both |a| and |b| must already be in the Montgomery domain (by
|
||||||
|
* |GFp_BN_to_mont|). In particular, |a| and |b| are assumed to be in the range
|
||||||
|
* [0, n), where |n| is the Montgomery modulus. It returns one on success or
|
||||||
|
* zero on error. */
|
||||||
|
OPENSSL_EXPORT int GFp_BN_mod_mul_mont(
|
||||||
|
BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *n,
|
||||||
|
const BN_ULONG n0[/*BN_MONT_CTX_N0_LIMBS*/]);
|
||||||
|
|
||||||
|
/* GFp_BN_reduce_montgomery returns |a % n| in constant-ish time using
|
||||||
|
* Montgomery reduction. |a| is assumed to be in the range [0, n**2), where |n|
|
||||||
|
* is the Montgomery modulus. It returns one on success or zero on error. */
|
||||||
|
int GFp_BN_reduce_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *n,
|
||||||
|
const BN_ULONG n0[/*BN_MONT_CTX_N0_LIMBS*/]);
|
||||||
|
|
||||||
|
|
||||||
|
/* Exponentiation. */
|
||||||
|
|
||||||
|
OPENSSL_EXPORT int GFp_BN_mod_exp_mont_consttime(
|
||||||
|
BIGNUM *rr, const BIGNUM *a_mont, const BIGNUM *p, size_t p_bits,
|
||||||
|
const BIGNUM *one_mont, const BIGNUM *n,
|
||||||
|
const BN_ULONG n0[/*BN_MONT_CTX_N0_LIMBS*/]);
|
||||||
|
|
||||||
|
|
||||||
|
/* Private functions */
|
||||||
|
|
||||||
|
/* Keep in sync with `BIGNUM` in `ring::rsa::bigint`. */
|
||||||
|
struct bignum_st {
|
||||||
|
BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks in little-endian
|
||||||
|
order. */
|
||||||
|
int top; /* Index of last used element in |d|, plus one. */
|
||||||
|
int dmax; /* Size of |d|, in words. */
|
||||||
|
int flags; /* bitmask of BN_FLG_* values */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BN_FLG_MALLOCED 0x01
|
||||||
|
#define BN_FLG_STATIC_DATA 0x02
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern C */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* OPENSSL_HEADER_BN_H */
|
||||||
189
test-generator/cbits/GFp/cpu.h
Normal file
189
test-generator/cbits/GFp/cpu.h
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This package is an SSL implementation written
|
||||||
|
* by Eric Young (eay@cryptsoft.com).
|
||||||
|
* The implementation was written so as to conform with Netscapes SSL.
|
||||||
|
*
|
||||||
|
* This library is free for commercial and non-commercial use as long as
|
||||||
|
* the following conditions are aheared to. The following conditions
|
||||||
|
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||||
|
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||||
|
* included with this distribution is covered by the same copyright terms
|
||||||
|
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||||
|
*
|
||||||
|
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||||
|
* the code are not to be removed.
|
||||||
|
* If this package is used in a product, Eric Young should be given attribution
|
||||||
|
* as the author of the parts of the library used.
|
||||||
|
* This can be in the form of a textual message at program startup or
|
||||||
|
* in documentation (online or textual) provided with the package.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* "This product includes cryptographic software written by
|
||||||
|
* Eric Young (eay@cryptsoft.com)"
|
||||||
|
* The word 'cryptographic' can be left out if the rouines from the library
|
||||||
|
* being used are not cryptographic related :-).
|
||||||
|
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||||
|
* the apps directory (application code) you must include an acknowledgement:
|
||||||
|
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The licence and distribution terms for any publically available version or
|
||||||
|
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||||
|
* copied and put under another distribution licence
|
||||||
|
* [including the GNU Public Licence.]
|
||||||
|
*
|
||||||
|
* This product includes cryptographic software written by Eric Young
|
||||||
|
* (eay@cryptsoft.com). This product includes software written by Tim
|
||||||
|
* Hudson (tjh@cryptsoft.com). */
|
||||||
|
|
||||||
|
#ifndef OPENSSL_HEADER_CPU_H
|
||||||
|
#define OPENSSL_HEADER_CPU_H
|
||||||
|
|
||||||
|
#include <GFp/base.h>
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Runtime CPU feature support */
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
|
||||||
|
/* GFp_ia32cap_P contains the Intel CPUID bits when running on an x86 or
|
||||||
|
* x86-64 system.
|
||||||
|
*
|
||||||
|
* Index 0:
|
||||||
|
* EDX for CPUID where EAX = 1
|
||||||
|
* Bit 20 is always zero
|
||||||
|
* Bit 28 is adjusted to reflect whether the data cache is shared between
|
||||||
|
* multiple logical cores
|
||||||
|
* Bit 30 is used to indicate an Intel CPU
|
||||||
|
* Index 1:
|
||||||
|
* ECX for CPUID where EAX = 1
|
||||||
|
* Bit 11 is used to indicate AMD XOP support, not SDBG
|
||||||
|
* Index 2:
|
||||||
|
* EBX for CPUID where EAX = 7
|
||||||
|
* Index 3 is set to zero.
|
||||||
|
*
|
||||||
|
* Note: the CPUID bits are pre-adjusted for the OSXSAVE bit and the YMM and XMM
|
||||||
|
* bits in XCR0, so it is not necessary to check those. */
|
||||||
|
extern uint32_t GFp_ia32cap_P[4];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
|
||||||
|
|
||||||
|
#if defined(OPENSSL_APPLE)
|
||||||
|
/* iOS builds use the static ARM configuration. */
|
||||||
|
#define OPENSSL_STATIC_ARMCAP
|
||||||
|
|
||||||
|
#if defined(OPENSSL_AARCH64)
|
||||||
|
#define OPENSSL_STATIC_ARMCAP_AES
|
||||||
|
#define OPENSSL_STATIC_ARMCAP_SHA1
|
||||||
|
#define OPENSSL_STATIC_ARMCAP_SHA256
|
||||||
|
#define OPENSSL_STATIC_ARMCAP_PMULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(OPENSSL_STATIC_ARMCAP)
|
||||||
|
|
||||||
|
/* GFp_is_NEON_capable_at_runtime returns true if the current CPU has a NEON
|
||||||
|
* unit. Note that |OPENSSL_armcap_P| also exists and contains the same
|
||||||
|
* information in a form that's easier for assembly to use. */
|
||||||
|
OPENSSL_EXPORT uint8_t GFp_is_NEON_capable_at_runtime(void);
|
||||||
|
|
||||||
|
/* GFp_is_NEON_capable returns true if the current CPU has a NEON unit. If
|
||||||
|
* this is known statically then it returns one immediately. */
|
||||||
|
static inline int GFp_is_NEON_capable(void) {
|
||||||
|
/* On 32-bit ARM, one CPU is known to have a broken NEON unit which is known
|
||||||
|
* to fail with on some hand-written NEON assembly. Assume that non-Android
|
||||||
|
* applications will not use that buggy CPU but still support Android users
|
||||||
|
* that do, even when the compiler is instructed to freely emit NEON code.
|
||||||
|
* See https://crbug.com/341598 and https://crbug.com/606629. */
|
||||||
|
#if defined(__ARM_NEON__) && (!defined(OPENSSL_ARM) || !defined(__ANDROID__))
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
return GFp_is_NEON_capable_at_runtime();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(OPENSSL_ARM)
|
||||||
|
/* GFp_has_broken_NEON returns one if the current CPU is known to have a
|
||||||
|
* broken NEON unit. See https://crbug.com/341598. */
|
||||||
|
OPENSSL_EXPORT int GFp_has_broken_NEON(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* GFp_is_ARMv8_AES_capable returns true if the current CPU supports the
|
||||||
|
* ARMv8 AES instruction. */
|
||||||
|
int GFp_is_ARMv8_AES_capable(void);
|
||||||
|
|
||||||
|
/* GFp_is_ARMv8_PMULL_capable returns true if the current CPU supports the
|
||||||
|
* ARMv8 PMULL instruction. */
|
||||||
|
int GFp_is_ARMv8_PMULL_capable(void);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline int GFp_is_NEON_capable(void) {
|
||||||
|
#if defined(OPENSSL_STATIC_ARMCAP_NEON) || defined(__ARM_NEON__)
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int GFp_is_ARMv8_AES_capable(void) {
|
||||||
|
#if defined(OPENSSL_STATIC_ARMCAP_AES)
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int GFp_is_ARMv8_PMULL_capable(void) {
|
||||||
|
#if defined(OPENSSL_STATIC_ARMCAP_PMULL)
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* OPENSSL_STATIC_ARMCAP */
|
||||||
|
#endif /* OPENSSL_ARM || OPENSSL_AARCH64 */
|
||||||
|
|
||||||
|
#if defined(OPENSSL_PPC64LE)
|
||||||
|
|
||||||
|
/* CRYPTO_is_PPC64LE_vcrypto_capable returns true iff the current CPU supports
|
||||||
|
* the Vector.AES category of instructions. */
|
||||||
|
int CRYPTO_is_PPC64LE_vcrypto_capable(void);
|
||||||
|
|
||||||
|
#endif /* OPENSSL_PPC64LE */
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern C */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* OPENSSL_HEADER_CPU_H */
|
||||||
93
test-generator/cbits/GFp/mem.h
Normal file
93
test-generator/cbits/GFp/mem.h
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This package is an SSL implementation written
|
||||||
|
* by Eric Young (eay@cryptsoft.com).
|
||||||
|
* The implementation was written so as to conform with Netscapes SSL.
|
||||||
|
*
|
||||||
|
* This library is free for commercial and non-commercial use as long as
|
||||||
|
* the following conditions are aheared to. The following conditions
|
||||||
|
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||||
|
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||||
|
* included with this distribution is covered by the same copyright terms
|
||||||
|
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||||
|
*
|
||||||
|
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||||
|
* the code are not to be removed.
|
||||||
|
* If this package is used in a product, Eric Young should be given attribution
|
||||||
|
* as the author of the parts of the library used.
|
||||||
|
* This can be in the form of a textual message at program startup or
|
||||||
|
* in documentation (online or textual) provided with the package.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* "This product includes cryptographic software written by
|
||||||
|
* Eric Young (eay@cryptsoft.com)"
|
||||||
|
* The word 'cryptographic' can be left out if the rouines from the library
|
||||||
|
* being used are not cryptographic related :-).
|
||||||
|
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||||
|
* the apps directory (application code) you must include an acknowledgement:
|
||||||
|
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The licence and distribution terms for any publically available version or
|
||||||
|
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||||
|
* copied and put under another distribution licence
|
||||||
|
* [including the GNU Public Licence.] */
|
||||||
|
|
||||||
|
#ifndef OPENSSL_HEADER_MEM_H
|
||||||
|
#define OPENSSL_HEADER_MEM_H
|
||||||
|
|
||||||
|
#include <GFp/base.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Memory and string functions, see also buf.h.
|
||||||
|
*
|
||||||
|
* OpenSSL has, historically, had a complex set of malloc debugging options.
|
||||||
|
* However, that was written in a time before Valgrind and ASAN. Since we now
|
||||||
|
* have those tools, the OpenSSL allocation functions are simply macros around
|
||||||
|
* the standard memory functions. */
|
||||||
|
|
||||||
|
|
||||||
|
#define OPENSSL_malloc malloc
|
||||||
|
#define OPENSSL_realloc realloc
|
||||||
|
#define OPENSSL_free free
|
||||||
|
|
||||||
|
/* GFp_memcmp returns zero iff the |len| bytes at |a| and |b| are equal. It
|
||||||
|
* takes an amount of time dependent on |len|, but independent of the contents
|
||||||
|
* of |a| and |b|. Unlike memcmp, it cannot be used to put elements into a
|
||||||
|
* defined order as the return value when a != b is undefined, other than to be
|
||||||
|
* non-zero. */
|
||||||
|
OPENSSL_EXPORT int GFp_memcmp(const void *a, const void *b, size_t len);
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern C */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* OPENSSL_HEADER_MEM_H */
|
||||||
75
test-generator/cbits/GFp/type_check.h
Normal file
75
test-generator/cbits/GFp/type_check.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This package is an SSL implementation written
|
||||||
|
* by Eric Young (eay@cryptsoft.com).
|
||||||
|
* The implementation was written so as to conform with Netscapes SSL.
|
||||||
|
*
|
||||||
|
* This library is free for commercial and non-commercial use as long as
|
||||||
|
* the following conditions are aheared to. The following conditions
|
||||||
|
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||||
|
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||||
|
* included with this distribution is covered by the same copyright terms
|
||||||
|
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||||
|
*
|
||||||
|
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||||
|
* the code are not to be removed.
|
||||||
|
* If this package is used in a product, Eric Young should be given attribution
|
||||||
|
* as the author of the parts of the library used.
|
||||||
|
* This can be in the form of a textual message at program startup or
|
||||||
|
* in documentation (online or textual) provided with the package.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* "This product includes cryptographic software written by
|
||||||
|
* Eric Young (eay@cryptsoft.com)"
|
||||||
|
* The word 'cryptographic' can be left out if the rouines from the library
|
||||||
|
* being used are not cryptographic related :-).
|
||||||
|
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||||
|
* the apps directory (application code) you must include an acknowledgement:
|
||||||
|
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The licence and distribution terms for any publically available version or
|
||||||
|
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||||
|
* copied and put under another distribution licence
|
||||||
|
* [including the GNU Public Licence.] */
|
||||||
|
|
||||||
|
#ifndef OPENSSL_HEADER_TYPE_CHECK_H
|
||||||
|
#define OPENSSL_HEADER_TYPE_CHECK_H
|
||||||
|
|
||||||
|
#include <GFp/base.h>
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||||
|
#define OPENSSL_COMPILE_ASSERT(cond, msg) _Static_assert(cond, #msg)
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define OPENSSL_COMPILE_ASSERT(cond, msg) \
|
||||||
|
typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)] \
|
||||||
|
__attribute__((unused))
|
||||||
|
#else
|
||||||
|
#define OPENSSL_COMPILE_ASSERT(cond, msg) \
|
||||||
|
typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* OPENSSL_HEADER_TYPE_CHECK_H */
|
||||||
2133
test-generator/cbits/asm/x25519-asm-arm.S
Normal file
2133
test-generator/cbits/asm/x25519-asm-arm.S
Normal file
File diff suppressed because it is too large
Load Diff
1921
test-generator/cbits/asm/x25519-asm-x86_64.S
Normal file
1921
test-generator/cbits/asm/x25519-asm-x86_64.S
Normal file
File diff suppressed because it is too large
Load Diff
4726
test-generator/cbits/curve25519.c
Normal file
4726
test-generator/cbits/curve25519.c
Normal file
File diff suppressed because it is too large
Load Diff
109
test-generator/cbits/internal.h
Normal file
109
test-generator/cbits/internal.h
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/* Copyright (c) 2015, Google Inc.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||||
|
|
||||||
|
#ifndef OPENSSL_HEADER_CURVE25519_INTERNAL_H
|
||||||
|
#define OPENSSL_HEADER_CURVE25519_INTERNAL_H
|
||||||
|
|
||||||
|
#include <GFp/base.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(OPENSSL_X86_64) && !defined(OPENSSL_SMALL) && \
|
||||||
|
!defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_ASM)
|
||||||
|
/* This isn't compatible with Windows because the asm code makes use of the red
|
||||||
|
* zone, which Windows doesn't support. */
|
||||||
|
#define BORINGSSL_X25519_X86_64
|
||||||
|
|
||||||
|
void GFp_x25519_x86_64(uint8_t out[32], const uint8_t scalar[32],
|
||||||
|
const uint8_t point[32]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
|
||||||
|
#define BORINGSSL_X25519_NEON
|
||||||
|
|
||||||
|
/* x25519_NEON is defined in asm/x25519-arm.S. */
|
||||||
|
void GFp_x25519_NEON(uint8_t out[32], const uint8_t scalar[32],
|
||||||
|
const uint8_t point[32]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* fe means field element. Here the field is \Z/(2^255-19). An element t,
|
||||||
|
* entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
|
||||||
|
* t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
|
||||||
|
* context.
|
||||||
|
*
|
||||||
|
* Keep in sync with `Elem` and `ELEM_LIMBS` in curve25519/ops.rs. */
|
||||||
|
typedef int32_t fe[10];
|
||||||
|
|
||||||
|
/* ge means group element.
|
||||||
|
|
||||||
|
* Here the group is the set of pairs (x,y) of field elements (see fe.h)
|
||||||
|
* satisfying -x^2 + y^2 = 1 + d x^2y^2
|
||||||
|
* where d = -121665/121666.
|
||||||
|
*
|
||||||
|
* Representations:
|
||||||
|
* ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
|
||||||
|
* ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
|
||||||
|
* ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
|
||||||
|
* ge_precomp (Duif): (y+x,y-x,2dxy)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Keep in sync with `Point` in curve25519/ops.rs. */
|
||||||
|
typedef struct {
|
||||||
|
fe X;
|
||||||
|
fe Y;
|
||||||
|
fe Z;
|
||||||
|
} ge_p2;
|
||||||
|
|
||||||
|
|
||||||
|
/* Keep in sync with `ExtPoint` in curve25519/ops.rs. */
|
||||||
|
typedef struct {
|
||||||
|
fe X;
|
||||||
|
fe Y;
|
||||||
|
fe Z;
|
||||||
|
fe T;
|
||||||
|
} ge_p3;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
fe X;
|
||||||
|
fe Y;
|
||||||
|
fe Z;
|
||||||
|
fe T;
|
||||||
|
} ge_p1p1;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
fe yplusx;
|
||||||
|
fe yminusx;
|
||||||
|
fe xy2d;
|
||||||
|
} ge_precomp;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
fe YplusX;
|
||||||
|
fe YminusX;
|
||||||
|
fe Z;
|
||||||
|
fe T2d;
|
||||||
|
} ge_cached;
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern C */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* OPENSSL_HEADER_CURVE25519_INTERNAL_H */
|
||||||
361
test-generator/cbits/internal2.h
Normal file
361
test-generator/cbits/internal2.h
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This package is an SSL implementation written
|
||||||
|
* by Eric Young (eay@cryptsoft.com).
|
||||||
|
* The implementation was written so as to conform with Netscapes SSL.
|
||||||
|
*
|
||||||
|
* This library is free for commercial and non-commercial use as long as
|
||||||
|
* the following conditions are aheared to. The following conditions
|
||||||
|
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||||
|
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||||
|
* included with this distribution is covered by the same copyright terms
|
||||||
|
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||||
|
*
|
||||||
|
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||||
|
* the code are not to be removed.
|
||||||
|
* If this package is used in a product, Eric Young should be given attribution
|
||||||
|
* as the author of the parts of the library used.
|
||||||
|
* This can be in the form of a textual message at program startup or
|
||||||
|
* in documentation (online or textual) provided with the package.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* "This product includes cryptographic software written by
|
||||||
|
* Eric Young (eay@cryptsoft.com)"
|
||||||
|
* The word 'cryptographic' can be left out if the rouines from the library
|
||||||
|
* being used are not cryptographic related :-).
|
||||||
|
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||||
|
* the apps directory (application code) you must include an acknowledgement:
|
||||||
|
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The licence and distribution terms for any publically available version or
|
||||||
|
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||||
|
* copied and put under another distribution licence
|
||||||
|
* [including the GNU Public Licence.]
|
||||||
|
*/
|
||||||
|
/* ====================================================================
|
||||||
|
* Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this
|
||||||
|
* software must display the following acknowledgment:
|
||||||
|
* "This product includes software developed by the OpenSSL Project
|
||||||
|
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||||
|
*
|
||||||
|
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||||
|
* endorse or promote products derived from this software without
|
||||||
|
* prior written permission. For written permission, please contact
|
||||||
|
* openssl-core@openssl.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "OpenSSL"
|
||||||
|
* nor may "OpenSSL" appear in their names without prior written
|
||||||
|
* permission of the OpenSSL Project.
|
||||||
|
*
|
||||||
|
* 6. Redistributions of any form whatsoever must retain the following
|
||||||
|
* acknowledgment:
|
||||||
|
* "This product includes software developed by the OpenSSL Project
|
||||||
|
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||||
|
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This product includes cryptographic software written by Eric Young
|
||||||
|
* (eay@cryptsoft.com). This product includes software written by Tim
|
||||||
|
* Hudson (tjh@cryptsoft.com). */
|
||||||
|
|
||||||
|
#ifndef OPENSSL_HEADER_CRYPTO_INTERNAL_H
|
||||||
|
#define OPENSSL_HEADER_CRYPTO_INTERNAL_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#if defined(__clang__) || defined(_MSC_VER)
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <GFp/base.h>
|
||||||
|
#include <GFp/type_check.h>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(push, 3)
|
||||||
|
#include <intrin.h>
|
||||||
|
#pragma warning(pop)
|
||||||
|
#if !defined(__cplusplus)
|
||||||
|
#define alignas(x) __declspec(align(x))
|
||||||
|
#define alignof __alignof
|
||||||
|
#endif
|
||||||
|
#elif !defined(__clang__) && defined(__GNUC__) && __GNUC__ == 4 && \
|
||||||
|
__GNUC_MINOR__ <= 6
|
||||||
|
#define alignas(x) __attribute__((aligned (x)))
|
||||||
|
#define alignof __alignof__
|
||||||
|
#else
|
||||||
|
#include <stdalign.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM) || \
|
||||||
|
defined(OPENSSL_AARCH64) || defined(OPENSSL_PPC64LE)
|
||||||
|
/* OPENSSL_cpuid_setup initializes the platform-specific feature cache. */
|
||||||
|
void GFp_cpuid_setup(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define OPENSSL_LITTLE_ENDIAN 1
|
||||||
|
#define OPENSSL_BIG_ENDIAN 2
|
||||||
|
|
||||||
|
#if defined(OPENSSL_X86_64) || defined(OPENSSL_X86) || \
|
||||||
|
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
|
||||||
|
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||||
|
#define OPENSSL_ENDIAN OPENSSL_LITTLE_ENDIAN
|
||||||
|
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
|
||||||
|
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||||
|
#define OPENSSL_ENDIAN OPENSSL_BIG_ENDIAN
|
||||||
|
#else
|
||||||
|
#error "Cannot determine endianness"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define bswap_u32(x) __builtin_bswap32(x)
|
||||||
|
#define bswap_u64(x) __builtin_bswap64(x)
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#pragma intrinsic(_byteswap_ulong, _byteswap_uint64)
|
||||||
|
#define bswap_u32(x) _byteswap_ulong(x)
|
||||||
|
#define bswap_u64(x) _byteswap_uint64(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(_MSC_VER) && defined(OPENSSL_64_BIT)
|
||||||
|
typedef __int128_t int128_t;
|
||||||
|
typedef __uint128_t uint128_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Constant-time utility functions.
|
||||||
|
*
|
||||||
|
* The following methods return a bitmask of all ones (0xff...f) for true and 0
|
||||||
|
* for false. This is useful for choosing a value based on the result of a
|
||||||
|
* conditional in constant time. */
|
||||||
|
|
||||||
|
/* constant_time_msb returns the given value with the MSB copied to all the
|
||||||
|
* other bits. */
|
||||||
|
static inline unsigned int constant_time_msb_unsigned(unsigned int a) {
|
||||||
|
return (unsigned int)((int)(a) >> (sizeof(int) * 8 - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
OPENSSL_COMPILE_ASSERT(sizeof(ptrdiff_t) == sizeof(size_t),
|
||||||
|
ptrdiff_t_and_size_t_are_different_sizes);
|
||||||
|
|
||||||
|
static inline size_t constant_time_msb_size_t(size_t a) {
|
||||||
|
return (size_t)((ptrdiff_t)(a) >> (sizeof(ptrdiff_t) * 8 - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* constant_time_is_zero returns 0xff..f if a == 0 and 0 otherwise. */
|
||||||
|
static inline unsigned int constant_time_is_zero_unsigned(unsigned int a) {
|
||||||
|
/* Here is an SMT-LIB verification of this formula:
|
||||||
|
*
|
||||||
|
* (define-fun is_zero ((a (_ BitVec 32))) (_ BitVec 32)
|
||||||
|
* (bvand (bvnot a) (bvsub a #x00000001))
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* (declare-fun a () (_ BitVec 32))
|
||||||
|
*
|
||||||
|
* (assert (not (= (= #x00000001 (bvlshr (is_zero a) #x0000001f)) (= a #x00000000))))
|
||||||
|
* (check-sat)
|
||||||
|
* (get-model)
|
||||||
|
*/
|
||||||
|
return constant_time_msb_unsigned(~a & (a - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* constant_time_is_zero_size_t is like |constant_time_is_zero_unsigned| but
|
||||||
|
* operates on |size_t|. */
|
||||||
|
static inline size_t constant_time_is_zero_size_t(size_t a) {
|
||||||
|
return constant_time_msb_size_t(~a & (a - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t constant_time_is_nonzero_size_t(size_t a) {
|
||||||
|
return constant_time_is_zero_size_t(constant_time_is_zero_size_t(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* constant_time_eq_int returns 0xff..f if a == b and 0 otherwise. */
|
||||||
|
static inline unsigned int constant_time_eq_int(int a, int b) {
|
||||||
|
return constant_time_is_zero_unsigned((unsigned)(a) ^ (unsigned)(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* constant_time_eq_size_t acts like |constant_time_eq_int| but operates on
|
||||||
|
* |size_t|. */
|
||||||
|
static inline size_t constant_time_eq_size_t(size_t a, size_t b) {
|
||||||
|
return constant_time_is_zero_size_t(a ^ b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* constant_time_select_size_t returns (mask & a) | (~mask & b). When |mask| is
|
||||||
|
* all 1s or all 0s (as returned by the methods above), the select methods
|
||||||
|
* return either |a| (if |mask| is nonzero) or |b| (if |mask| is zero). it is
|
||||||
|
* derived from BoringSSL's |constant_time_select|. */
|
||||||
|
static inline size_t constant_time_select_size_t(size_t mask, size_t a,
|
||||||
|
size_t b) {
|
||||||
|
return (mask & a) | (~mask & b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* from_be_u32_ptr returns the 32-bit big-endian-encoded value at |data|. */
|
||||||
|
static inline uint32_t from_be_u32_ptr(const uint8_t *data) {
|
||||||
|
#if defined(__clang__) || defined(_MSC_VER)
|
||||||
|
/* XXX: Unlike GCC, Clang doesn't optimize compliant access to unaligned data
|
||||||
|
* well. See https://llvm.org/bugs/show_bug.cgi?id=20605,
|
||||||
|
* https://llvm.org/bugs/show_bug.cgi?id=17603,
|
||||||
|
* http://blog.regehr.org/archives/702, and
|
||||||
|
* http://blog.regehr.org/archives/1055. MSVC seems to have similar problems.
|
||||||
|
*/
|
||||||
|
uint32_t value;
|
||||||
|
memcpy(&value, data, sizeof(value));
|
||||||
|
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
|
||||||
|
value = bswap_u32(value);
|
||||||
|
#endif
|
||||||
|
return value;
|
||||||
|
#else
|
||||||
|
return ((uint32_t)data[0] << 24) |
|
||||||
|
((uint32_t)data[1] << 16) |
|
||||||
|
((uint32_t)data[2] << 8) |
|
||||||
|
((uint32_t)data[3]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* from_be_u64_ptr returns the 64-bit big-endian-encoded value at |data|. */
|
||||||
|
static inline uint64_t from_be_u64_ptr(const uint8_t *data) {
|
||||||
|
#if defined(__clang__) || defined(_MSC_VER)
|
||||||
|
/* XXX: Unlike GCC, Clang doesn't optimize compliant access to unaligned data
|
||||||
|
* well. See https://llvm.org/bugs/show_bug.cgi?id=20605,
|
||||||
|
* https://llvm.org/bugs/show_bug.cgi?id=17603,
|
||||||
|
* http://blog.regehr.org/archives/702, and
|
||||||
|
* http://blog.regehr.org/archives/1055. MSVC seems to have similar problems.
|
||||||
|
*/
|
||||||
|
uint64_t value;
|
||||||
|
memcpy(&value, data, sizeof(value));
|
||||||
|
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
|
||||||
|
value = bswap_u64(value);
|
||||||
|
#endif
|
||||||
|
return value;
|
||||||
|
#else
|
||||||
|
return ((uint64_t)data[0] << 56) |
|
||||||
|
((uint64_t)data[1] << 48) |
|
||||||
|
((uint64_t)data[2] << 40) |
|
||||||
|
((uint64_t)data[3] << 32) |
|
||||||
|
((uint64_t)data[4] << 24) |
|
||||||
|
((uint64_t)data[5] << 16) |
|
||||||
|
((uint64_t)data[6] << 8) |
|
||||||
|
((uint64_t)data[7]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* to_be_u32_ptr writes the value |x| to the location |out| in big-endian
|
||||||
|
order. */
|
||||||
|
static inline void to_be_u32_ptr(uint8_t *out, uint32_t value) {
|
||||||
|
#if defined(__clang__) || defined(_MSC_VER)
|
||||||
|
/* XXX: Unlike GCC, Clang doesn't optimize compliant access to unaligned data
|
||||||
|
* well. See https://llvm.org/bugs/show_bug.cgi?id=20605,
|
||||||
|
* https://llvm.org/bugs/show_bug.cgi?id=17603,
|
||||||
|
* http://blog.regehr.org/archives/702, and
|
||||||
|
* http://blog.regehr.org/archives/1055. MSVC seems to have similar problems.
|
||||||
|
*/
|
||||||
|
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
|
||||||
|
value = bswap_u32(value);
|
||||||
|
#endif
|
||||||
|
memcpy(out, &value, sizeof(value));
|
||||||
|
#else
|
||||||
|
out[0] = (uint8_t)(value >> 24);
|
||||||
|
out[1] = (uint8_t)(value >> 16);
|
||||||
|
out[2] = (uint8_t)(value >> 8);
|
||||||
|
out[3] = (uint8_t)value;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* to_be_u64_ptr writes the value |value| to the location |out| in big-endian
|
||||||
|
order. */
|
||||||
|
static inline void to_be_u64_ptr(uint8_t *out, uint64_t value) {
|
||||||
|
#if defined(__clang__) || defined(_MSC_VER)
|
||||||
|
/* XXX: Unlike GCC, Clang doesn't optimize compliant access to unaligned data
|
||||||
|
* well. See https://llvm.org/bugs/show_bug.cgi?id=20605,
|
||||||
|
* https://llvm.org/bugs/show_bug.cgi?id=17603,
|
||||||
|
* http://blog.regehr.org/archives/702, and
|
||||||
|
* http://blog.regehr.org/archives/1055. MSVC seems to have similar problems.
|
||||||
|
*/
|
||||||
|
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
|
||||||
|
value = bswap_u64(value);
|
||||||
|
#endif
|
||||||
|
memcpy(out, &value, sizeof(value));
|
||||||
|
#else
|
||||||
|
out[0] = (uint8_t)(value >> 56);
|
||||||
|
out[1] = (uint8_t)(value >> 48);
|
||||||
|
out[2] = (uint8_t)(value >> 40);
|
||||||
|
out[3] = (uint8_t)(value >> 32);
|
||||||
|
out[4] = (uint8_t)(value >> 24);
|
||||||
|
out[5] = (uint8_t)(value >> 16);
|
||||||
|
out[6] = (uint8_t)(value >> 8);
|
||||||
|
out[7] = (uint8_t)value;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* from_be_u64 returns the native representation of the 64-bit
|
||||||
|
* big-endian-encoded value |x|. */
|
||||||
|
static inline uint64_t from_be_u64(uint64_t x) {
|
||||||
|
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
|
||||||
|
x = bswap_u64(x);
|
||||||
|
#endif
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern C */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* OPENSSL_HEADER_CRYPTO_INTERNAL_H */
|
||||||
1921
test-generator/cbits/x25519-asm-x86_64.S
Normal file
1921
test-generator/cbits/x25519-asm-x86_64.S
Normal file
File diff suppressed because it is too large
Load Diff
244
test-generator/cbits/x25519-x86_64.c
Normal file
244
test-generator/cbits/x25519-x86_64.c
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
/* Copyright (c) 2015, Google Inc.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||||
|
|
||||||
|
/* This code is mostly taken from the ref10 version of Ed25519 in SUPERCOP
|
||||||
|
* 20141124 (http://bench.cr.yp.to/supercop.html). That code is released as
|
||||||
|
* public domain but this file has the ISC license just to keep licencing
|
||||||
|
* simple.
|
||||||
|
*
|
||||||
|
* The field functions are shared by Ed25519 and X25519 where possible. */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(BORINGSSL_X25519_X86_64)
|
||||||
|
|
||||||
|
typedef struct { uint64_t v[5]; } fe25519;
|
||||||
|
|
||||||
|
/* These functions are defined in asm/x25519-x86_64.S */
|
||||||
|
void GFp_x25519_x86_64_work_cswap(fe25519 *, uint64_t);
|
||||||
|
void GFp_x25519_x86_64_mul(fe25519 *out, const fe25519 *a, const fe25519 *b);
|
||||||
|
void GFp_x25519_x86_64_square(fe25519 *out, const fe25519 *a);
|
||||||
|
void GFp_x25519_x86_64_freeze(fe25519 *);
|
||||||
|
void GFp_x25519_x86_64_ladderstep(fe25519 *work);
|
||||||
|
|
||||||
|
static void fe25519_setint(fe25519 *r, unsigned v) {
|
||||||
|
r->v[0] = v;
|
||||||
|
r->v[1] = 0;
|
||||||
|
r->v[2] = 0;
|
||||||
|
r->v[3] = 0;
|
||||||
|
r->v[4] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assumes input x being reduced below 2^255 */
|
||||||
|
static void fe25519_pack(unsigned char r[32], const fe25519 *x) {
|
||||||
|
fe25519 t;
|
||||||
|
t = *x;
|
||||||
|
GFp_x25519_x86_64_freeze(&t);
|
||||||
|
|
||||||
|
r[0] = (uint8_t)(t.v[0] & 0xff);
|
||||||
|
r[1] = (uint8_t)((t.v[0] >> 8) & 0xff);
|
||||||
|
r[2] = (uint8_t)((t.v[0] >> 16) & 0xff);
|
||||||
|
r[3] = (uint8_t)((t.v[0] >> 24) & 0xff);
|
||||||
|
r[4] = (uint8_t)((t.v[0] >> 32) & 0xff);
|
||||||
|
r[5] = (uint8_t)((t.v[0] >> 40) & 0xff);
|
||||||
|
r[6] = (uint8_t)((t.v[0] >> 48));
|
||||||
|
|
||||||
|
r[6] ^= (uint8_t)((t.v[1] << 3) & 0xf8);
|
||||||
|
r[7] = (uint8_t)((t.v[1] >> 5) & 0xff);
|
||||||
|
r[8] = (uint8_t)((t.v[1] >> 13) & 0xff);
|
||||||
|
r[9] = (uint8_t)((t.v[1] >> 21) & 0xff);
|
||||||
|
r[10] = (uint8_t)((t.v[1] >> 29) & 0xff);
|
||||||
|
r[11] = (uint8_t)((t.v[1] >> 37) & 0xff);
|
||||||
|
r[12] = (uint8_t)((t.v[1] >> 45));
|
||||||
|
|
||||||
|
r[12] ^= (uint8_t)((t.v[2] << 6) & 0xc0);
|
||||||
|
r[13] = (uint8_t)((t.v[2] >> 2) & 0xff);
|
||||||
|
r[14] = (uint8_t)((t.v[2] >> 10) & 0xff);
|
||||||
|
r[15] = (uint8_t)((t.v[2] >> 18) & 0xff);
|
||||||
|
r[16] = (uint8_t)((t.v[2] >> 26) & 0xff);
|
||||||
|
r[17] = (uint8_t)((t.v[2] >> 34) & 0xff);
|
||||||
|
r[18] = (uint8_t)((t.v[2] >> 42) & 0xff);
|
||||||
|
r[19] = (uint8_t)((t.v[2] >> 50));
|
||||||
|
|
||||||
|
r[19] ^= (uint8_t)((t.v[3] << 1) & 0xfe);
|
||||||
|
r[20] = (uint8_t)((t.v[3] >> 7) & 0xff);
|
||||||
|
r[21] = (uint8_t)((t.v[3] >> 15) & 0xff);
|
||||||
|
r[22] = (uint8_t)((t.v[3] >> 23) & 0xff);
|
||||||
|
r[23] = (uint8_t)((t.v[3] >> 31) & 0xff);
|
||||||
|
r[24] = (uint8_t)((t.v[3] >> 39) & 0xff);
|
||||||
|
r[25] = (uint8_t)((t.v[3] >> 47));
|
||||||
|
|
||||||
|
r[25] ^= (uint8_t)((t.v[4] << 4) & 0xf0);
|
||||||
|
r[26] = (uint8_t)((t.v[4] >> 4) & 0xff);
|
||||||
|
r[27] = (uint8_t)((t.v[4] >> 12) & 0xff);
|
||||||
|
r[28] = (uint8_t)((t.v[4] >> 20) & 0xff);
|
||||||
|
r[29] = (uint8_t)((t.v[4] >> 28) & 0xff);
|
||||||
|
r[30] = (uint8_t)((t.v[4] >> 36) & 0xff);
|
||||||
|
r[31] = (uint8_t)((t.v[4] >> 44));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fe25519_unpack(fe25519 *r, const uint8_t x[32]) {
|
||||||
|
r->v[0] = x[0];
|
||||||
|
r->v[0] += (uint64_t)x[1] << 8;
|
||||||
|
r->v[0] += (uint64_t)x[2] << 16;
|
||||||
|
r->v[0] += (uint64_t)x[3] << 24;
|
||||||
|
r->v[0] += (uint64_t)x[4] << 32;
|
||||||
|
r->v[0] += (uint64_t)x[5] << 40;
|
||||||
|
r->v[0] += ((uint64_t)x[6] & 7) << 48;
|
||||||
|
|
||||||
|
r->v[1] = x[6] >> 3;
|
||||||
|
r->v[1] += (uint64_t)x[7] << 5;
|
||||||
|
r->v[1] += (uint64_t)x[8] << 13;
|
||||||
|
r->v[1] += (uint64_t)x[9] << 21;
|
||||||
|
r->v[1] += (uint64_t)x[10] << 29;
|
||||||
|
r->v[1] += (uint64_t)x[11] << 37;
|
||||||
|
r->v[1] += ((uint64_t)x[12] & 63) << 45;
|
||||||
|
|
||||||
|
r->v[2] = x[12] >> 6;
|
||||||
|
r->v[2] += (uint64_t)x[13] << 2;
|
||||||
|
r->v[2] += (uint64_t)x[14] << 10;
|
||||||
|
r->v[2] += (uint64_t)x[15] << 18;
|
||||||
|
r->v[2] += (uint64_t)x[16] << 26;
|
||||||
|
r->v[2] += (uint64_t)x[17] << 34;
|
||||||
|
r->v[2] += (uint64_t)x[18] << 42;
|
||||||
|
r->v[2] += ((uint64_t)x[19] & 1) << 50;
|
||||||
|
|
||||||
|
r->v[3] = x[19] >> 1;
|
||||||
|
r->v[3] += (uint64_t)x[20] << 7;
|
||||||
|
r->v[3] += (uint64_t)x[21] << 15;
|
||||||
|
r->v[3] += (uint64_t)x[22] << 23;
|
||||||
|
r->v[3] += (uint64_t)x[23] << 31;
|
||||||
|
r->v[3] += (uint64_t)x[24] << 39;
|
||||||
|
r->v[3] += ((uint64_t)x[25] & 15) << 47;
|
||||||
|
|
||||||
|
r->v[4] = x[25] >> 4;
|
||||||
|
r->v[4] += (uint64_t)x[26] << 4;
|
||||||
|
r->v[4] += (uint64_t)x[27] << 12;
|
||||||
|
r->v[4] += (uint64_t)x[28] << 20;
|
||||||
|
r->v[4] += (uint64_t)x[29] << 28;
|
||||||
|
r->v[4] += (uint64_t)x[30] << 36;
|
||||||
|
r->v[4] += ((uint64_t)x[31] & 127) << 44;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fe25519_invert(fe25519 *r, const fe25519 *x) {
|
||||||
|
fe25519 z2;
|
||||||
|
fe25519 z9;
|
||||||
|
fe25519 z11;
|
||||||
|
fe25519 z2_5_0;
|
||||||
|
fe25519 z2_10_0;
|
||||||
|
fe25519 z2_20_0;
|
||||||
|
fe25519 z2_50_0;
|
||||||
|
fe25519 z2_100_0;
|
||||||
|
fe25519 t;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* 2 */ GFp_x25519_x86_64_square(&z2, x);
|
||||||
|
/* 4 */ GFp_x25519_x86_64_square(&t, &z2);
|
||||||
|
/* 8 */ GFp_x25519_x86_64_square(&t, &t);
|
||||||
|
/* 9 */ GFp_x25519_x86_64_mul(&z9, &t, x);
|
||||||
|
/* 11 */ GFp_x25519_x86_64_mul(&z11, &z9, &z2);
|
||||||
|
/* 22 */ GFp_x25519_x86_64_square(&t, &z11);
|
||||||
|
/* 2^5 - 2^0 = 31 */ GFp_x25519_x86_64_mul(&z2_5_0, &t, &z9);
|
||||||
|
|
||||||
|
/* 2^6 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_5_0);
|
||||||
|
/* 2^20 - 2^10 */ for (i = 1; i < 5; i++) { GFp_x25519_x86_64_square(&t, &t); }
|
||||||
|
/* 2^10 - 2^0 */ GFp_x25519_x86_64_mul(&z2_10_0, &t, &z2_5_0);
|
||||||
|
|
||||||
|
/* 2^11 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_10_0);
|
||||||
|
/* 2^20 - 2^10 */ for (i = 1; i < 10; i++) { GFp_x25519_x86_64_square(&t, &t); }
|
||||||
|
/* 2^20 - 2^0 */ GFp_x25519_x86_64_mul(&z2_20_0, &t, &z2_10_0);
|
||||||
|
|
||||||
|
/* 2^21 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_20_0);
|
||||||
|
/* 2^40 - 2^20 */ for (i = 1; i < 20; i++) { GFp_x25519_x86_64_square(&t, &t); }
|
||||||
|
/* 2^40 - 2^0 */ GFp_x25519_x86_64_mul(&t, &t, &z2_20_0);
|
||||||
|
|
||||||
|
/* 2^41 - 2^1 */ GFp_x25519_x86_64_square(&t, &t);
|
||||||
|
/* 2^50 - 2^10 */ for (i = 1; i < 10; i++) { GFp_x25519_x86_64_square(&t, &t); }
|
||||||
|
/* 2^50 - 2^0 */ GFp_x25519_x86_64_mul(&z2_50_0, &t, &z2_10_0);
|
||||||
|
|
||||||
|
/* 2^51 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_50_0);
|
||||||
|
/* 2^100 - 2^50 */ for (i = 1; i < 50; i++) { GFp_x25519_x86_64_square(&t, &t); }
|
||||||
|
/* 2^100 - 2^0 */ GFp_x25519_x86_64_mul(&z2_100_0, &t, &z2_50_0);
|
||||||
|
|
||||||
|
/* 2^101 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_100_0);
|
||||||
|
/* 2^200 - 2^100 */ for (i = 1; i < 100; i++) {
|
||||||
|
GFp_x25519_x86_64_square(&t, &t);
|
||||||
|
}
|
||||||
|
/* 2^200 - 2^0 */ GFp_x25519_x86_64_mul(&t, &t, &z2_100_0);
|
||||||
|
|
||||||
|
/* 2^201 - 2^1 */ GFp_x25519_x86_64_square(&t, &t);
|
||||||
|
/* 2^250 - 2^50 */ for (i = 1; i < 50; i++) { GFp_x25519_x86_64_square(&t, &t); }
|
||||||
|
/* 2^250 - 2^0 */ GFp_x25519_x86_64_mul(&t, &t, &z2_50_0);
|
||||||
|
|
||||||
|
/* 2^251 - 2^1 */ GFp_x25519_x86_64_square(&t, &t);
|
||||||
|
/* 2^252 - 2^2 */ GFp_x25519_x86_64_square(&t, &t);
|
||||||
|
/* 2^253 - 2^3 */ GFp_x25519_x86_64_square(&t, &t);
|
||||||
|
|
||||||
|
/* 2^254 - 2^4 */ GFp_x25519_x86_64_square(&t, &t);
|
||||||
|
|
||||||
|
/* 2^255 - 2^5 */ GFp_x25519_x86_64_square(&t, &t);
|
||||||
|
/* 2^255 - 21 */ GFp_x25519_x86_64_mul(r, &t, &z11);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mladder(fe25519 *xr, fe25519 *zr, const uint8_t s[32]) {
|
||||||
|
fe25519 work[5];
|
||||||
|
|
||||||
|
work[0] = *xr;
|
||||||
|
fe25519_setint(work + 1, 1);
|
||||||
|
fe25519_setint(work + 2, 0);
|
||||||
|
work[3] = *xr;
|
||||||
|
fe25519_setint(work + 4, 1);
|
||||||
|
|
||||||
|
int i, j;
|
||||||
|
uint8_t prevbit = 0;
|
||||||
|
|
||||||
|
j = 6;
|
||||||
|
for (i = 31; i >= 0; i--) {
|
||||||
|
while (j >= 0) {
|
||||||
|
const uint8_t bit = 1 & (s[i] >> j);
|
||||||
|
const uint64_t swap = bit ^ prevbit;
|
||||||
|
prevbit = bit;
|
||||||
|
GFp_x25519_x86_64_work_cswap(work + 1, swap);
|
||||||
|
GFp_x25519_x86_64_ladderstep(work);
|
||||||
|
j -= 1;
|
||||||
|
}
|
||||||
|
j = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
*xr = work[1];
|
||||||
|
*zr = work[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
void GFp_x25519_x86_64(uint8_t out[32], const uint8_t scalar[32],
|
||||||
|
const uint8_t point[32]) {
|
||||||
|
uint8_t e[32];
|
||||||
|
memcpy(e, scalar, sizeof(e));
|
||||||
|
|
||||||
|
e[0] &= 248;
|
||||||
|
e[31] &= 127;
|
||||||
|
e[31] |= 64;
|
||||||
|
|
||||||
|
fe25519 t;
|
||||||
|
fe25519 z;
|
||||||
|
fe25519_unpack(&t, point);
|
||||||
|
mladder(&t, &z, e);
|
||||||
|
fe25519_invert(&z, &z);
|
||||||
|
GFp_x25519_x86_64_mul(&t, &t, &z);
|
||||||
|
fe25519_pack(out, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* BORINGSSL_X25519_X86_64 */
|
||||||
@@ -20,9 +20,13 @@ extra-source-files: CHANGELOG.md
|
|||||||
|
|
||||||
executable gen-tests
|
executable gen-tests
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
other-modules: Database, DSA, ECDSATesting, Math, RFC6979, RSA, Task, Utils
|
other-modules: Database, DSA, ECDSATesting, ED25519, ED25519.PrecompPoints, Math, RFC6979, RSA, Task, Utils
|
||||||
-- other-extensions:
|
-- other-extensions:
|
||||||
build-depends: base >=4.11 && < 4.14, ascii-progress, bytestring, containers, crypto-api, cryptonite, directory, DSA, filepath, integer-gmp, memory, random
|
build-depends: base >=4.11 && < 4.14, ascii-progress, bytestring, containers, crypto-api, cryptonite, directory, DSA, filepath, integer-gmp, memory, random
|
||||||
hs-source-dirs: .
|
hs-source-dirs: .
|
||||||
|
c-sources: cbits/curve25519.c cbits/x25519-x86_64.c cbits/x25519-asm-x86_64.S
|
||||||
|
include-dirs: cbits
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
ghc-options: -Wall -O2 -threaded -rtsopts -with-rtsopts=-N
|
ghc-options: -Wall -O2 -threaded -rtsopts -with-rtsopts=-N
|
||||||
|
if os(Windows) || !arch(x86_64)
|
||||||
|
buildable: False
|
||||||
4004
testdata/ed25519/addsub.test
vendored
Normal file
4004
testdata/ed25519/addsub.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2002
testdata/ed25519/bytes.test
vendored
Normal file
2002
testdata/ed25519/bytes.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3003
testdata/ed25519/cmov.test
vendored
Normal file
3003
testdata/ed25519/cmov.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
6006
testdata/ed25519/conversion.test
vendored
Normal file
6006
testdata/ed25519/conversion.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3003
testdata/ed25519/fbv.test
vendored
Normal file
3003
testdata/ed25519/fbv.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2002
testdata/ed25519/invert.test
vendored
Normal file
2002
testdata/ed25519/invert.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3003
testdata/ed25519/istests.test
vendored
Normal file
3003
testdata/ed25519/istests.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3003
testdata/ed25519/load.test
vendored
Normal file
3003
testdata/ed25519/load.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4004
testdata/ed25519/maddsub.test
vendored
Normal file
4004
testdata/ed25519/maddsub.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3003
testdata/ed25519/mul.test
vendored
Normal file
3003
testdata/ed25519/mul.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4004
testdata/ed25519/muladd.test
vendored
Normal file
4004
testdata/ed25519/muladd.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2002
testdata/ed25519/negate.test
vendored
Normal file
2002
testdata/ed25519/negate.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2002
testdata/ed25519/pow22523.test
vendored
Normal file
2002
testdata/ed25519/pow22523.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4004
testdata/ed25519/pt_double.test
vendored
Normal file
4004
testdata/ed25519/pt_double.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4004
testdata/ed25519/ptaddsub.test
vendored
Normal file
4004
testdata/ed25519/ptaddsub.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2002
testdata/ed25519/pubfrompriv.test
vendored
Normal file
2002
testdata/ed25519/pubfrompriv.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2002
testdata/ed25519/reduce.test
vendored
Normal file
2002
testdata/ed25519/reduce.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
20
testdata/ed25519/rfc8032.test
vendored
Normal file
20
testdata/ed25519/rfc8032.test
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
r: 9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60
|
||||||
|
u: d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a
|
||||||
|
m:
|
||||||
|
s: e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b
|
||||||
|
r: 4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb
|
||||||
|
u: 3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c
|
||||||
|
m: 72
|
||||||
|
s: 92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00
|
||||||
|
r: c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7
|
||||||
|
u: fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025
|
||||||
|
m: af82
|
||||||
|
s: 6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a
|
||||||
|
r: f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5
|
||||||
|
u: 278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e
|
||||||
|
m: 08b8b2b733424243760fe426a4b54908632110a66c2f6591eabd3345e3e4eb98fa6e264bf09efe12ee50f8f54e9f77b1e355f6c50544e23fb1433ddf73be84d879de7c0046dc4996d9e773f4bc9efe5738829adb26c81b37c93a1b270b20329d658675fc6ea534e0810a4432826bf58c941efb65d57a338bbd2e26640f89ffbc1a858efcb8550ee3a5e1998bd177e93a7363c344fe6b199ee5d02e82d522c4feba15452f80288a821a579116ec6dad2b3b310da903401aa62100ab5d1a36553e06203b33890cc9b832f79ef80560ccb9a39ce767967ed628c6ad573cb116dbefefd75499da96bd68a8a97b928a8bbc103b6621fcde2beca1231d206be6cd9ec7aff6f6c94fcd7204ed3455c68c83f4a41da4af2b74ef5c53f1d8ac70bdcb7ed185ce81bd84359d44254d95629e9855a94a7c1958d1f8ada5d0532ed8a5aa3fb2d17ba70eb6248e594e1a2297acbbb39d502f1a8c6eb6f1ce22b3de1a1f40cc24554119a831a9aad6079cad88425de6bde1a9187ebb6092cf67bf2b13fd65f27088d78b7e883c8759d2c4f5c65adb7553878ad575f9fad878e80a0c9ba63bcbcc2732e69485bbc9c90bfbd62481d9089beccf80cfe2df16a2cf65bd92dd597b0707e0917af48bbb75fed413d238f5555a7a569d80c3414a8d0859dc65a46128bab27af87a71314f318c782b23ebfe808b82b0ce26401d2e22f04d83d1255dc51addd3b75a2b1ae0784504df543af8969be3ea7082ff7fc9888c144da2af58429ec96031dbcad3dad9af0dcbaaaf268cb8fcffead94f3c7ca495e056a9b47acdb751fb73e666c6c655ade8297297d07ad1ba5e43f1bca32301651339e22904cc8c42f58c30c04aafdb038dda0847dd988dcda6f3bfd15c4b4c4525004aa06eeff8ca61783aacec57fb3d1f92b0fe2fd1a85f6724517b65e614ad6808d6f6ee34dff7310fdc82aebfd904b01e1dc54b2927094b2db68d6f903b68401adebf5a7e08d78ff4ef5d63653a65040cf9bfd4aca7984a74d37145986780fc0b16ac451649de6188a7dbdf191f64b5fc5e2ab47b57f7f7276cd419c17a3ca8e1b939ae49e488acba6b965610b5480109c8b17b80e1b7b750dfc7598d5d5011fd2dcc5600a32ef5b52a1ecc820e308aa342721aac0943bf6686b64b2579376504ccc493d97e6aed3fb0f9cd71a43dd497f01f17c0e2cb3797aa2a2f256656168e6c496afc5fb93246f6b1116398a346f1a641f3b041e989f7914f90cc2c7fff357876e506b50d334ba77c225bc307ba537152f3f1610e4eafe595f6d9d90d11faa933a15ef1369546868a7f3a45a96768d40fd9d03412c091c6315cf4fde7cb68606937380db2eaaa707b4c4185c32eddcdd306705e4dc1ffc872eeee475a64dfac86aba41c0618983f8741c5ef68d3a101e8a3b8cac60c905c15fc910840b94c00a0b9d0
|
||||||
|
s: 0aab4c900501b3e24d7cdf4663326a3a87df5e4843b2cbdb67cbf6e460fec350aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03
|
||||||
|
r: 833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42
|
||||||
|
u: ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf
|
||||||
|
m: ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f
|
||||||
|
s: dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b58909351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704
|
||||||
2002
testdata/ed25519/scalar_mult.test
vendored
Normal file
2002
testdata/ed25519/scalar_mult.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4004
testdata/ed25519/scalar_mult_gen.test
vendored
Normal file
4004
testdata/ed25519/scalar_mult_gen.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4004
testdata/ed25519/sign.test
vendored
Normal file
4004
testdata/ed25519/sign.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2002
testdata/ed25519/slide.test
vendored
Normal file
2002
testdata/ed25519/slide.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2002
testdata/ed25519/square.test
vendored
Normal file
2002
testdata/ed25519/square.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2002
testdata/ed25519/square2.test
vendored
Normal file
2002
testdata/ed25519/square2.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2880
testdata/sha/hmac.test
vendored
Normal file
2880
testdata/sha/hmac.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user