Some more ECDSA documentation.

This commit is contained in:
2019-05-26 20:48:04 -07:00
parent 2145fb47fa
commit a19c1ee124
6 changed files with 91 additions and 18 deletions

View File

@@ -1,30 +1,54 @@
use cryptonum::signed::{I192,I256,I384,I576}; use cryptonum::signed::{I192,I256,I384,I576};
use cryptonum::unsigned::{Decoder}; use cryptonum::unsigned::{Decoder};
use cryptonum::unsigned::{U192,U256,U384,U576}; use cryptonum::unsigned::{U192,U256,U384,U576};
use ecdsa::point::Point;
use std::fmt::Debug; use std::fmt::Debug;
/// Elliptic curves must implement this trait in order to work with the rest
/// of the ECDSA system. I've included instances for the core NIST curves
/// used in most systems, but this could be extended without issues.
/// (Eventually the curves defined here should actually be extended in
/// interesting ways to make the math faster, but we haven't gotten there
/// yet.)
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub trait EllipticCurve { pub trait EllipticCurve {
/// The unsigned numeric type that fits constants for this curve.
type Unsigned : Clone; type Unsigned : Clone;
/// The signed numeric type that fits constants for this curve.
type Signed : Clone + Debug + PartialEq; type Signed : Clone + Debug + PartialEq;
/// The type of a point on the curve
type Point;
/// The size of the curve in bits.
fn size() -> usize; fn size() -> usize;
/// The `p` value for the curve.
fn p() -> Self::Unsigned; fn p() -> Self::Unsigned;
/// The `p` value for the curve.
fn n() -> Self::Unsigned; fn n() -> Self::Unsigned;
/// The seed value for the curve.
fn SEED() -> Self::Unsigned; fn SEED() -> Self::Unsigned;
/// The `c` value for the curve.
fn c() -> Self::Unsigned; fn c() -> Self::Unsigned;
/// The `a` value for the curve.
fn a() -> Self::Unsigned; fn a() -> Self::Unsigned;
/// The `b` value for the curve.
fn b() -> Self::Unsigned; fn b() -> Self::Unsigned;
/// The `x` coordinate of the base point for the curve.
fn Gx() -> Self::Signed; fn Gx() -> Self::Signed;
/// The `y` coordinate of the base point for the curve.
fn Gy() -> Self::Signed; fn Gy() -> Self::Signed;
/// Generate a point for the curve given the provided values.
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point;
} }
/// NIST curve P-192 (FIPS 186-4, page 101-102), a.k.a. secp192r1 from RFC5480
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub enum P192 {} pub struct P192 {}
impl EllipticCurve for P192 { impl EllipticCurve for P192 {
type Unsigned = U192; type Unsigned = U192;
type Signed = I192; type Signed = I192;
type Point = Point<P192>;
fn size() -> usize { fn size() -> usize {
192 192
@@ -61,14 +85,20 @@ impl EllipticCurve for P192 {
fn Gy() -> I192 { fn Gy() -> I192 {
I192::from(U192::from([0x73f977a11e794811, 0x631011ed6b24cdd5, 0x07192b95ffc8da78])) I192::from(U192::from([0x73f977a11e794811, 0x631011ed6b24cdd5, 0x07192b95ffc8da78]))
} }
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
Point::<P192>{ x: I192::from(x), y: I192::from(y) }
}
} }
/// NIST curve P-224 (FIPS 186-4, page 102), a.k.a. secp224r1 from RFC5480
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub enum P224 {} pub struct P224 {}
impl EllipticCurve for P224 { impl EllipticCurve for P224 {
type Unsigned = U256; type Unsigned = U256;
type Signed = I256; type Signed = I256;
type Point = Point<P224>;
fn size() -> usize { fn size() -> usize {
224 224
@@ -144,14 +174,20 @@ impl EllipticCurve for P224 {
0x85, 0x00, 0x7e, 0x34 0x85, 0x00, 0x7e, 0x34
])) ]))
} }
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
Point::<P224>{ x: I256::from(x), y: I256::from(y) }
}
} }
/// NIST curve P-256 (FIPS 186-4, page 102-103), a.k.a. secp256r1 from RFC5480
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub enum P256 {} pub struct P256 {}
impl EllipticCurve for P256 { impl EllipticCurve for P256 {
type Signed = I256; type Signed = I256;
type Unsigned = U256; type Unsigned = U256;
type Point = Point<P256>;
fn size() -> usize { fn size() -> usize {
256 256
@@ -228,14 +264,20 @@ impl EllipticCurve for P256 {
0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5
])) ]))
} }
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
Point::<P256>{ x: I256::from(x), y: I256::from(y) }
}
} }
/// NIST curve P-384 (FIPS 186-4, page 103-104), a.k.a. secp384r1 from RFC5480
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub enum P384 {} pub struct P384 {}
impl EllipticCurve for P384 { impl EllipticCurve for P384 {
type Signed = I384; type Signed = I384;
type Unsigned = U384; type Unsigned = U384;
type Point = Point<P384>;
fn size() -> usize { fn size() -> usize {
384 384
@@ -325,14 +367,20 @@ impl EllipticCurve for P384 {
0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f
])) ]))
} }
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
Point::<P384>{ x: I384::from(x), y: I384::from(y) }
}
} }
/// NIST curve P-521 (FIPS 186-4, page 104), a.k.a. secp521r1 from RFC5480
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub enum P521 {} pub struct P521 {}
impl EllipticCurve for P521 { impl EllipticCurve for P521 {
type Signed = I576; type Signed = I576;
type Unsigned = U576; type Unsigned = U576;
type Point = Point<P521>;
fn size() -> usize { fn size() -> usize {
521 521
@@ -443,4 +491,8 @@ impl EllipticCurve for P521 {
0x66, 0x50 0x66, 0x50
])) ]))
} }
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
Point::<P521>{ x: I576::from(x), y: I576::from(y) }
}
} }

