Compare commits
60 Commits
better_rsa
...
ssh
| Author | SHA1 | Date | |
|---|---|---|---|
| 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
|
||||
*.user_stacks
|
||||
**/.ghc.environment.*
|
||||
tests/rsa/dist*
|
||||
|
||||
test.ed25519
|
||||
@@ -9,13 +9,14 @@ license-file = "LICENSE"
|
||||
repository = "https://github.com/acw/simple_crypto"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "^1.2.7"
|
||||
base64 = "^0.10.1"
|
||||
byteorder = "^1.3.1"
|
||||
chrono = "^0.4.6"
|
||||
cryptonum = { path = "cryptonum" }
|
||||
digest = "^0.8.0"
|
||||
hmac = "^0.7.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"
|
||||
|
||||
@@ -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)
|
||||
- Make Point::double_scalar_mult() not truly awful
|
||||
- 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?
|
||||
- Test cases for key generation
|
||||
- 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,44 @@
|
||||
//! 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
|
||||
//! extern crate sha2;
|
||||
//!
|
||||
//! use simple_crypto::dsa::{DSAKeyPair,DSAParameters,L2048N256};
|
||||
//! use sha2::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 params;
|
||||
mod private;
|
||||
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;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@@ -13,27 +50,41 @@ pub use self::public::*;
|
||||
use cryptonum::unsigned::*;
|
||||
use rand::Rng;
|
||||
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 public: DSAPubKey<P,L>
|
||||
pub private: DSAPrivateKey<P>,
|
||||
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 {
|
||||
($ptype: ident, $ltype: ident, $ntype: ident, $nbig: ident) => {
|
||||
impl DSAKeyGeneration for DSAKeyPair<$ptype,$ltype,$ntype>
|
||||
impl DSAKeyPair<$ptype>
|
||||
{
|
||||
type Params = $ptype;
|
||||
|
||||
fn generate<G: Rng>(params: &$ptype, rng: &mut G) -> Self
|
||||
/// Generate a DSA key pair using the given parameters and random
|
||||
/// number generator. Please make sure that the RNG you're using
|
||||
/// 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);
|
||||
let n = $ptype::n_size();
|
||||
@@ -45,7 +96,7 @@ macro_rules! generate_dsa_pair {
|
||||
// strength of requested_security_strength or more. If an ERROR
|
||||
// indication is returned, then return an ERROR indication,
|
||||
// Invalid_x, and Invalid_y.
|
||||
let returned_bits: Vec<u8> = rng.sample_iter(&Standard).take(n + 8).collect();
|
||||
let returned_bits: Vec<u8> = rng.sample_iter(&Standard).take( (n + 64) / 8 ).collect();
|
||||
// 5. Convert returned_bits to the (non-negative) integer c.
|
||||
let c = $nbig::from_bytes(&returned_bits);
|
||||
// 6. x = (c mod (q-1)) + 1.
|
||||
@@ -55,8 +106,8 @@ macro_rules! generate_dsa_pair {
|
||||
// 7. y = g^x mod p
|
||||
let y = params.g.modexp(&$ltype::from(&x), ¶ms.p);
|
||||
// 8. Return SUCCESS, x, and y.
|
||||
let private = DSAPrivKey::new(params.clone(), x);
|
||||
let public = DSAPubKey::new(params.clone(), y);
|
||||
let private = DSAPrivateKey::<$ptype>::new(params.clone(), x);
|
||||
let public = DSAPublicKey::<$ptype>::new(params.clone(), y);
|
||||
DSAKeyPair { private, public }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,30 @@ use simple_asn1::{ToASN1,ASN1Block,ASN1Class,ASN1EncodeErr};
|
||||
use rand::Rng;
|
||||
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
|
||||
{
|
||||
/// The fixed-width, unsigned type of values in L.
|
||||
type L;
|
||||
/// The fixed-width, unsigned type of values in 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;
|
||||
/// 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;
|
||||
/// Return the size of values of N in bits.
|
||||
fn n_size() -> usize;
|
||||
/// Return the size of values of L in bits.
|
||||
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 {
|
||||
Self::n_size()
|
||||
}
|
||||
@@ -23,7 +37,8 @@ pub trait DSAParameters : ToASN1
|
||||
|
||||
macro_rules! generate_parameters {
|
||||
($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 p: $ltype,
|
||||
pub g: $ltype,
|
||||
@@ -71,7 +86,7 @@ macro_rules! generate_parameters {
|
||||
|
||||
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
|
||||
// (since that's guaranteed to be >= N), and with the hash
|
||||
@@ -105,10 +120,9 @@ macro_rules! generate_parameters {
|
||||
#[allow(non_snake_case)]
|
||||
let U = $ntype::from_bytes(&ubytes);
|
||||
// 7. q = 2^(N–1) + U + 1 – (U mod 2).
|
||||
let ulow = if U.is_even() { 0 } else { 1 };
|
||||
let mut q = $ntype::from(1u64) << (N - 1);
|
||||
q += U;
|
||||
q += $ntype::from(1u64 + ulow);
|
||||
let highbit = $ntype::from(1u64) << (N - 1);
|
||||
let lowbit = $ntype::from(1u64);
|
||||
let q = U | highbit | lowbit;
|
||||
// 8. Test whether or not q is prime as specified in Appendix C.3.
|
||||
let q_is_prime = q.probably_prime(rng, 40);
|
||||
// 9. If q is not a prime, then go to step 5.
|
||||
@@ -126,7 +140,7 @@ macro_rules! generate_parameters {
|
||||
for j in 0..n {
|
||||
let val = &domain_parameter_seed + U256::from(offset + j);
|
||||
let bytes = hash(&val, 32);
|
||||
assert_eq!(seedlen, bytes.len());
|
||||
assert_eq!(seedlen, bytes.len() * 8);
|
||||
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).
|
||||
|
||||
@@ -5,49 +5,33 @@ use dsa::params::*;
|
||||
use dsa::rfc6979::*;
|
||||
use hmac::{Hmac,Mac};
|
||||
|
||||
pub trait DSAPrivateKey {
|
||||
type Params;
|
||||
type L;
|
||||
type N;
|
||||
|
||||
/// Generate a new private key using the given DSA parameters and private
|
||||
/// key value.
|
||||
fn new(params: Self::Params, x: Self::N) -> Self;
|
||||
/// Generate a DSA signature for the given message, using the appropriate
|
||||
/// hash included in the type invocation.
|
||||
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<Self::N>
|
||||
where
|
||||
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
||||
Hmac<Hash>: Mac;
|
||||
}
|
||||
|
||||
pub struct DSAPrivKey<Params,N>
|
||||
/// A DSA private key, parameterized by its DSA parameters (so that you don't
|
||||
/// accidentally pass the wrong key to the wrong routine).
|
||||
pub struct DSAPrivateKey<Params: DSAParameters>
|
||||
{
|
||||
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 {
|
||||
DSA1024Private(DSAPrivKey<L1024N160,U192>),
|
||||
DSA2048SmallPrivate(DSAPrivKey<L2048N224,U256>),
|
||||
DSA2048Private(DSAPrivKey<L2048N256,U256>),
|
||||
DSA3072Private(DSAPrivKey<L3072N256,U256>)
|
||||
DSA1024Private(DSAPrivateKey<L1024N160>),
|
||||
DSA2048SmallPrivate(DSAPrivateKey<L2048N224>),
|
||||
DSA2048Private(DSAPrivateKey<L2048N256>),
|
||||
DSA3072Private(DSAPrivateKey<L3072N256>)
|
||||
}
|
||||
|
||||
macro_rules! privkey_impls {
|
||||
($ptype: ident, $ltype: ident, $ntype: ident, $big: ident, $bigger: ident, $biggest: ident) => {
|
||||
impl DSAPrivateKey for DSAPrivKey<$ptype,$ntype>
|
||||
impl DSAPrivateKey<$ptype>
|
||||
{
|
||||
type Params = $ptype;
|
||||
type L = $ltype;
|
||||
type N = $ntype;
|
||||
|
||||
fn new(params: $ptype, x: $ntype) -> DSAPrivKey<$ptype,$ntype>
|
||||
pub fn new(params: $ptype, x: $ntype) -> DSAPrivateKey<$ptype>
|
||||
{
|
||||
DSAPrivKey{ params, x }
|
||||
DSAPrivateKey{ params, x }
|
||||
}
|
||||
|
||||
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<$ntype>
|
||||
pub fn sign<Hash>(&self, m: &[u8]) -> DSASignature<$ntype>
|
||||
where
|
||||
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
||||
Hmac<Hash>: Mac
|
||||
@@ -155,7 +139,7 @@ macro_rules! generate_tests {
|
||||
let s = $nt::from_bytes(sbytes);
|
||||
|
||||
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 {
|
||||
224 => private.sign::<Sha224>(mbytes),
|
||||
256 => private.sign::<Sha256>(mbytes),
|
||||
|
||||
@@ -7,45 +7,32 @@ use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,ToASN1};
|
||||
use std::cmp::min;
|
||||
use utils::TranslateNums;
|
||||
|
||||
pub trait DSAPublicKey {
|
||||
type Params : DSAParameters;
|
||||
type L;
|
||||
type N;
|
||||
|
||||
/// Generate a new public key given the parameters and public value.
|
||||
fn new(params: Self::Params, y: Self::L) -> Self;
|
||||
/// Verify the given signature against the given message, using the
|
||||
/// appropriate hash function.
|
||||
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<Self::N>) -> bool
|
||||
where Hash: Digest;
|
||||
}
|
||||
|
||||
pub struct DSAPubKey<Params,L> {
|
||||
/// A DSA public key, parameterized by its DSA parameters (so that you don't
|
||||
/// accidentally pass the wrong thing to the wrong function).
|
||||
pub struct DSAPublicKey<Params: DSAParameters> {
|
||||
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 {
|
||||
DSAPublicL1024N160(DSAPubKey<L1024N160,U1024>),
|
||||
DSAPublicL2048N224(DSAPubKey<L2048N224,U2048>),
|
||||
DSAPublicL2048N256(DSAPubKey<L2048N256,U2048>),
|
||||
DSAPublicL3072N256(DSAPubKey<L3072N256,U3072>)
|
||||
DSAPublicL1024N160(DSAPublicKey<L1024N160>),
|
||||
DSAPublicL2048N224(DSAPublicKey<L2048N224>),
|
||||
DSAPublicL2048N256(DSAPublicKey<L2048N256>),
|
||||
DSAPublicL3072N256(DSAPublicKey<L3072N256>)
|
||||
}
|
||||
|
||||
macro_rules! pubkey_impls {
|
||||
($ptype: ident, $ltype: ident, $ntype: ident, $dbl: ident, $bdbl: ident) => {
|
||||
impl DSAPublicKey for DSAPubKey<$ptype,$ltype>
|
||||
impl DSAPublicKey<$ptype>
|
||||
{
|
||||
type Params = $ptype;
|
||||
type L = $ltype;
|
||||
type N = $ntype;
|
||||
|
||||
fn new(params: $ptype, y: $ltype) -> DSAPubKey<$ptype,$ltype>
|
||||
pub fn new(params: $ptype, y: $ltype) -> DSAPublicKey<$ptype>
|
||||
{
|
||||
DSAPubKey{ params, y }
|
||||
DSAPublicKey{ params, y }
|
||||
}
|
||||
|
||||
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<$ntype>) -> bool
|
||||
pub fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<$ntype>) -> bool
|
||||
where Hash: Digest
|
||||
{
|
||||
if sig.r >= self.params.q {
|
||||
@@ -80,7 +67,7 @@ macro_rules! pubkey_impls {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToASN1 for DSAPubKey<$ptype,$ltype> {
|
||||
impl ToASN1 for DSAPublicKey<$ptype> {
|
||||
type Error = ASN1EncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
@@ -136,7 +123,7 @@ macro_rules! generate_tests {
|
||||
let s = $nt::from_bytes(sbytes);
|
||||
|
||||
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);
|
||||
match h {
|
||||
224 => assert!(public.verify::<Sha224>(mbytes, &sig)),
|
||||
|
||||
@@ -4,8 +4,8 @@ use sha1::Sha1;
|
||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||
use simple_asn1::{der_decode,der_encode};
|
||||
use dsa::params::{DSAParameters,L1024N160,L2048N256};
|
||||
use dsa::private::{DSAPrivateKey,DSAPrivKey};
|
||||
use dsa::public::{DSAPublicKey,DSAPubKey};
|
||||
use dsa::private::DSAPrivateKey;
|
||||
use dsa::public::DSAPublicKey;
|
||||
use dsa::rfc6979::KIterator;
|
||||
|
||||
macro_rules! run_rfc6979_test {
|
||||
@@ -99,8 +99,8 @@ fn appendix_a21() {
|
||||
let params = L1024N160::new(p, g, q);
|
||||
let x = U192::from_bytes(&xbytes);
|
||||
let y = U1024::from_bytes(&ybytes);
|
||||
let private = DSAPrivKey::new(params.clone(), x);
|
||||
let public = DSAPubKey::<L1024N160,U1024>::new(params.clone(), y);
|
||||
let private = DSAPrivateKey::<L1024N160>::new(params.clone(), x);
|
||||
let public = DSAPublicKey::<L1024N160>::new(params.clone(), y);
|
||||
//
|
||||
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
|
||||
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
|
||||
@@ -359,8 +359,8 @@ fn appendix_a22() {
|
||||
let params = L2048N256::new(p, g, q);
|
||||
let x = U256::from_bytes(&xbytes);
|
||||
let y = U2048::from_bytes(&ybytes);
|
||||
let private = DSAPrivKey::<L2048N256,U256>::new(params.clone(), x);
|
||||
let public = DSAPubKey::<L2048N256,U2048>::new(params.clone(), y);
|
||||
let private = DSAPrivateKey::<L2048N256>::new(params.clone(), x);
|
||||
let public = DSAPublicKey::<L2048N256>::new(params.clone(), y);
|
||||
//
|
||||
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
|
||||
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
|
||||
|
||||
@@ -1,28 +1,54 @@
|
||||
use cryptonum::signed::{I192,I256,I384,I576};
|
||||
use cryptonum::unsigned::{Decoder};
|
||||
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)]
|
||||
pub trait EllipticCurve {
|
||||
/// The unsigned numeric type that fits constants for this curve.
|
||||
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;
|
||||
/// The `p` value for the curve.
|
||||
fn p() -> Self::Unsigned;
|
||||
/// The `p` value for the curve.
|
||||
fn n() -> Self::Unsigned;
|
||||
/// The seed value for the curve.
|
||||
fn SEED() -> Self::Unsigned;
|
||||
/// The `c` value for the curve.
|
||||
fn c() -> Self::Unsigned;
|
||||
/// The `a` value for the curve.
|
||||
fn a() -> Self::Unsigned;
|
||||
/// The `b` value for the curve.
|
||||
fn b() -> Self::Unsigned;
|
||||
/// The `x` coordinate of the base point for the curve.
|
||||
fn Gx() -> Self::Signed;
|
||||
/// The `y` coordinate of the base point for the curve.
|
||||
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 {
|
||||
type Unsigned = U192;
|
||||
type Signed = I192;
|
||||
type Point = Point<P192>;
|
||||
|
||||
fn size() -> usize {
|
||||
192
|
||||
@@ -59,13 +85,20 @@ impl EllipticCurve for P192 {
|
||||
fn Gy() -> I192 {
|
||||
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 {
|
||||
type Unsigned = U256;
|
||||
type Signed = I256;
|
||||
type Point = Point<P224>;
|
||||
|
||||
fn size() -> usize {
|
||||
224
|
||||
@@ -141,13 +174,20 @@ impl EllipticCurve for P224 {
|
||||
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 {
|
||||
type Signed = I256;
|
||||
type Unsigned = U256;
|
||||
type Point = Point<P256>;
|
||||
|
||||
fn size() -> usize {
|
||||
256
|
||||
@@ -224,13 +264,20 @@ impl EllipticCurve for P256 {
|
||||
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 {
|
||||
type Signed = I384;
|
||||
type Unsigned = U384;
|
||||
type Point = Point<P384>;
|
||||
|
||||
fn size() -> usize {
|
||||
384
|
||||
@@ -320,13 +367,20 @@ impl EllipticCurve for P384 {
|
||||
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 {
|
||||
type Signed = I576;
|
||||
type Unsigned = U576;
|
||||
type Point = Point<P521>;
|
||||
|
||||
fn size() -> usize {
|
||||
521
|
||||
@@ -437,4 +491,8 @@ impl EllipticCurve for P521 {
|
||||
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,95 @@
|
||||
pub mod curve;
|
||||
pub mod point;
|
||||
pub mod private;
|
||||
pub mod public;
|
||||
//! The generation and use of ECDSA keys is pretty straightforward, compared
|
||||
//! to DSA and RSA. You should be able to find what you want to do in the
|
||||
//! following code snippet, as an example:
|
||||
//!
|
||||
//! ```rust
|
||||
//! extern crate sha2;
|
||||
//!
|
||||
//! use simple_crypto::ecdsa::{ECDSAKeyPair,P384};
|
||||
//! use sha2::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::unsigned::{CryptoNum,Decoder};
|
||||
use cryptonum::unsigned::{U192,U256,U384,U576};
|
||||
use rand::Rng;
|
||||
use rand::distributions::Standard;
|
||||
use self::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
||||
pub use self::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
||||
use self::point::{ECCPoint,Point};
|
||||
pub use self::private::{ECCPrivateKey,ECCPrivate};
|
||||
pub use self::public::{ECCPublicKey,ECDSAPublic,ECCPubKey};
|
||||
pub use self::private::{ECDSAPrivate,ECCPrivateKey};
|
||||
pub use self::public::{ECDSAPublic,ECCPublicKey};
|
||||
pub use self::public::{ECDSADecodeErr,ECDSAEncodeErr};
|
||||
use super::KeyPair;
|
||||
|
||||
pub trait ECDSAKeyPair<Public,Private> {
|
||||
fn generate<G: Rng>(g: &mut G) -> (Public, Private);
|
||||
/// An ECDSA key pair for the given curve.
|
||||
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 {
|
||||
($curve: ident, $un: ident, $si: ident) => {
|
||||
impl ECDSAKeyPair<ECCPubKey<$curve>,ECCPrivate<$curve>> for $curve {
|
||||
fn generate<G: Rng>(rng: &mut G) -> (ECCPubKey<$curve>, ECCPrivate<$curve>)
|
||||
impl KeyPair for ECDSAKeyPair<$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 {
|
||||
let size = ($curve::size() + 7) / 8;
|
||||
@@ -38,9 +106,10 @@ macro_rules! generate_impl {
|
||||
|
||||
let d = $si::from(&proposed_d);
|
||||
let public_point = Point::<$curve>::default().scale(&d);
|
||||
let public = ECCPubKey::<$curve>::new(public_point);
|
||||
let private = ECCPrivate::<$curve>::new(proposed_d);
|
||||
return (public, private);
|
||||
let public = ECCPublicKey::<$curve>::new(public_point);
|
||||
let private = ECCPrivateKey::<$curve>::new(proposed_d);
|
||||
|
||||
return ECDSAKeyPair{ public, private };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ pub trait ECCPoint : Sized {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub struct Point<T: EllipticCurve>
|
||||
{
|
||||
pub x: T::Signed,
|
||||
|
||||
@@ -5,34 +5,44 @@ use dsa::rfc6979::{DSASignature,KIterator,bits2int};
|
||||
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
||||
use ecdsa::point::{ECCPoint,Point};
|
||||
use hmac::{Hmac,Mac};
|
||||
use std::fmt;
|
||||
|
||||
pub struct ECCPrivate<Curve: EllipticCurve> {
|
||||
d: Curve::Unsigned
|
||||
/// A private key for the given curve.
|
||||
#[derive(PartialEq)]
|
||||
pub struct ECCPrivateKey<Curve: EllipticCurve> {
|
||||
pub(crate) d: Curve::Unsigned
|
||||
}
|
||||
|
||||
pub trait ECCPrivateKey {
|
||||
type Unsigned;
|
||||
impl<Curve: EllipticCurve> fmt::Debug for ECCPrivateKey<Curve> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error>
|
||||
{
|
||||
f.write_str("<ECCPrivateKey>")
|
||||
}
|
||||
}
|
||||
|
||||
fn new(d: Self::Unsigned) -> Self;
|
||||
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<Self::Unsigned>
|
||||
where
|
||||
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
||||
Hmac<Hash>: Mac;
|
||||
/// A generic private key.
|
||||
pub enum ECDSAPrivate {
|
||||
P192(ECCPrivateKey<P192>),
|
||||
P224(ECCPrivateKey<P224>),
|
||||
P256(ECCPrivateKey<P256>),
|
||||
P384(ECCPrivateKey<P384>),
|
||||
P521(ECCPrivateKey<P521>),
|
||||
}
|
||||
|
||||
macro_rules! generate_privates
|
||||
{
|
||||
($curve: ident, $base: ident, $sig: ident, $dbl: ident, $quad: ident) => {
|
||||
impl ECCPrivateKey for ECCPrivate<$curve>
|
||||
impl ECCPrivateKey<$curve>
|
||||
{
|
||||
type Unsigned = $base;
|
||||
|
||||
fn new(d: $base) -> ECCPrivate<$curve>
|
||||
/// Generate a new private key using the given private scalar.
|
||||
pub fn new(d: $base) -> ECCPrivateKey<$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
|
||||
/// in the type.
|
||||
pub fn sign<Hash>(&self, m: &[u8]) -> DSASignature<$base>
|
||||
where
|
||||
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
||||
Hmac<Hash>: Mac
|
||||
@@ -136,7 +146,7 @@ macro_rules! sign_test_body
|
||||
let r = $base::from_bytes(rbytes);
|
||||
let s = $base::from_bytes(sbytes);
|
||||
|
||||
let private = ECCPrivate::<$curve>::new(d);
|
||||
let private = ECCPrivateKey::<$curve>::new(d);
|
||||
let sig = match usize::from(h) {
|
||||
224 => private.sign::<Sha224>(mbytes),
|
||||
256 => private.sign::<Sha256>(mbytes),
|
||||
|
||||
@@ -8,29 +8,24 @@ use hmac::{Hmac,Mac};
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,FromASN1,ToASN1};
|
||||
use std::cmp::min;
|
||||
|
||||
pub struct ECCPubKey<Curve: EllipticCurve> {
|
||||
q: Point<Curve>
|
||||
/// An ECDSA public key for the given 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 {
|
||||
ECCPublicP192(ECCPubKey<P192>),
|
||||
ECCPublicP224(ECCPubKey<P224>),
|
||||
ECCPublicP256(ECCPubKey<P256>),
|
||||
ECCPublicP384(ECCPubKey<P384>),
|
||||
ECCPublicP521(ECCPubKey<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;
|
||||
P192(ECCPublicKey<P192>),
|
||||
P224(ECCPublicKey<P224>),
|
||||
P256(ECCPublicKey<P256>),
|
||||
P384(ECCPublicKey<P384>),
|
||||
P521(ECCPublicKey<P521>),
|
||||
}
|
||||
|
||||
/// An error that can occur when encoding an ECDSA public key as an ASN.1
|
||||
/// object.
|
||||
pub enum ECDSAEncodeErr {
|
||||
ASN1EncodeErr(ASN1EncodeErr),
|
||||
XValueNegative, YValueNegative
|
||||
@@ -42,6 +37,8 @@ impl From<ASN1EncodeErr> for ECDSAEncodeErr {
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that can occur when decoding an ECDSA public key from an
|
||||
/// ASN.1 blob.
|
||||
#[derive(Debug)]
|
||||
pub enum ECDSADecodeErr {
|
||||
ASN1DecodeErr(ASN1DecodeErr),
|
||||
@@ -58,17 +55,17 @@ impl From<ASN1DecodeErr> for ECDSADecodeErr {
|
||||
|
||||
macro_rules! public_impl {
|
||||
($curve: ident, $un: ident, $si: ident) => {
|
||||
impl ECCPublicKey for ECCPubKey<$curve>
|
||||
impl ECCPublicKey<$curve>
|
||||
{
|
||||
type Curve = $curve;
|
||||
type Unsigned = $un;
|
||||
|
||||
fn new(q: Point<$curve>) -> ECCPubKey<$curve>
|
||||
/// Generate a new public key object from the given public point.
|
||||
pub fn new(q: Point<$curve>) -> ECCPublicKey<$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,
|
||||
/// assuming the provided hash function.
|
||||
pub fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<$un>) -> bool
|
||||
where
|
||||
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
|
||||
Hmac<Hash>: Mac
|
||||
@@ -103,7 +100,7 @@ macro_rules! public_impl {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToASN1 for ECCPubKey<$curve> {
|
||||
impl ToASN1 for ECCPublicKey<$curve> {
|
||||
type Error = ECDSAEncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class) -> Result<Vec<ASN1Block>,ECDSAEncodeErr>
|
||||
@@ -136,10 +133,10 @@ macro_rules! public_impl {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromASN1 for ECCPubKey<$curve> {
|
||||
impl FromASN1 for ECCPublicKey<$curve> {
|
||||
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)?;
|
||||
if let ASN1Block::BitString(_, _, _, target) = x {
|
||||
@@ -155,7 +152,7 @@ macro_rules! public_impl {
|
||||
let x = $un::from_bytes(xbstr);
|
||||
let y = $un::from_bytes(ybstr);
|
||||
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
|
||||
let res = ECCPubKey::<$curve>::new(point);
|
||||
let res = ECCPublicKey::<$curve>::new(point);
|
||||
Ok((res, rest))
|
||||
} else {
|
||||
Err(ECDSADecodeErr::InvalidKeyFormat)
|
||||
@@ -201,7 +198,7 @@ macro_rules! verify_test_body
|
||||
let s = $un::from_bytes(sbytes);
|
||||
|
||||
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
|
||||
let public = ECCPubKey::<$curve>::new(point);
|
||||
let public = ECCPublicKey::<$curve>::new(point);
|
||||
let sig = DSASignature::new(r, s);
|
||||
match usize::from(h) {
|
||||
224 => assert!(public.verify::<Sha224>(mbytes, &sig)),
|
||||
|
||||
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");
|
||||
});
|
||||
}
|
||||
|
||||
268
src/ed25519/mod.rs
Normal file
268
src/ed25519/mod.rs
Normal file
@@ -0,0 +1,268 @@
|
||||
//! 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 digest::Digest;
|
||||
use rand::Rng;
|
||||
use sha2::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::digest(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.input(&self.prefix);
|
||||
ctx.input(&msg);
|
||||
let nonce = digest_scalar(ctx.result().as_slice());
|
||||
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.input(signature_r);
|
||||
ctx.input(public_key);
|
||||
ctx.input(msg);
|
||||
ctx.result().as_slice().to_vec()
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
20
src/lib.rs
20
src/lib.rs
@@ -9,6 +9,7 @@
|
||||
//! that a new user should use, along with documentation regarding how and
|
||||
//! when they should use it, and examples. For now, it mostly just fowards
|
||||
//! off to more detailed modules. Help requested!
|
||||
extern crate base64;
|
||||
extern crate byteorder;
|
||||
extern crate chrono;
|
||||
extern crate cryptonum;
|
||||
@@ -35,10 +36,29 @@ pub mod dsa;
|
||||
/// The `ecdsa` module provides bare-bones support for ECDSA signing,
|
||||
/// verification, and key generation.
|
||||
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 `x509` module supports parsing and generating x.509 certificates, as
|
||||
/// used by TLS and others.
|
||||
pub mod x509;
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod testing;
|
||||
mod utils;
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
use cryptonum::unsigned::*;
|
||||
use num::bigint::BigUint;
|
||||
use rsa::errors::RSAError;
|
||||
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>
|
||||
{
|
||||
let mut idhash = Vec::new();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use simple_asn1::ASN1DecodeErr;
|
||||
use rand;
|
||||
|
||||
/// A bunch of errors that you can get generating, reading, or
|
||||
/// writing RSA keys.
|
||||
#[derive(Debug)]
|
||||
pub enum RSAError {
|
||||
BadMessageSize,
|
||||
|
||||
236
src/rsa/mod.rs
236
src/rsa/mod.rs
@@ -17,6 +17,39 @@
|
||||
//! Encryption and decryption are via the OAEP mechanism, as described in
|
||||
//! 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;
|
||||
//! extern crate sha2;
|
||||
//!
|
||||
//! use simple_crypto::rsa::RSAKeyPair;
|
||||
//! use simple_crypto::rsa::SIGNING_HASH_SHA256;
|
||||
//! use simple_crypto::rsa::OAEPParams;
|
||||
//! use sha2::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 errors;
|
||||
mod oaep;
|
||||
@@ -24,6 +57,7 @@ mod private;
|
||||
mod public;
|
||||
mod signing_hashes;
|
||||
|
||||
pub use self::core::RSAMode;
|
||||
pub use self::errors::RSAError;
|
||||
pub use self::signing_hashes::{SigningHash,
|
||||
SIGNING_HASH_NULL,
|
||||
@@ -33,20 +67,16 @@ pub use self::signing_hashes::{SigningHash,
|
||||
SIGNING_HASH_SHA384,
|
||||
SIGNING_HASH_SHA512};
|
||||
pub use self::oaep::OAEPParams;
|
||||
pub use self::private::{RSAPrivate, RSAPrivateKey,
|
||||
RSA512Private, RSA1024Private, RSA2048Private,
|
||||
RSA3072Private, RSA4096Private, RSA8192Private,
|
||||
RSA15360Private};
|
||||
pub use self::public::{RSAPublic, RSAPublicKey,
|
||||
RSA512Public, RSA1024Public, RSA2048Public,
|
||||
RSA3072Public, RSA4096Public, RSA8192Public,
|
||||
RSA15360Public};
|
||||
|
||||
pub use self::private::{RSAPrivate, RSAPrivateKey};
|
||||
pub use self::public::{RSAPublic, RSAPublicKey};
|
||||
use cryptonum::signed::{EGCD,ModInv};
|
||||
use cryptonum::unsigned::{CryptoNum,PrimeGen};
|
||||
use cryptonum::unsigned::{U256,U512,U1024,U1536,U2048,U3072,U4096,U7680,U8192,U15360};
|
||||
use rand::RngCore;
|
||||
#[cfg(test)]
|
||||
use std::fmt;
|
||||
use std::ops::Sub;
|
||||
use super::KeyPair;
|
||||
|
||||
fn diff<T>(a: &T, b: &T) -> T
|
||||
where
|
||||
@@ -60,38 +90,164 @@ fn diff<T>(a: &T, b: &T) -> T
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_rsa_pair
|
||||
{
|
||||
($pair: ident, $pub: ident, $priv: ident, $uint: ident, $half: ident, $iterations: expr) => {
|
||||
pub struct $pair {
|
||||
pub public: $pub,
|
||||
pub private: $priv
|
||||
/// An RSA key pair containing keys of the given size; keeping them in the
|
||||
/// type means you'll never forget which one you have.
|
||||
///
|
||||
/// As an aside:
|
||||
/// * `U512` should only be used for testing
|
||||
/// * `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 {
|
||||
pub fn new(pu: $pub, pr: $priv) -> $pair {
|
||||
$pair {
|
||||
/// A generic RSA key pair that is agnostic about its key size. It's not
|
||||
/// totally clear why this is useful, at this point.
|
||||
#[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,
|
||||
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
|
||||
{
|
||||
loop {
|
||||
let ebase = 65537u32;
|
||||
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 pminus1 = &p - &one;
|
||||
let qminus1 = &q - &one;
|
||||
let phi = pminus1 * qminus1;
|
||||
let n = &p * &q;
|
||||
if let Some(d) = e.modinv(&phi) {
|
||||
let public = $pub::new(n.clone(), e);
|
||||
let private = $priv::new(n, d);
|
||||
return $pair::new(public, private);
|
||||
let public = RSAPublicKey::<$uint>::new(n.clone(), e);
|
||||
let private = RSAPrivateKey::<$uint>::new(n, d);
|
||||
return RSAKeyPair::<$uint>::new(public, private);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,13 +285,13 @@ macro_rules! generate_rsa_pair
|
||||
}
|
||||
}
|
||||
|
||||
generate_rsa_pair!(RSA512KeyPair, RSA512Public, RSA512Private, U512, U256, 7);
|
||||
generate_rsa_pair!(RSA1024KeyPair, RSA1024Public, RSA1024Private, U1024, U512, 7);
|
||||
generate_rsa_pair!(RSA2048KeyPair, RSA2048Public, RSA2048Private, U2048, U1024, 4);
|
||||
generate_rsa_pair!(RSA3072KeyPair, RSA3072Public, RSA3072Private, U3072, U1536, 3);
|
||||
generate_rsa_pair!(RSA4096KeyPair, RSA4096Public, RSA4096Private, U4096, U2048, 3);
|
||||
generate_rsa_pair!(RSA8192KeyPair, RSA8192Public, RSA8192Private, U8192, U4096, 3);
|
||||
generate_rsa_pair!(RSA15360KeyPair, RSA15360Public, RSA15360Private, U15360, U7680, 3);
|
||||
generate_rsa_pair!(U512, U256, 7);
|
||||
generate_rsa_pair!(U1024, U512, 7);
|
||||
generate_rsa_pair!(U2048, U1024, 4);
|
||||
generate_rsa_pair!(U3072, U1536, 3);
|
||||
generate_rsa_pair!(U4096, U2048, 3);
|
||||
generate_rsa_pair!(U8192, U4096, 3);
|
||||
generate_rsa_pair!(U15360, U7680, 3);
|
||||
|
||||
#[cfg(test)]
|
||||
mod generation {
|
||||
@@ -143,15 +299,15 @@ mod generation {
|
||||
use std::fmt;
|
||||
use super::*;
|
||||
|
||||
impl Clone for RSA512KeyPair {
|
||||
fn clone(&self) -> RSA512KeyPair {
|
||||
RSA512KeyPair{
|
||||
public: RSA512Public {
|
||||
impl Clone for RSAKeyPair<U512> {
|
||||
fn clone(&self) -> RSAKeyPair<U512> {
|
||||
RSAKeyPair {
|
||||
public: RSAPublicKey {
|
||||
n: self.public.n.clone(),
|
||||
nu: self.public.nu.clone(),
|
||||
e: self.public.e.clone(),
|
||||
},
|
||||
private: RSA512Private {
|
||||
private: RSAPrivateKey {
|
||||
nu: self.private.nu.clone(),
|
||||
d: self.private.d.clone()
|
||||
}
|
||||
@@ -159,7 +315,7 @@ mod generation {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for RSA512KeyPair {
|
||||
impl fmt::Debug for RSAKeyPair<U512> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("RSA512KeyPair")
|
||||
.field("n", &self.public.n)
|
||||
@@ -169,14 +325,14 @@ mod generation {
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for RSA512KeyPair {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> RSA512KeyPair {
|
||||
RSA512KeyPair::generate(g)
|
||||
impl Arbitrary for RSAKeyPair<U512> {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> RSAKeyPair<U512> {
|
||||
RSAKeyPair::<U512>::generate(g)
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
keypair.public.verify(&SIGNING_HASH_SHA256, &msg, &sig)
|
||||
}
|
||||
|
||||
@@ -1,56 +1,49 @@
|
||||
use cryptonum::unsigned::*;
|
||||
use digest::{Digest,FixedOutput};
|
||||
use rsa::core::{drop0s,pkcs1_pad,xor_vecs};
|
||||
use rsa::core::{RSAMode,drop0s,pkcs1_pad,xor_vecs};
|
||||
use rsa::errors::RSAError;
|
||||
use rsa::oaep::OAEPParams;
|
||||
use rsa::signing_hashes::SigningHash;
|
||||
|
||||
pub trait RSAPrivateKey<N> {
|
||||
/// Generate a new private key using the given modulus and private
|
||||
/// exponent. You probably don't want to use this function directly
|
||||
/// unless you're writing your own key generation routine or key
|
||||
/// parsing library.
|
||||
fn new(n: N, d: N) -> Self;
|
||||
|
||||
/// Sign the given message with the given private key.
|
||||
fn sign(&self, signhash: &SigningHash, msg: &[u8]) -> Vec<u8>;
|
||||
|
||||
/// Decrypt the provided message using the given OAEP parameters. As
|
||||
/// mentioned in the comment for encryption, RSA decryption is really,
|
||||
/// really slow. So if your plaintext is larger than about half the
|
||||
/// bit size of the key, it's almost certainly a better idea to generate
|
||||
/// a fresh symmetric encryption key, encrypt only the key with RSA, and
|
||||
/// then encrypt the message with that key.
|
||||
fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
where H: Default + Digest + FixedOutput;
|
||||
/// An RSA private key. Useful for signing messages and decrypting encrypted
|
||||
/// content.
|
||||
#[derive(Clone,PartialEq)]
|
||||
pub struct RSAPrivateKey<R: RSAMode>
|
||||
{
|
||||
pub(crate) nu: R::Barrett,
|
||||
pub(crate) d: R
|
||||
}
|
||||
|
||||
/// A generic RSA private key which is agnostic to its key size.
|
||||
#[derive(Clone,PartialEq)]
|
||||
pub enum RSAPrivate {
|
||||
Key512(RSA512Private),
|
||||
Key1024(RSA1024Private),
|
||||
Key2048(RSA2048Private),
|
||||
Key3072(RSA3072Private),
|
||||
Key4096(RSA4096Private),
|
||||
Key8192(RSA8192Private),
|
||||
Key15360(RSA15360Private)
|
||||
Key512(RSAPrivateKey<U512>),
|
||||
Key1024(RSAPrivateKey<U1024>),
|
||||
Key2048(RSAPrivateKey<U2048>),
|
||||
Key3072(RSAPrivateKey<U3072>),
|
||||
Key4096(RSAPrivateKey<U4096>),
|
||||
Key8192(RSAPrivateKey<U8192>),
|
||||
Key15360(RSAPrivateKey<U15360>)
|
||||
}
|
||||
|
||||
macro_rules! generate_rsa_private
|
||||
{
|
||||
($rsa: ident, $num: ident, $bar: ident, $size: expr) => {
|
||||
pub struct $rsa {
|
||||
pub(crate) nu: $bar,
|
||||
pub(crate) d: $num
|
||||
}
|
||||
|
||||
impl RSAPrivateKey<$num> for $rsa {
|
||||
fn new(n: $num, d: $num) -> $rsa {
|
||||
($num: ident, $bar: ident, $size: expr) => {
|
||||
impl RSAPrivateKey<$num> {
|
||||
/// Generate a new private key with the given modulus and private
|
||||
/// 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
|
||||
/// instantiation. But you do you.
|
||||
pub fn new(n: $num, d: $num) -> RSAPrivateKey<$num> {
|
||||
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>
|
||||
{
|
||||
let hash = (signhash.run)(msg);
|
||||
@@ -61,7 +54,14 @@ macro_rules! generate_rsa_private
|
||||
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>(&self, oaep: &OAEPParams<H>, msg: &[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
where H: Default + Digest + FixedOutput
|
||||
{
|
||||
@@ -74,9 +74,7 @@ macro_rules! generate_rsa_private
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl $rsa {
|
||||
fn sp1(&self, m: &$num) -> $num {
|
||||
m.modexp(&self.d, &self.nu)
|
||||
}
|
||||
@@ -139,17 +137,17 @@ macro_rules! generate_rsa_private
|
||||
}
|
||||
}
|
||||
|
||||
generate_rsa_private!(RSA512Private, U512, BarrettU512, 512);
|
||||
generate_rsa_private!(RSA1024Private, U1024, BarrettU1024, 1024);
|
||||
generate_rsa_private!(RSA2048Private, U2048, BarrettU2048, 2048);
|
||||
generate_rsa_private!(RSA3072Private, U3072, BarrettU3072, 3072);
|
||||
generate_rsa_private!(RSA4096Private, U4096, BarrettU4096, 4096);
|
||||
generate_rsa_private!(RSA8192Private, U8192, BarrettU8192, 8192);
|
||||
generate_rsa_private!(RSA15360Private, U15360, BarrettU15360, 15360);
|
||||
generate_rsa_private!(U512, BarrettU512, 512);
|
||||
generate_rsa_private!(U1024, BarrettU1024, 1024);
|
||||
generate_rsa_private!(U2048, BarrettU2048, 2048);
|
||||
generate_rsa_private!(U3072, BarrettU3072, 3072);
|
||||
generate_rsa_private!(U4096, BarrettU4096, 4096);
|
||||
generate_rsa_private!(U8192, BarrettU8192, 8192);
|
||||
generate_rsa_private!(U15360, BarrettU15360, 15360);
|
||||
|
||||
#[cfg(test)]
|
||||
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);
|
||||
run_test(fname.to_string(), 7, |case| {
|
||||
let (neg0, dbytes) = case.get("d").unwrap();
|
||||
@@ -173,7 +171,7 @@ macro_rules! sign_test_body {
|
||||
512 => &SIGNING_HASH_SHA512,
|
||||
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);
|
||||
assert_eq!(*sbytes, sig);
|
||||
});
|
||||
@@ -182,7 +180,7 @@ macro_rules! sign_test_body {
|
||||
|
||||
#[cfg(test)]
|
||||
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);
|
||||
run_test(fname.to_string(), 9, |case| {
|
||||
let (neg0, nbytes) = case.get("n").unwrap();
|
||||
@@ -203,7 +201,7 @@ macro_rules! decrypt_test_body {
|
||||
let k = usize::from(bigk);
|
||||
let d = $num::from_bytes(dbytes);
|
||||
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 message = match usize::from($num::from_bytes(hbytes)) {
|
||||
224 => privkey.decrypt(&OAEPParams::<Sha224>::new(lstr), &cbytes),
|
||||
@@ -219,7 +217,7 @@ macro_rules! decrypt_test_body {
|
||||
}
|
||||
|
||||
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)]
|
||||
#[allow(non_snake_case)]
|
||||
mod $mod {
|
||||
@@ -231,16 +229,16 @@ macro_rules! generate_tests {
|
||||
|
||||
#[test]
|
||||
fn sign() {
|
||||
sign_test_body!($mod, $rsa, $num, $bar, $num64, $size);
|
||||
sign_test_body!($mod, $num, $bar, $num64, $size);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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)]
|
||||
#[allow(non_snake_case)]
|
||||
mod $mod {
|
||||
@@ -253,22 +251,22 @@ macro_rules! generate_tests {
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn sign() {
|
||||
sign_test_body!($mod, $rsa, $num, $bar, $num64, $size);
|
||||
sign_test_body!($mod, $num, $bar, $num64, $size);
|
||||
}
|
||||
|
||||
#[ignore]
|
||||
#[test]
|
||||
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!(RSA1024, RSA1024Private, U1024, BarrettU1024, U1088, 1024);
|
||||
generate_tests!(RSA2048, RSA2048Private, U2048, BarrettU2048, U2112, 2048);
|
||||
generate_tests!(RSA3072, RSA3072Private, U3072, BarrettU3072, U3136, 3072);
|
||||
generate_tests!(RSA4096, RSA4096Private, U4096, BarrettU4096, U4160, 4096);
|
||||
generate_tests!(ignore RSA8192, RSA8192Private, U8192, BarrettU8192, U8256, 8192);
|
||||
generate_tests!(ignore RSA15360, RSA15360Private, U15360, BarrettU15360, U15424, 15360);
|
||||
generate_tests!( RSA512, U512, BarrettU512, U576, 512);
|
||||
generate_tests!( RSA1024, U1024, BarrettU1024, U1088, 1024);
|
||||
generate_tests!( RSA2048, U2048, BarrettU2048, U2112, 2048);
|
||||
generate_tests!( RSA3072, U3072, BarrettU3072, U3136, 3072);
|
||||
generate_tests!( RSA4096, U4096, BarrettU4096, U4160, 4096);
|
||||
generate_tests!(ignore RSA8192, U8192, BarrettU8192, U8256, 8192);
|
||||
generate_tests!(ignore RSA15360, U15360, BarrettU15360, U15424, 15360);
|
||||
@@ -2,7 +2,7 @@ use cryptonum::unsigned::*;
|
||||
use digest::{Digest,FixedOutput};
|
||||
use rand::Rng;
|
||||
use rand::rngs::OsRng;
|
||||
use rsa::core::{decode_biguint,pkcs1_pad,xor_vecs};
|
||||
use rsa::core::{RSAMode,decode_biguint,pkcs1_pad,xor_vecs};
|
||||
use rsa::errors::RSAError;
|
||||
use rsa::oaep::OAEPParams;
|
||||
use rsa::signing_hashes::SigningHash;
|
||||
@@ -12,65 +12,31 @@ use simple_asn1::{ASN1Block,ASN1DecodeErr,ASN1EncodeErr,
|
||||
use std::fmt;
|
||||
use utils::TranslateNums;
|
||||
|
||||
pub trait RSAPublicKey<N> {
|
||||
/// Generate a new public key pair for the given modulus and
|
||||
/// exponent. You should probably not call this directly unless
|
||||
/// you're writing a key generation function or writing your own
|
||||
/// public key parser.
|
||||
fn new(n: N, e: N) -> Self;
|
||||
|
||||
/// Verify that the provided signature is valid; that the private
|
||||
/// key associated with this public key sent exactly this message.
|
||||
/// The hash used here must exactly match the hash used to sign
|
||||
/// the message, including its ASN.1 metadata.
|
||||
fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool;
|
||||
|
||||
/// Encrypt the message with a hash function, given the appropriate
|
||||
/// label. Please note that RSA encryption is not particularly fast,
|
||||
/// and decryption is very slow indeed. Thus, most crypto systems that
|
||||
/// need asymmetric encryption should generate a symmetric key, encrypt
|
||||
/// that key with RSA encryption, and then encrypt the actual message
|
||||
/// with that symmetric key.
|
||||
///
|
||||
/// In this variant of the function, we use an explicit random number
|
||||
/// generator, just in case you have one you really like. It better be
|
||||
/// cryptographically strong, though, as some of the padding protections
|
||||
/// are relying on it.
|
||||
fn encrypt_rng<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
where
|
||||
G: Rng,
|
||||
H: Default + Digest + FixedOutput;
|
||||
|
||||
/// Encrypt the message with a hash function, given the appropriate
|
||||
/// label. Please note that RSA encryption is not particularly fast,
|
||||
/// and decryption is very slow indeed. Thus, most crypto systems that
|
||||
/// need asymmetric encryption should generate a symmetric key, encrypt
|
||||
/// that key with RSA encryption, and then encrypt the actual message
|
||||
/// with that symmetric key.
|
||||
///
|
||||
/// This variant will just use the system RNG for its randomness.
|
||||
fn encrypt<H>(&self,oaep:&OAEPParams<H>,msg:&[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
where
|
||||
H: Default + Digest + FixedOutput
|
||||
{
|
||||
let mut g = OsRng::new()?;
|
||||
self.encrypt_rng(&mut g, oaep, msg)
|
||||
}
|
||||
/// An RSA public key. Useful for verifying signatures or encrypting data to
|
||||
/// send to the private key holder.
|
||||
#[derive(Clone,PartialEq)]
|
||||
pub struct RSAPublicKey<R: RSAMode> {
|
||||
pub(crate) n: R,
|
||||
pub(crate) nu: R::Barrett,
|
||||
pub(crate) e: R
|
||||
}
|
||||
|
||||
/// A generic private key that is agnostic to the key size.
|
||||
#[derive(Clone,PartialEq)]
|
||||
pub enum RSAPublic {
|
||||
Key512(RSA512Public),
|
||||
Key1024(RSA1024Public),
|
||||
Key2048(RSA2048Public),
|
||||
Key3072(RSA3072Public),
|
||||
Key4096(RSA4096Public),
|
||||
Key8192(RSA8192Public),
|
||||
Key15360(RSA15360Public)
|
||||
Key512( RSAPublicKey<U512>),
|
||||
Key1024( RSAPublicKey<U1024>),
|
||||
Key2048( RSAPublicKey<U2048>),
|
||||
Key3072( RSAPublicKey<U3072>),
|
||||
Key4096( RSAPublicKey<U4096>),
|
||||
Key8192( RSAPublicKey<U8192>),
|
||||
Key15360(RSAPublicKey<U15360>)
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
match self {
|
||||
@@ -109,43 +75,43 @@ impl FromASN1 for RSAPublic {
|
||||
512 => {
|
||||
let n2 = U512::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||
let e2 = U512::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||
let res = RSA512Public::new(n2, e2);
|
||||
let res = RSAPublicKey::<U512>::new(n2, e2);
|
||||
Ok((RSAPublic::Key512(res), rest))
|
||||
}
|
||||
1024 => {
|
||||
let n2 = U1024::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||
let e2 = U1024::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||
let res = RSA1024Public::new(n2, e2);
|
||||
let res = RSAPublicKey::<U1024>::new(n2, e2);
|
||||
Ok((RSAPublic::Key1024(res), rest))
|
||||
}
|
||||
2048 => {
|
||||
let n2 = U2048::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||
let e2 = U2048::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||
let res = RSA2048Public::new(n2, e2);
|
||||
let res = RSAPublicKey::<U2048>::new(n2, e2);
|
||||
Ok((RSAPublic::Key2048(res), rest))
|
||||
}
|
||||
3072 => {
|
||||
let n2 = U3072::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||
let e2 = U3072::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||
let res = RSA3072Public::new(n2, e2);
|
||||
let res = RSAPublicKey::<U3072>::new(n2, e2);
|
||||
Ok((RSAPublic::Key3072(res), rest))
|
||||
}
|
||||
4096 => {
|
||||
let n2 = U4096::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||
let e2 = U4096::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||
let res = RSA4096Public::new(n2, e2);
|
||||
let res = RSAPublicKey::<U4096>::new(n2, e2);
|
||||
Ok((RSAPublic::Key4096(res), rest))
|
||||
}
|
||||
8192 => {
|
||||
let n2 = U8192::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||
let e2 = U8192::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||
let res = RSA8192Public::new(n2, e2);
|
||||
let res = RSAPublicKey::<U8192>::new(n2, e2);
|
||||
Ok((RSAPublic::Key8192(res), rest))
|
||||
}
|
||||
15360 => {
|
||||
let n2 = U15360::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||
let e2 = U15360::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||
let res = RSA15360Public::new(n2, e2);
|
||||
let res = RSAPublicKey::<U15360>::new(n2, e2);
|
||||
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
|
||||
{
|
||||
($rsa: ident, $num: ident, $bar: ident, $var: ident, $size: expr) => {
|
||||
#[derive(PartialEq)]
|
||||
pub struct $rsa {
|
||||
pub(crate) n: $num,
|
||||
pub(crate) nu: $bar,
|
||||
pub(crate) e: $num
|
||||
}
|
||||
|
||||
impl RSAPublicKey<$num> for $rsa {
|
||||
fn new(n: $num, e: $num) -> $rsa {
|
||||
($num: ident, $bar: ident, $var: ident, $size: expr) => {
|
||||
impl RSAPublicKey<$num> {
|
||||
/// Generate a new public key pair for the given modulus and
|
||||
/// exponent. You should probably not call this directly unless
|
||||
/// you're writing a key generation function or writing your own
|
||||
/// public key parser.
|
||||
pub fn new(n: $num, e: $num) -> RSAPublicKey<$num> {
|
||||
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
|
||||
{
|
||||
let hash: Vec<u8> = (signhash.run)(msg);
|
||||
@@ -203,7 +185,18 @@ macro_rules! generate_rsa_public
|
||||
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>
|
||||
where
|
||||
G: Rng,
|
||||
@@ -222,9 +215,24 @@ macro_rules! generate_rsa_public
|
||||
|
||||
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>(&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)
|
||||
}
|
||||
|
||||
impl $rsa {
|
||||
fn vp1(&self, s: &$num) -> $num {
|
||||
s.modexp(&self.e, &self.nu)
|
||||
}
|
||||
@@ -283,11 +291,11 @@ macro_rules! generate_rsa_public
|
||||
}
|
||||
}
|
||||
|
||||
impl FromASN1 for $rsa {
|
||||
impl FromASN1 for RSAPublicKey<$num> {
|
||||
type Error = RSAError;
|
||||
|
||||
fn from_asn1(bs: &[ASN1Block])
|
||||
-> Result<($rsa,&[ASN1Block]),RSAError>
|
||||
-> Result<(RSAPublicKey<$num>,&[ASN1Block]),RSAError>
|
||||
{
|
||||
let (core, rest) = RSAPublic::from_asn1(bs)?;
|
||||
|
||||
@@ -298,7 +306,7 @@ macro_rules! generate_rsa_public
|
||||
}
|
||||
}
|
||||
|
||||
impl ToASN1 for $rsa {
|
||||
impl ToASN1 for RSAPublicKey<$num> {
|
||||
type Error = ASN1EncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
@@ -314,7 +322,7 @@ macro_rules! generate_rsa_public
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl fmt::Debug for $rsa {
|
||||
impl fmt::Debug for RSAPublicKey<$num> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct(stringify!($rsa))
|
||||
.field("n", &self.n)
|
||||
@@ -326,17 +334,17 @@ macro_rules! generate_rsa_public
|
||||
}
|
||||
}
|
||||
|
||||
generate_rsa_public!(RSA512Public, U512, BarrettU512, Key512, 512);
|
||||
generate_rsa_public!(RSA1024Public, U1024, BarrettU1024, Key1024, 1024);
|
||||
generate_rsa_public!(RSA2048Public, U2048, BarrettU2048, Key2048, 2048);
|
||||
generate_rsa_public!(RSA3072Public, U3072, BarrettU3072, Key3072, 3072);
|
||||
generate_rsa_public!(RSA4096Public, U4096, BarrettU4096, Key4096, 4096);
|
||||
generate_rsa_public!(RSA8192Public, U8192, BarrettU8192, Key8192, 8192);
|
||||
generate_rsa_public!(RSA15360Public, U15360, BarrettU15360, Key15360, 15360);
|
||||
generate_rsa_public!(U512, BarrettU512, Key512, 512);
|
||||
generate_rsa_public!(U1024, BarrettU1024, Key1024, 1024);
|
||||
generate_rsa_public!(U2048, BarrettU2048, Key2048, 2048);
|
||||
generate_rsa_public!(U3072, BarrettU3072, Key3072, 3072);
|
||||
generate_rsa_public!(U4096, BarrettU4096, Key4096, 4096);
|
||||
generate_rsa_public!(U8192, BarrettU8192, Key8192, 8192);
|
||||
generate_rsa_public!(U15360, BarrettU15360, Key15360, 15360);
|
||||
|
||||
#[cfg(test)]
|
||||
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);
|
||||
run_test(fname.to_string(), 7, |case| {
|
||||
let (neg0, nbytes) = case.get("n").unwrap();
|
||||
@@ -350,8 +358,8 @@ macro_rules! new_test_body {
|
||||
let bigk = $num::from_bytes(kbytes);
|
||||
let k = usize::from(bigk);
|
||||
let e = $num::from(65537u64);
|
||||
let pubkey2 = $rsa::new(n.clone(), e.clone());
|
||||
let pubkey1 = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
||||
let pubkey2 = RSAPublicKey::<$num>::new(n.clone(), e.clone());
|
||||
let pubkey1 = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
||||
assert_eq!(pubkey1, pubkey2);
|
||||
});
|
||||
};
|
||||
@@ -359,7 +367,7 @@ macro_rules! new_test_body {
|
||||
|
||||
#[cfg(test)]
|
||||
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);
|
||||
run_test(fname.to_string(), 7, |case| {
|
||||
let (neg0, nbytes) = case.get("n").unwrap();
|
||||
@@ -373,9 +381,9 @@ macro_rules! encode_test_body {
|
||||
let bigk = $num::from_bytes(kbytes);
|
||||
let k = usize::from(bigk);
|
||||
let e = $num::from(65537u64);
|
||||
let pubkey = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
||||
let pubkey = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
||||
let asn1 = pubkey.to_asn1().unwrap();
|
||||
let (pubkey2, _) = $rsa::from_asn1(&asn1).unwrap();
|
||||
let (pubkey2, _) = RSAPublicKey::from_asn1(&asn1).unwrap();
|
||||
assert_eq!(pubkey, pubkey2);
|
||||
});
|
||||
};
|
||||
@@ -383,7 +391,7 @@ macro_rules! encode_test_body {
|
||||
|
||||
#[cfg(test)]
|
||||
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);
|
||||
run_test(fname.to_string(), 7, |case| {
|
||||
let (neg0, nbytes) = case.get("n").unwrap();
|
||||
@@ -400,7 +408,7 @@ macro_rules! verify_test_body {
|
||||
let bigk = $num::from_bytes(kbytes);
|
||||
let k = usize::from(bigk);
|
||||
let e = $num::from(65537u64);
|
||||
let pubkey = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
||||
let pubkey = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
||||
let hashnum = u64::from($num::from_bytes(hbytes));
|
||||
let sighash = match hashnum {
|
||||
160 => &SIGNING_HASH_SHA1,
|
||||
@@ -417,7 +425,7 @@ macro_rules! verify_test_body {
|
||||
|
||||
#[cfg(test)]
|
||||
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);
|
||||
run_test(fname.to_string(), 9, |case| {
|
||||
let (neg0, nbytes) = case.get("n").unwrap();
|
||||
@@ -438,8 +446,8 @@ macro_rules! encrypt_test_body {
|
||||
let e = $num::from(65537u64);
|
||||
let d = $num::from_bytes(dbytes);
|
||||
let nu = $bar::from_components(k, n64, nu);
|
||||
let pubkey = $rsa{ n: n.clone(), nu: nu.clone(), e: e };
|
||||
let privkey = $priv{ nu: nu, d: d };
|
||||
let pubkey = RSAPublicKey{ n: n.clone(), nu: nu.clone(), e: e };
|
||||
let privkey = RSAPrivateKey{ nu: nu, d: d };
|
||||
let lstr = String::from_utf8(lbytes.clone()).unwrap();
|
||||
let cipher = match usize::from($num::from_bytes(hbytes)) {
|
||||
224 => pubkey.encrypt(&OAEPParams::<Sha224>::new(lstr.clone()), mbytes),
|
||||
@@ -463,7 +471,7 @@ macro_rules! encrypt_test_body {
|
||||
}
|
||||
|
||||
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)]
|
||||
#[allow(non_snake_case)]
|
||||
mod $mod {
|
||||
@@ -475,16 +483,16 @@ macro_rules! generate_tests {
|
||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||
|
||||
#[test]
|
||||
fn new() { new_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
|
||||
fn new() { new_test_body!($mod, $num, $bar, $num64, $size); }
|
||||
#[test]
|
||||
fn encode() { encode_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
|
||||
fn encode() { encode_test_body!($mod, $num, $bar, $num64, $size); }
|
||||
#[test]
|
||||
fn verify() { verify_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
|
||||
fn verify() { verify_test_body!($mod, $num, $bar, $num64, $size); }
|
||||
#[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)]
|
||||
#[allow(non_snake_case)]
|
||||
mod $mod {
|
||||
@@ -497,24 +505,24 @@ macro_rules! generate_tests {
|
||||
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn new() { new_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
|
||||
fn new() { new_test_body!($mod, $num, $bar, $num64, $size); }
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn encode() { encode_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
|
||||
fn encode() { encode_test_body!($mod, $num, $bar, $num64, $size); }
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn verify() { verify_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
|
||||
fn verify() { verify_test_body!($mod, $num, $bar, $num64, $size); }
|
||||
#[ignore]
|
||||
#[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!(RSA1024, RSA1024Public, RSA1024Private, U1024, BarrettU1024, U1088, 1024);
|
||||
generate_tests!(RSA2048, RSA2048Public, RSA2048Private, U2048, BarrettU2048, U2112, 2048);
|
||||
generate_tests!(RSA3072, RSA3072Public, RSA3072Private, U3072, BarrettU3072, U3136, 3072);
|
||||
generate_tests!(RSA4096, RSA4096Public, RSA4096Private, U4096, BarrettU4096, U4160, 4096);
|
||||
generate_tests!(ignore RSA8192, RSA8192Public, RSA8192Private, U8192, BarrettU8192, U8256, 8192);
|
||||
generate_tests!(ignore RSA15360, RSA15360Public, RSA15360Private, U15360, BarrettU15360, U15424, 15360);
|
||||
generate_tests!( RSA512, U512, BarrettU512, U576, 512);
|
||||
generate_tests!( RSA1024, U1024, BarrettU1024, U1088, 1024);
|
||||
generate_tests!( RSA2048, U2048, BarrettU2048, U2112, 2048);
|
||||
generate_tests!( RSA3072, U3072, BarrettU3072, U3136, 3072);
|
||||
generate_tests!( RSA4096, U4096, BarrettU4096, U4160, 4096);
|
||||
generate_tests!(ignore RSA8192, U8192, BarrettU8192, U8256, 8192);
|
||||
generate_tests!(ignore RSA15360, U15360, BarrettU15360, U15424, 15360);
|
||||
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)
|
||||
}
|
||||
}
|
||||
308
src/ssh/frame.rs
Normal file
308
src/ssh/frame.rs
Normal file
@@ -0,0 +1,308 @@
|
||||
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-----\n";
|
||||
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 != '\n').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);
|
||||
while bytestr.len() > 70 {
|
||||
let rest = bytestr.split_off(70);
|
||||
output.push_str(&bytestr);
|
||||
output.push_str("\n");
|
||||
bytestr = rest;
|
||||
}
|
||||
output.push_str(&bytestr);
|
||||
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() {
|
||||
is_ok &= 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);
|
||||
// starts_with() avoids newline unpleasantness
|
||||
assert!(contents.starts_with(&rendered));
|
||||
}
|
||||
}
|
||||
|
||||
#[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 sha2::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() {
|
||||
match nibble_iter.next() {
|
||||
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) => {
|
||||
let b1 = c1.to_digit(16).unwrap() as u8;
|
||||
let b2 = c2.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).expect(&format!("Unexpected character: |{}|", c2)) as u8;
|
||||
val.push( (b2 << 4) | b1 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,28 @@ use num::BigUint;
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
|
||||
use x509::error::X509ParseError;
|
||||
|
||||
/// A supported x509 hash algorithm
|
||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||
pub enum HashAlgorithm { SHA1, SHA224, SHA256, SHA384, SHA512 }
|
||||
|
||||
/// A supported x509 asymmetric crypto algorithm
|
||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||
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)]
|
||||
pub struct AlgorithmIdentifier {
|
||||
pub hash: HashAlgorithm,
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
||||
use std::ops::Index;
|
||||
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)]
|
||||
pub struct InfoBlock {
|
||||
fields: Vec<AttributeTypeValue>
|
||||
pub fields: Vec<AttributeTypeValue>
|
||||
}
|
||||
|
||||
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)]
|
||||
struct AttributeTypeValue {
|
||||
attrtype: X520Name,
|
||||
value: String
|
||||
pub struct AttributeTypeValue {
|
||||
pub attrtype: X520Name,
|
||||
pub value: String
|
||||
}
|
||||
|
||||
fn decode_attribute_type_value(x: &ASN1Block)
|
||||
|
||||
@@ -3,6 +3,7 @@ use num::bigint::ToBigInt;
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
||||
use x509::error::X509ParseError;
|
||||
|
||||
/// Which version of x.509 certificate this is.
|
||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||
pub enum X509Version { V1, V2, V3 }
|
||||
|
||||
@@ -65,6 +66,7 @@ impl ToASN1 for X509Version {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/// The serial number for this certificate.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct X509Serial {
|
||||
num: BigUint
|
||||
|
||||
@@ -6,19 +6,20 @@ mod name;
|
||||
mod publickey;
|
||||
mod validity;
|
||||
|
||||
use dsa::{DSAPublic,DSAPublicKey};
|
||||
use ecdsa::{ECDSAPublic,ECCPublicKey};
|
||||
use dsa::DSAPublic;
|
||||
use ecdsa::ECDSAPublic;
|
||||
use rsa::{SIGNING_HASH_SHA1,SIGNING_HASH_SHA224,SIGNING_HASH_SHA256,SIGNING_HASH_SHA384,SIGNING_HASH_SHA512};
|
||||
use sha1::Sha1;
|
||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||
use simple_asn1::{ASN1Block,FromASN1,der_decode,from_der};
|
||||
use x509::validity::Validity;
|
||||
use x509::algident::{AlgorithmIdentifier,HashAlgorithm,PublicKeyInfo,
|
||||
decode_algorithm_ident};
|
||||
use x509::atv::InfoBlock;
|
||||
pub use x509::validity::Validity;
|
||||
pub use x509::algident::{AlgorithmIdentifier,HashAlgorithm,PublicKeyInfo};
|
||||
use x509::algident::{decode_algorithm_ident};
|
||||
pub use x509::atv::InfoBlock;
|
||||
use x509::error::X509ParseError;
|
||||
use x509::misc::{X509Serial,X509Version,decode_signature};
|
||||
use x509::publickey::X509PublicKey;
|
||||
pub use x509::misc::{X509Serial,X509Version};
|
||||
use x509::misc::{decode_signature};
|
||||
pub use x509::publickey::X509PublicKey;
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
@@ -88,6 +89,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> {
|
||||
let blocks = from_der(&buffer[..])?;
|
||||
match blocks.first() {
|
||||
@@ -182,7 +185,7 @@ fn check_signature(alg: &AlgorithmIdentifier,
|
||||
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)?;
|
||||
match alg.hash {
|
||||
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
||||
@@ -194,7 +197,7 @@ fn check_signature(alg: &AlgorithmIdentifier,
|
||||
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)?;
|
||||
match alg.hash {
|
||||
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
||||
@@ -206,7 +209,7 @@ fn check_signature(alg: &AlgorithmIdentifier,
|
||||
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)?;
|
||||
match alg.hash {
|
||||
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
||||
@@ -218,7 +221,7 @@ fn check_signature(alg: &AlgorithmIdentifier,
|
||||
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)?;
|
||||
match alg.hash {
|
||||
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
||||
@@ -230,7 +233,7 @@ fn check_signature(alg: &AlgorithmIdentifier,
|
||||
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)?;
|
||||
match alg.hash {
|
||||
HashAlgorithm::SHA1 if key.verify::<Sha1>(block, &ecdsa_sig) => Ok(()),
|
||||
|
||||
@@ -2,6 +2,8 @@ use num::BigUint;
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
|
||||
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)]
|
||||
pub enum X520Name {
|
||||
Name, Surname, GivenName, Initials, GenerationQualifier, CommonName,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
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 ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPubKey};
|
||||
use ecdsa::curve::{P192,P224,P256,P384,P521};
|
||||
use ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPublicKey};
|
||||
use ecdsa::{P192,P224,P256,P384,P521};
|
||||
use num::BigUint;
|
||||
use rsa::RSAPublic;
|
||||
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 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 {
|
||||
DSA(DSAPublic),
|
||||
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)?;
|
||||
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||
let y = U3072::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||
let key = DSAPubKey::<L3072N256,U3072>::new(params, y);
|
||||
let key = DSAPublicKey::<L3072N256>::new(params, y);
|
||||
let reskey = DSAPublic::DSAPublicL3072N256(key);
|
||||
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)?;
|
||||
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||
let y = U2048::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||
let key = DSAPubKey::<L2048N256,U2048>::new(params, y);
|
||||
let key = DSAPublicKey::<L2048N256>::new(params, y);
|
||||
let reskey = DSAPublic::DSAPublicL2048N256(key);
|
||||
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)?;
|
||||
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||
let y = U2048::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||
let key = DSAPubKey::<L2048N224,U2048>::new(params, y);
|
||||
let key = DSAPublicKey::<L2048N224>::new(params, y);
|
||||
let reskey = DSAPublic::DSAPublicL2048N224(key);
|
||||
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)?;
|
||||
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||
let y = U1024::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||
let key = DSAPubKey::<L1024N160,U1024>::new(params, y);
|
||||
let key = DSAPublicKey::<L1024N160>::new(params, y);
|
||||
let reskey = DSAPublic::DSAPublicL1024N160(key);
|
||||
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 (base_curve_oid, mut keyvec) = match x {
|
||||
ECDSAPublic::ECCPublicP192(k) => (oid!(1,2,840,10045,3,1,1), k.to_asn1_class(c)?),
|
||||
ECDSAPublic::ECCPublicP224(k) => (oid!(1,3,132,0,33), k.to_asn1_class(c)?),
|
||||
ECDSAPublic::ECCPublicP256(k) => (oid!(1,2,840,10045,3,1,7), k.to_asn1_class(c)?),
|
||||
ECDSAPublic::ECCPublicP384(k) => (oid!(1,3,132,0,34), k.to_asn1_class(c)?),
|
||||
ECDSAPublic::ECCPublicP521(k) => (oid!(1,3,132,0,35), k.to_asn1_class(c)?),
|
||||
ECDSAPublic::P192(k) => (oid!(1,2,840,10045,3,1,1), k.to_asn1_class(c)?),
|
||||
ECDSAPublic::P224(k) => (oid!(1,3,132,0,33), k.to_asn1_class(c)?),
|
||||
ECDSAPublic::P256(k) => (oid!(1,2,840,10045,3,1,7), k.to_asn1_class(c)?),
|
||||
ECDSAPublic::P384(k) => (oid!(1,3,132,0,34), 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 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 oid == oid!(1,2,840,10045,3,1,1) {
|
||||
let (res, _) = ECCPubKey::<P192>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::ECCPublicP192(res));
|
||||
let (res, _) = ECCPublicKey::<P192>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::P192(res));
|
||||
}
|
||||
|
||||
if oid == oid!(1,3,132,0,33) {
|
||||
let (res, _) = ECCPubKey::<P224>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::ECCPublicP224(res));
|
||||
let (res, _) = ECCPublicKey::<P224>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::P224(res));
|
||||
}
|
||||
|
||||
if oid == oid!(1,2,840,10045,3,1,7) {
|
||||
let (res, _) = ECCPubKey::<P256>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::ECCPublicP256(res));
|
||||
let (res, _) = ECCPublicKey::<P256>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::P256(res));
|
||||
}
|
||||
|
||||
if oid == oid!(1,3,132,0,34) {
|
||||
let (res, _) = ECCPubKey::<P384>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::ECCPublicP384(res));
|
||||
let (res, _) = ECCPublicKey::<P384>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::P384(res));
|
||||
}
|
||||
|
||||
if oid == oid!(1,3,132,0,35) {
|
||||
let (res, _) = ECCPubKey::<P521>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::ECCPublicP521(res));
|
||||
let (res, _) = ECCPublicKey::<P521>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::P521(res));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,11 @@ use chrono::{DateTime,Utc};
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
||||
use x509::error::X509ParseError;
|
||||
|
||||
/// The range of dates in which this certificate is valid.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct Validity {
|
||||
not_before: DateTime<Utc>,
|
||||
not_after: DateTime<Utc>
|
||||
pub not_before: DateTime<Utc>,
|
||||
pub not_after: DateTime<Utc>
|
||||
}
|
||||
|
||||
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.Map.Strict as Map
|
||||
import Math(showX,showBin)
|
||||
import Task(Task(..),Test)
|
||||
import Task(Task(..),liftTest)
|
||||
import Utils(HashAlg(..),generateHash,showHash)
|
||||
|
||||
import Debug.Trace
|
||||
|
||||
dsaSizes :: [(ParameterSizes, Int)]
|
||||
dsaSizes = [(L1024_N160, 400),
|
||||
(L2048_N224, 100),
|
||||
@@ -38,27 +36,26 @@ signTest :: ParameterSizes -> Int -> Task
|
||||
signTest sz cnt = Task {
|
||||
taskName = "DSA " ++ show sz ++ " signing",
|
||||
taskFile = "../testdata/dsa/sign" ++ showParam sz ++ ".test",
|
||||
taskTest = go,
|
||||
taskTest = liftTest go,
|
||||
taskCount = cnt
|
||||
}
|
||||
where
|
||||
go :: Test
|
||||
go (memory, drg0) =
|
||||
case generateProbablePrimes sz drg0 sha256 Nothing of
|
||||
Left _ -> trace "generate primes" $ goAdvance memory drg0
|
||||
Left _ -> goAdvance memory drg0
|
||||
Right (p, q, _, drg1) ->
|
||||
case generateUnverifiableGenerator p q of
|
||||
Nothing -> trace "generate g" $ goAdvance memory drg1
|
||||
Nothing -> goAdvance memory drg1
|
||||
Just g ->
|
||||
let params = Params p g q
|
||||
in case generateKeyPairWithParams params drg1 of
|
||||
Left _ -> trace "generate key" $ goAdvance memory drg1
|
||||
Left _ -> goAdvance memory drg1
|
||||
Right (pub, priv, drg2) ->
|
||||
let (msg, drg3) = withDRG drg2 $ getRandomBytes =<< ((fromIntegral . BS.head) `fmap` getRandomBytes 1)
|
||||
(hashf, drg4) = withDRG drg3 generateHash
|
||||
in case signMessage' (translateHash hashf) kViaRFC6979 drg4 priv (BSL.fromStrict msg) of
|
||||
Left _ ->
|
||||
trace "sign failure" $ go (memory, drg4)
|
||||
go (memory, drg4)
|
||||
Right (sig, drg5) ->
|
||||
let res = Map.fromList [("p", showX p),
|
||||
("q", showX q),
|
||||
|
||||
@@ -15,7 +15,7 @@ import qualified Data.ByteString as S
|
||||
import qualified Data.Map.Strict as Map
|
||||
import Math(showX,showBin)
|
||||
import RFC6979(generateKStream)
|
||||
import Task(Task(..))
|
||||
import Task(Task(..),liftTest)
|
||||
import Utils(HashAlg(..),generateHash,runHash,showHash)
|
||||
|
||||
curves :: [(String, Curve)]
|
||||
@@ -29,7 +29,7 @@ negateTest :: String -> Curve -> Task
|
||||
negateTest name curve = Task {
|
||||
taskName = name ++ " point negation",
|
||||
taskFile = "../testdata/ecc/negate/" ++ name ++ ".test",
|
||||
taskTest = go,
|
||||
taskTest = liftTest go,
|
||||
taskCount = 1000
|
||||
}
|
||||
where
|
||||
@@ -49,7 +49,7 @@ doubleTest :: String -> Curve -> Task
|
||||
doubleTest name curve = Task {
|
||||
taskName = name ++ " point doubling",
|
||||
taskFile = "../testdata/ecc/double/" ++ name ++ ".test",
|
||||
taskTest = go,
|
||||
taskTest = liftTest go,
|
||||
taskCount = 1000
|
||||
}
|
||||
where
|
||||
@@ -69,7 +69,7 @@ addTest :: String -> Curve -> Task
|
||||
addTest name curve = Task {
|
||||
taskName = name ++ " point addition",
|
||||
taskFile = "../testdata/ecc/add/" ++ name ++ ".test",
|
||||
taskTest = go,
|
||||
taskTest = liftTest go,
|
||||
taskCount = 1000
|
||||
}
|
||||
where
|
||||
@@ -92,7 +92,7 @@ scaleTest :: String -> Curve -> Task
|
||||
scaleTest name curve = Task {
|
||||
taskName = name ++ " point scaling",
|
||||
taskFile = "../testdata/ecc/scale/" ++ name ++ ".test",
|
||||
taskTest = go,
|
||||
taskTest = liftTest go,
|
||||
taskCount = 1000
|
||||
}
|
||||
where
|
||||
@@ -117,7 +117,7 @@ addScaleTest :: String -> Curve -> Task
|
||||
addScaleTest name curve = Task {
|
||||
taskName = name ++ " point addition of two scalings",
|
||||
taskFile = "../testdata/ecc/add_scale2/" ++ name ++ ".test",
|
||||
taskTest = go,
|
||||
taskTest = liftTest go,
|
||||
taskCount = 1000
|
||||
}
|
||||
where
|
||||
@@ -144,7 +144,7 @@ signTest :: String -> Curve -> Task
|
||||
signTest name curve = Task {
|
||||
taskName = name ++ " curve signing",
|
||||
taskFile = "../testdata/ecc/sign/" ++ name ++ ".test",
|
||||
taskTest = go,
|
||||
taskTest = liftTest go,
|
||||
taskCount = 1000
|
||||
}
|
||||
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 DSA(dsaTasks)
|
||||
import ECDSATesting(ecdsaTasks)
|
||||
import ED25519(ed25519Tasks)
|
||||
import GHC.Conc(getNumCapabilities)
|
||||
import RFC6979(rfcTasks)
|
||||
import RSA(rsaTasks)
|
||||
@@ -38,6 +39,6 @@ main = displayConsoleRegions $
|
||||
do
|
||||
executors <- getNumCapabilities
|
||||
done <- newChan
|
||||
tasks <- newMVar (dsaTasks ++ ecdsaTasks ++ rfcTasks ++ rsaTasks)
|
||||
tasks <- newMVar (dsaTasks ++ ecdsaTasks ++ rfcTasks ++ rsaTasks ++ ed25519Tasks)
|
||||
replicateM_ executors (spawnExecutor tasks done)
|
||||
replicateM_ executors (void $ readChan done)
|
||||
@@ -15,7 +15,7 @@ import qualified Data.ByteString as S
|
||||
import Data.Char(toUpper)
|
||||
import qualified Data.Map.Strict as Map
|
||||
import Math(showBin,showX)
|
||||
import Task(Task(..))
|
||||
import Task(Task(..),liftTest)
|
||||
import Utils(HashAlg(..), runHash)
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ rfc6979Test :: HashAlg -> Task
|
||||
rfc6979Test alg = Task {
|
||||
taskName = name ++ " RFC 6979 deterministic k-generation",
|
||||
taskFile = "../testdata/rfc6979/" ++ name ++ ".test",
|
||||
taskTest = go,
|
||||
taskTest = liftTest go,
|
||||
taskCount = 1000
|
||||
}
|
||||
where
|
||||
|
||||
@@ -18,7 +18,7 @@ import Data.Maybe(fromMaybe,isJust)
|
||||
import Data.Word(Word8)
|
||||
import Database(Database)
|
||||
import Math(barrett,computeK,showX,showBin)
|
||||
import Task(Task(..))
|
||||
import Task(Task(..),liftTest)
|
||||
import Utils(HashAlg(..),generateHash,showHash)
|
||||
|
||||
rsaSizes :: [(Int, Int)]
|
||||
@@ -40,7 +40,7 @@ signTest :: Int -> Int -> Task
|
||||
signTest sz cnt = Task {
|
||||
taskName = "RSA " ++ show sz ++ " signing",
|
||||
taskFile = "../testdata/rsa/sign" ++ show sz ++ ".test",
|
||||
taskTest = go,
|
||||
taskTest = liftTest go,
|
||||
taskCount = cnt
|
||||
}
|
||||
where
|
||||
@@ -78,7 +78,7 @@ encryptTest :: Int -> Int -> Task
|
||||
encryptTest sz cnt = Task {
|
||||
taskName = "RSA " ++ show sz ++ " encryption",
|
||||
taskFile = "../testdata/rsa/encrypt" ++ show sz ++ ".test",
|
||||
taskTest = go,
|
||||
taskTest = liftTest go,
|
||||
taskCount = cnt
|
||||
}
|
||||
where
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
module Task(
|
||||
Test,
|
||||
Task(..),
|
||||
runTask
|
||||
runTask,
|
||||
liftTest
|
||||
)
|
||||
where
|
||||
|
||||
@@ -15,7 +16,7 @@ import System.Directory(createDirectoryIfMissing,doesFileExist)
|
||||
import System.FilePath(takeDirectory)
|
||||
import System.IO(Handle,IOMode(..),hPutStrLn,withFile)
|
||||
|
||||
type Test = Database -> (Map.Map String String, Integer, Database)
|
||||
type Test = Database -> IO (Map.Map String String, Integer, Database)
|
||||
|
||||
data Task = Task {
|
||||
taskName :: String,
|
||||
@@ -24,6 +25,10 @@ data Task = Task {
|
||||
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 gen task =
|
||||
do createDirectoryIfMissing True (takeDirectory (taskFile task))
|
||||
@@ -40,8 +45,8 @@ runTask gen task =
|
||||
where
|
||||
writer :: Handle -> ProgressBar -> Test -> Database -> Int -> IO Database
|
||||
writer hndl pg runner db x =
|
||||
do let (output, key, acc@(db',gen')) = runner db
|
||||
before = Map.findWithDefault [] "RESULT" db'
|
||||
do (output, key, acc@(db',gen')) <- runner db
|
||||
let before = Map.findWithDefault [] "RESULT" db'
|
||||
if length (filter (== key) before) >= 10
|
||||
then writer hndl pg runner acc x
|
||||
else do forM_ (Map.toList output) $ \ (outkey, val) ->
|
||||
|
||||
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
|
||||
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:
|
||||
build-depends: base >=4.11 && < 4.14, ascii-progress, bytestring, containers, crypto-api, cryptonite, directory, DSA, filepath, integer-gmp, memory, random
|
||||
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
|
||||
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
21
testdata/ssh/dsa1024-1
vendored
Normal file
21
testdata/ssh/dsa1024-1
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH
|
||||
NzAAAAgQCSopxU2Z3j5yRG6C2s61Yw4LpeK2JvW5WPN3Vwh4184/UsW5LbaT28rhIgiiIJ
|
||||
LK+MWngCY/B3BsfI8ESrO/9azvvgu3e2CeJgZI2FDFOvQDpAspC8+D/MFX2T4H5wtAhAeG
|
||||
0ZBLyHkyD4vMpyGm78NlKYuELZ5MnqYbiNbk4D/QAAABUAjL97trgh43VJbUTaSPJb1JS2
|
||||
PyEAAACBAIJIOEB2hDM7u/Nu5RX/uAuDZWdCBfXsZiGKtMBggt4lwR8pgaM7GdNa5RAB+A
|
||||
D4uYjdYEY+8jQwVK17Hro85aNxhb2CqgDwy6p/xw9o4Mg6N0d8c37G6TR13VMSNb8S8a6u
|
||||
XDquooYHEqUNBpc3ZqF04VlOBMQ+eaplJwjez/YZAAAAgA30+EQmqT+jyEQNIJdbVDuNlo
|
||||
ZcVwSNorY/PFapm0nXU+xd7JvbRl8qOrCjUBkzrR/hE6niACBSxEAkWFvFL8WMKrw5Wo3Q
|
||||
9bgRV/tnryBF/ntYselEb7C97Ola7liA8akNkO/Wxd95PRnYXZcT4Z+ylRGTASCL4R0JLo
|
||||
5S3UxmAAAB+FQ5nYFUOZ2BAAAAB3NzaC1kc3MAAACBAJKinFTZnePnJEboLazrVjDgul4r
|
||||
Ym9blY83dXCHjXzj9SxbkttpPbyuEiCKIgksr4xaeAJj8HcGx8jwRKs7/1rO++C7d7YJ4m
|
||||
BkjYUMU69AOkCykLz4P8wVfZPgfnC0CEB4bRkEvIeTIPi8ynIabvw2Upi4QtnkyephuI1u
|
||||
TgP9AAAAFQCMv3u2uCHjdUltRNpI8lvUlLY/IQAAAIEAgkg4QHaEMzu7827lFf+4C4NlZ0
|
||||
IF9exmIYq0wGCC3iXBHymBozsZ01rlEAH4APi5iN1gRj7yNDBUrXseujzlo3GFvYKqAPDL
|
||||
qn/HD2jgyDo3R3xzfsbpNHXdUxI1vxLxrq5cOq6ihgcSpQ0GlzdmoXThWU4ExD55qmUnCN
|
||||
7P9hkAAACADfT4RCapP6PIRA0gl1tUO42WhlxXBI2itj88VqmbSddT7F3sm9tGXyo6sKNQ
|
||||
GTOtH+ETqeIAIFLEQCRYW8UvxYwqvDlajdD1uBFX+2evIEX+e1ix6URvsL3s6VruWIDxqQ
|
||||
2Q79bF33k9GdhdlxPhn7KVEZMBIIvhHQkujlLdTGYAAAAVAIn6EyjG3VGgWT4cSZ9gPCfi
|
||||
AXJdAAAAGmF3aWNrQGR1bndvcnRoeS51aHN1cmUuY29tAQIDBAUGBw==
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
1
testdata/ssh/dsa1024-1.pub
vendored
Normal file
1
testdata/ssh/dsa1024-1.pub
vendored
Normal file
@@ -0,0 +1 @@
|
||||
ssh-dss AAAAB3NzaC1kc3MAAACBAJKinFTZnePnJEboLazrVjDgul4rYm9blY83dXCHjXzj9SxbkttpPbyuEiCKIgksr4xaeAJj8HcGx8jwRKs7/1rO++C7d7YJ4mBkjYUMU69AOkCykLz4P8wVfZPgfnC0CEB4bRkEvIeTIPi8ynIabvw2Upi4QtnkyephuI1uTgP9AAAAFQCMv3u2uCHjdUltRNpI8lvUlLY/IQAAAIEAgkg4QHaEMzu7827lFf+4C4NlZ0IF9exmIYq0wGCC3iXBHymBozsZ01rlEAH4APi5iN1gRj7yNDBUrXseujzlo3GFvYKqAPDLqn/HD2jgyDo3R3xzfsbpNHXdUxI1vxLxrq5cOq6ihgcSpQ0GlzdmoXThWU4ExD55qmUnCN7P9hkAAACADfT4RCapP6PIRA0gl1tUO42WhlxXBI2itj88VqmbSddT7F3sm9tGXyo6sKNQGTOtH+ETqeIAIFLEQCRYW8UvxYwqvDlajdD1uBFX+2evIEX+e1ix6URvsL3s6VruWIDxqQ2Q79bF33k9GdhdlxPhn7KVEZMBIIvhHQkujlLdTGY= awick@dunworthy.uhsure.com
|
||||
21
testdata/ssh/dsa1024-2
vendored
Normal file
21
testdata/ssh/dsa1024-2
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsQAAAAdzc2gtZH
|
||||
NzAAAAgQCNMax5283mzH5/kHpjm02w3A4Fx5UMdFct0PEks/iSgFfNVBmEseSj7g13mUx2
|
||||
IclNpe20PEj3pG42fzRCmriHxgxpeoOXZjkWXk4+od8wbHhkB+aHNG5tjpNvKWOO29IFE/
|
||||
Mp/7Ae1/gXK1qmvtxEuw1ZIWIZvnhr+D14Cp5lPwAAABUAhYTqLOrmDhgozft9Di63ytRJ
|
||||
YsEAAACAP/mQISEMVvArXUTGSUDMRpT1kHZx0eCyH1Y8qpEOg8vjH90rBf+i977q5fI3wA
|
||||
kkAWb8pkt0Gm6J0+TLOGz9xjDII8vyyjGX2LKK89FYBIkZ+fcJo45t+akJbSQvxR0zScZC
|
||||
j/6pRiZP8DNYvU2XdhZ5/PejdjyLTJc/raWAe14AAACAC6WrzwiUHtYuA9ucpXlO1aq5w3
|
||||
a9WhzHROTgLV0JMIDVT6RhpW9dlOhP6KHAk+bV3j23nCUjfDEPFmWq18iturn+t4CdJhfR
|
||||
Lcg0yZHVnHZYmhZHRhG47GtcZXb/V0W8xkfFu9yJiprIBmilTdwfztaBnuXfVUDeduepfx
|
||||
tQg0oAAAHwfdS1ZH3UtWQAAAAHc3NoLWRzcwAAAIEAjTGsedvN5sx+f5B6Y5tNsNwOBceV
|
||||
DHRXLdDxJLP4koBXzVQZhLHko+4Nd5lMdiHJTaXttDxI96RuNn80Qpq4h8YMaXqDl2Y5Fl
|
||||
5OPqHfMGx4ZAfmhzRubY6TbyljjtvSBRPzKf+wHtf4Fytapr7cRLsNWSFiGb54a/g9eAqe
|
||||
ZT8AAAAVAIWE6izq5g4YKM37fQ4ut8rUSWLBAAAAgD/5kCEhDFbwK11ExklAzEaU9ZB2cd
|
||||
Hgsh9WPKqRDoPL4x/dKwX/ove+6uXyN8AJJAFm/KZLdBpuidPkyzhs/cYwyCPL8soxl9iy
|
||||
ivPRWASJGfn3CaOObfmpCW0kL8UdM0nGQo/+qUYmT/AzWL1Nl3YWefz3o3Y8i0yXP62lgH
|
||||
teAAAAgAulq88IlB7WLgPbnKV5TtWqucN2vVocx0Tk4C1dCTCA1U+kYaVvXZToT+ihwJPm
|
||||
1d49t5wlI3wxDxZlqtfIrbq5/reAnSYX0S3INMmR1Zx2WJoWR0YRuOxrXGV2/1dFvMZHxb
|
||||
vciYqayAZopU3cH87WgZ7l31VA3nbnqX8bUINKAAAAFFKV6pwwS6wdCUQLixDil2i3z20u
|
||||
AAAAGmF3aWNrQGR1bndvcnRoeS51aHN1cmUuY29tAQ==
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
1
testdata/ssh/dsa1024-2.pub
vendored
Normal file
1
testdata/ssh/dsa1024-2.pub
vendored
Normal file
@@ -0,0 +1 @@
|
||||
ssh-dss AAAAB3NzaC1kc3MAAACBAI0xrHnbzebMfn+QemObTbDcDgXHlQx0Vy3Q8SSz+JKAV81UGYSx5KPuDXeZTHYhyU2l7bQ8SPekbjZ/NEKauIfGDGl6g5dmORZeTj6h3zBseGQH5oc0bm2Ok28pY47b0gUT8yn/sB7X+BcrWqa+3ES7DVkhYhm+eGv4PXgKnmU/AAAAFQCFhOos6uYOGCjN+30OLrfK1EliwQAAAIA/+ZAhIQxW8CtdRMZJQMxGlPWQdnHR4LIfVjyqkQ6Dy+Mf3SsF/6L3vurl8jfACSQBZvymS3QabonT5Ms4bP3GMMgjy/LKMZfYsorz0VgEiRn59wmjjm35qQltJC/FHTNJxkKP/qlGJk/wM1i9TZd2Fnn896N2PItMlz+tpYB7XgAAAIALpavPCJQe1i4D25yleU7VqrnDdr1aHMdE5OAtXQkwgNVPpGGlb12U6E/oocCT5tXePbecJSN8MQ8WZarXyK26uf63gJ0mF9EtyDTJkdWcdliaFkdGEbjsa1xldv9XRbzGR8W73ImKmsgGaKVN3B/O1oGe5d9VQN5256l/G1CDSg== awick@dunworthy.uhsure.com
|
||||
21
testdata/ssh/dsa1024-3
vendored
Normal file
21
testdata/ssh/dsa1024-3
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH
|
||||
NzAAAAgQCZw7G06AhpCc7eQ5WUMyuo5b9xkm4TvJI/W7Xtr7XrvG2hiDgLfDgfInotJoZh
|
||||
yBgsOtSwnfoVBMnbkMGYIVa+DRD+9VnVwOo2kv7cKaioKwHjiExKXnG3T7yWbWIHl61KB0
|
||||
DaFFnLS2q/p7qSxaZEMORflSwuUAaU3dHhdMuIVwAAABUA9x4hZRt4/SKWbHgkQNLR16nx
|
||||
HfsAAACBAJZMEP1GPRKzwJWgN2fXgrYoRNfB2ua1jPHVcU2ezuvaj5n7LtxQi79Ku0VN7S
|
||||
8DlBjW7uiW+9XUHve08MK14nkEwLGMErm+o/usKpXf0LUExa0LW/Msogo4cnMLUFdlzR2e
|
||||
ALNFX+icMQCfFct6uAnwpAuuIFDwOEipVnB08YQNAAAAgAxhAU84ELN8gFVTpVrB5cAUd2
|
||||
CJX6i4/lq6L9o/wDVd/Z69JKV1Jn/zPH/LxjN3mHXMBZ30HGOnuQhkIdb/1stguSO0o3nQ
|
||||
IzTtTIgyuu0RTig+4SIqw0n05CTUVjbzEwehyLTtMPbWZ+F51wgUr8has6zuwwxIeExJfC
|
||||
P9eYvYAAAB8ONMdaDjTHWgAAAAB3NzaC1kc3MAAACBAJnDsbToCGkJzt5DlZQzK6jlv3GS
|
||||
bhO8kj9bte2vteu8baGIOAt8OB8iei0mhmHIGCw61LCd+hUEyduQwZghVr4NEP71WdXA6j
|
||||
aS/twpqKgrAeOITEpecbdPvJZtYgeXrUoHQNoUWctLar+nupLFpkQw5F+VLC5QBpTd0eF0
|
||||
y4hXAAAAFQD3HiFlG3j9IpZseCRA0tHXqfEd+wAAAIEAlkwQ/UY9ErPAlaA3Z9eCtihE18
|
||||
Ha5rWM8dVxTZ7O69qPmfsu3FCLv0q7RU3tLwOUGNbu6Jb71dQe97TwwrXieQTAsYwSub6j
|
||||
+6wqld/QtQTFrQtb8yyiCjhycwtQV2XNHZ4As0Vf6JwxAJ8Vy3q4CfCkC64gUPA4SKlWcH
|
||||
TxhA0AAACADGEBTzgQs3yAVVOlWsHlwBR3YIlfqLj+Wrov2j/ANV39nr0kpXUmf/M8f8vG
|
||||
M3eYdcwFnfQcY6e5CGQh1v/Wy2C5I7SjedAjNO1MiDK67RFOKD7hIirDSfTkJNRWNvMTB6
|
||||
HItO0w9tZn4XnXCBSvyFqzrO7DDEh4TEl8I/15i9gAAAAUUvi6ONM44iZLHwT97nfZptMe
|
||||
YMQAAAAaYXdpY2tAZHVud29ydGh5LnVoc3VyZS5jb20=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
1
testdata/ssh/dsa1024-3.pub
vendored
Normal file
1
testdata/ssh/dsa1024-3.pub
vendored
Normal file
@@ -0,0 +1 @@
|
||||
ssh-dss AAAAB3NzaC1kc3MAAACBAJnDsbToCGkJzt5DlZQzK6jlv3GSbhO8kj9bte2vteu8baGIOAt8OB8iei0mhmHIGCw61LCd+hUEyduQwZghVr4NEP71WdXA6jaS/twpqKgrAeOITEpecbdPvJZtYgeXrUoHQNoUWctLar+nupLFpkQw5F+VLC5QBpTd0eF0y4hXAAAAFQD3HiFlG3j9IpZseCRA0tHXqfEd+wAAAIEAlkwQ/UY9ErPAlaA3Z9eCtihE18Ha5rWM8dVxTZ7O69qPmfsu3FCLv0q7RU3tLwOUGNbu6Jb71dQe97TwwrXieQTAsYwSub6j+6wqld/QtQTFrQtb8yyiCjhycwtQV2XNHZ4As0Vf6JwxAJ8Vy3q4CfCkC64gUPA4SKlWcHTxhA0AAACADGEBTzgQs3yAVVOlWsHlwBR3YIlfqLj+Wrov2j/ANV39nr0kpXUmf/M8f8vGM3eYdcwFnfQcY6e5CGQh1v/Wy2C5I7SjedAjNO1MiDK67RFOKD7hIirDSfTkJNRWNvMTB6HItO0w9tZn4XnXCBSvyFqzrO7DDEh4TEl8I/15i9g= awick@dunworthy.uhsure.com
|
||||
9
testdata/ssh/ecdsa256-1
vendored
Normal file
9
testdata/ssh/ecdsa256-1
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
|
||||
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQQapSFr4Ak0LikLhY2wRnI9H+ttSCz8
|
||||
I1qxBNSCmrIg4gYSacKyIeBOvh0TwVhb4dXUNQCrAwFrkoVif5Tf1f8FAAAAuE5AsvxOQL
|
||||
L8AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBqlIWvgCTQuKQuF
|
||||
jbBGcj0f621ILPwjWrEE1IKasiDiBhJpwrIh4E6+HRPBWFvh1dQ1AKsDAWuShWJ/lN/V/w
|
||||
UAAAAhAOLnouDts1najIC8jL/N4s2YAd86iDTKQKL/0j1wkC0NAAAAGmF3aWNrQGR1bndv
|
||||
cnRoeS51aHN1cmUuY29tAQIDBAU=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
1
testdata/ssh/ecdsa256-1.pub
vendored
Normal file
1
testdata/ssh/ecdsa256-1.pub
vendored
Normal file
@@ -0,0 +1 @@
|
||||
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBqlIWvgCTQuKQuFjbBGcj0f621ILPwjWrEE1IKasiDiBhJpwrIh4E6+HRPBWFvh1dQ1AKsDAWuShWJ/lN/V/wU= awick@dunworthy.uhsure.com
|
||||
9
testdata/ssh/ecdsa256-2
vendored
Normal file
9
testdata/ssh/ecdsa256-2
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
|
||||
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQR3qD0xPdjQM6QwKfgd6a0kVoUDqdFC
|
||||
soZ2MN4YUg39zAbN2WD2JaQI++OQT3Db6tgb0uvILi7MYkiywoagvrtWAAAAuFDv91lQ7/
|
||||
dZAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHeoPTE92NAzpDAp
|
||||
+B3prSRWhQOp0UKyhnYw3hhSDf3MBs3ZYPYlpAj745BPcNvq2BvS68guLsxiSLLChqC+u1
|
||||
YAAAAgVBtRdgi+mNU79/k+2g/0qjnrrFgfVRXmmz3gafM6ZpMAAAAaYXdpY2tAZHVud29y
|
||||
dGh5LnVoc3VyZS5jb20BAgMEBQY=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
1
testdata/ssh/ecdsa256-2.pub
vendored
Normal file
1
testdata/ssh/ecdsa256-2.pub
vendored
Normal file
@@ -0,0 +1 @@
|
||||
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHeoPTE92NAzpDAp+B3prSRWhQOp0UKyhnYw3hhSDf3MBs3ZYPYlpAj745BPcNvq2BvS68guLsxiSLLChqC+u1Y= awick@dunworthy.uhsure.com
|
||||
9
testdata/ssh/ecdsa256-3
vendored
Normal file
9
testdata/ssh/ecdsa256-3
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
|
||||
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQQXufDcrei6sxgA/L3qB4ryVeFFCtLi
|
||||
6sR48mv4rK3EJ47pr1OeGbOGR44gYQesdIdrcQeA++hjBLH8jbiQOibzAAAAuKHFUSOhxV
|
||||
EjAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBe58Nyt6LqzGAD8
|
||||
veoHivJV4UUK0uLqxHjya/isrcQnjumvU54Zs4ZHjiBhB6x0h2txB4D76GMEsfyNuJA6Jv
|
||||
MAAAAhAOMC8qwMPt6NQvyoYPYHqEZVqjyLfhmkj17ml+kYuZCSAAAAGmF3aWNrQGR1bndv
|
||||
cnRoeS51aHN1cmUuY29tAQIDBAU=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user