View File

@@ -1,25 +1,28 @@
pub mod curve; mod curve;
pub mod point; pub(crate) mod point;
pub mod private; mod private;
pub mod public; mod public;
use cryptonum::signed::{I192,I256,I384,I576}; use cryptonum::signed::{I192,I256,I384,I576};
use cryptonum::unsigned::{CryptoNum,Decoder}; use cryptonum::unsigned::{CryptoNum,Decoder};
use cryptonum::unsigned::{U192,U256,U384,U576}; use cryptonum::unsigned::{U192,U256,U384,U576};
use rand::Rng; use rand::Rng;
use rand::distributions::Standard; use rand::distributions::Standard;
use self::curve::{EllipticCurve,P192,P224,P256,P384,P521}; pub use self::curve::{EllipticCurve,P192,P224,P256,P384,P521};
use self::point::{ECCPoint,Point}; use self::point::{ECCPoint,Point};
pub use self::private::{ECDSAPrivate,ECCPrivateKey}; pub use self::private::{ECDSAPrivate,ECCPrivateKey};
pub use self::public::{ECDSAPublic,ECCPublicKey}; pub use self::public::{ECDSAPublic,ECCPublicKey};
pub use self::public::{ECDSADecodeErr,ECDSAEncodeErr}; pub use self::public::{ECDSADecodeErr,ECDSAEncodeErr};
use super::KeyPair; use super::KeyPair;
/// An ECDSA key pair for the given curve.
pub struct ECDSAKeyPair<Curve: EllipticCurve> { pub struct ECDSAKeyPair<Curve: EllipticCurve> {
pub public: ECCPublicKey<Curve>, pub public: ECCPublicKey<Curve>,
pub private: ECCPrivateKey<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 { pub enum ECDSAPair {
P192(ECCPublicKey<P192>,ECCPrivateKey<P192>), P192(ECCPublicKey<P192>,ECCPrivateKey<P192>),
P224(ECCPublicKey<P224>,ECCPrivateKey<P224>), P224(ECCPublicKey<P224>,ECCPrivateKey<P224>),
@@ -57,7 +60,12 @@ macro_rules! generate_impl {
ECDSAKeyPair{ public, private } ECDSAKeyPair{ public, private }
} }
} }
impl ECDSAKeyPair<$curve> { 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> pub fn generate<G: Rng>(rng: &mut G) -> ECDSAKeyPair<$curve>
{ {
loop { loop {

View File

@@ -7,6 +7,7 @@ use ecdsa::point::{ECCPoint,Point};
use hmac::{Hmac,Mac}; use hmac::{Hmac,Mac};
use std::fmt; use std::fmt;
/// A private key for the given curve.
#[derive(PartialEq)] #[derive(PartialEq)]
pub struct ECCPrivateKey<Curve: EllipticCurve> { pub struct ECCPrivateKey<Curve: EllipticCurve> {
pub(crate) d: Curve::Unsigned pub(crate) d: Curve::Unsigned
@@ -19,6 +20,7 @@ impl<Curve: EllipticCurve> fmt::Debug for ECCPrivateKey<Curve> {
} }
} }
/// A generic private key.
pub enum ECDSAPrivate { pub enum ECDSAPrivate {
P192(ECCPrivateKey<P192>), P192(ECCPrivateKey<P192>),
P224(ECCPrivateKey<P224>), P224(ECCPrivateKey<P224>),
@@ -32,11 +34,14 @@ macro_rules! generate_privates
($curve: ident, $base: ident, $sig: ident, $dbl: ident, $quad: ident) => { ($curve: ident, $base: ident, $sig: ident, $dbl: ident, $quad: ident) => {
impl ECCPrivateKey<$curve> impl ECCPrivateKey<$curve>
{ {
/// Generate a new private key using the given private scalar.
pub fn new(d: $base) -> ECCPrivateKey<$curve> pub fn new(d: $base) -> ECCPrivateKey<$curve>
{ {
ECCPrivateKey{ d } ECCPrivateKey{ d }
} }
/// Sign the given message with the current key, using the hash provided
/// in the type.
pub fn sign<Hash>(&self, m: &[u8]) -> DSASignature<$base> pub fn sign<Hash>(&self, m: &[u8]) -> DSASignature<$base>
where where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset, Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,

View File

@@ -8,11 +8,14 @@ use hmac::{Hmac,Mac};
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,FromASN1,ToASN1}; use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,FromASN1,ToASN1};
use std::cmp::min; use std::cmp::min;
/// An ECDSA public key for the given curve.
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct ECCPublicKey<Curve: EllipticCurve> { pub struct ECCPublicKey<Curve: EllipticCurve> {
pub(crate) q: Point<Curve> pub(crate) q: Point<Curve>
} }
/// A generic ECDSA public key, when you're not sure which curve you're
/// going to get.
pub enum ECDSAPublic { pub enum ECDSAPublic {
P192(ECCPublicKey<P192>), P192(ECCPublicKey<P192>),
P224(ECCPublicKey<P224>), P224(ECCPublicKey<P224>),
@@ -21,6 +24,8 @@ pub enum ECDSAPublic {
P521(ECCPublicKey<P521>), P521(ECCPublicKey<P521>),
} }
/// An error that can occur when encoding an ECDSA public key as an ASN.1
/// object.
pub enum ECDSAEncodeErr { pub enum ECDSAEncodeErr {
ASN1EncodeErr(ASN1EncodeErr), ASN1EncodeErr(ASN1EncodeErr),
XValueNegative, YValueNegative XValueNegative, YValueNegative
@@ -32,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)] #[derive(Debug)]
pub enum ECDSADecodeErr { pub enum ECDSADecodeErr {
ASN1DecodeErr(ASN1DecodeErr), ASN1DecodeErr(ASN1DecodeErr),
@@ -50,11 +57,14 @@ macro_rules! public_impl {
($curve: ident, $un: ident, $si: ident) => { ($curve: ident, $un: ident, $si: ident) => {
impl ECCPublicKey<$curve> impl ECCPublicKey<$curve>
{ {
/// Generate a new public key object from the given public point.
pub fn new(q: Point<$curve>) -> ECCPublicKey<$curve> pub fn new(q: Point<$curve>) -> ECCPublicKey<$curve>
{ {
ECCPublicKey{ q } ECCPublicKey{ q }
} }
/// 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 pub fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<$un>) -> bool
where where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset, Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,

View File

@@ -1,8 +1,6 @@
use cryptonum::signed::*;
use cryptonum::unsigned::*; use cryptonum::unsigned::*;
use ecdsa::{ECDSAPair,ECDSAPublic,ECCPublicKey,ECDSAPrivate,ECCPrivateKey}; use ecdsa::{ECDSAPair,ECDSAPublic,ECCPublicKey,ECDSAPrivate,ECCPrivateKey};
use ecdsa::curve::{P256,P384,P521}; use ecdsa::{EllipticCurve,P256,P384,P521};
use ecdsa::point::Point;
use std::io::{Read,Write}; use std::io::{Read,Write};
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError}; use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
use ssh::frame::*; use ssh::frame::*;
@@ -33,7 +31,7 @@ impl SSHKey for ECDSAPair {
} }
let x = U256::from_bytes(&val[1..33]); let x = U256::from_bytes(&val[1..33]);
let y = U256::from_bytes(&val[33..]); let y = U256::from_bytes(&val[33..]);
let p = Point::<P256>{ x: I256::from(x), y: I256::from(y) }; let p = P256::new_point(x, y);
let pbl = ECCPublicKey::<P256>::new(p); let pbl = ECCPublicKey::<P256>::new(p);
Ok(ECDSAPublic::P256(pbl)) Ok(ECDSAPublic::P256(pbl))
} }
@@ -44,7 +42,7 @@ impl SSHKey for ECDSAPair {
} }
let x = U384::from_bytes(&val[1..49]); let x = U384::from_bytes(&val[1..49]);
let y = U384::from_bytes(&val[49..]); let y = U384::from_bytes(&val[49..]);
let p = Point::<P384>{ x: I384::from(x), y: I384::from(y) }; let p = P384::new_point(x, y);
let pbl = ECCPublicKey::<P384>::new(p); let pbl = ECCPublicKey::<P384>::new(p);
Ok(ECDSAPublic::P384(pbl)) Ok(ECDSAPublic::P384(pbl))
} }
@@ -55,7 +53,7 @@ impl SSHKey for ECDSAPair {
} }
let x = U576::from_bytes(&val[1..67]); let x = U576::from_bytes(&val[1..67]);
let y = U576::from_bytes(&val[67..]); let y = U576::from_bytes(&val[67..]);
let p = Point::<P521>{ x: I576::from(x), y: I576::from(y) }; let p = P521::new_point(x, y);
let pbl = ECCPublicKey::<P521>::new(p); let pbl = ECCPublicKey::<P521>::new(p);
Ok(ECDSAPublic::P521(pbl)) Ok(ECDSAPublic::P521(pbl))
} }

View File

@@ -2,7 +2,7 @@ use cryptonum::unsigned::{U3072,U2048,U1024,U256,U192};
use dsa::{DSAPublic,DSAPublicKey,DSAParameters}; use dsa::{DSAPublic,DSAPublicKey,DSAParameters};
use dsa::{L3072N256,L2048N256,L2048N224,L1024N160}; use dsa::{L3072N256,L2048N256,L2048N224,L1024N160};
use ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPublicKey}; use ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPublicKey};
use ecdsa::curve::{P192,P224,P256,P384,P521}; use ecdsa::{P192,P224,P256,P384,P521};
use num::BigUint; use num::BigUint;
use rsa::RSAPublic; use rsa::RSAPublic;
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1, use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1,