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::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;
/// 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;
}
/// NIST curve P-192 (FIPS 186-4, page 101-102), a.k.a. secp192r1 from RFC5480
#[derive(Debug,PartialEq)]
pub enum P192 {}
pub struct P192 {}
impl EllipticCurve for P192 {
type Unsigned = U192;
type Signed = I192;
type Point = Point<P192>;
fn size() -> usize {
192
@@ -61,14 +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) }
}
}
/// NIST curve P-224 (FIPS 186-4, page 102), a.k.a. secp224r1 from RFC5480
#[derive(Debug,PartialEq)]
pub enum P224 {}
pub struct P224 {}
impl EllipticCurve for P224 {
type Unsigned = U256;
type Signed = I256;
type Point = Point<P224>;
fn size() -> usize {
224
@@ -144,14 +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) }
}
}
/// NIST curve P-256 (FIPS 186-4, page 102-103), a.k.a. secp256r1 from RFC5480
#[derive(Debug,PartialEq)]
pub enum P256 {}
pub struct P256 {}
impl EllipticCurve for P256 {
type Signed = I256;
type Unsigned = U256;
type Point = Point<P256>;
fn size() -> usize {
256
@@ -228,14 +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) }
}
}
/// NIST curve P-384 (FIPS 186-4, page 103-104), a.k.a. secp384r1 from RFC5480
#[derive(Debug,PartialEq)]
pub enum P384 {}
pub struct P384 {}
impl EllipticCurve for P384 {
type Signed = I384;
type Unsigned = U384;
type Point = Point<P384>;
fn size() -> usize {
384
@@ -325,14 +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) }
}
}
/// NIST curve P-521 (FIPS 186-4, page 104), a.k.a. secp521r1 from RFC5480
#[derive(Debug,PartialEq)]
pub enum P521 {}
pub struct P521 {}
impl EllipticCurve for P521 {
type Signed = I576;
type Unsigned = U576;
type Point = Point<P521>;
fn size() -> usize {
521
@@ -443,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) }
}
}

View File

@@ -1,25 +1,28 @@
pub mod curve;
pub mod point;
pub mod private;
pub mod public;
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::{ECDSAPrivate,ECCPrivateKey};
pub use self::public::{ECDSAPublic,ECCPublicKey};
pub use self::public::{ECDSADecodeErr,ECDSAEncodeErr};
use super::KeyPair;
/// 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>),
@@ -57,7 +60,12 @@ macro_rules! generate_impl {
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 {

View File

@@ -7,6 +7,7 @@ use ecdsa::point::{ECCPoint,Point};
use hmac::{Hmac,Mac};
use std::fmt;
/// A private key for the given curve.
#[derive(PartialEq)]
pub struct ECCPrivateKey<Curve: EllipticCurve> {
pub(crate) d: Curve::Unsigned
@@ -19,6 +20,7 @@ impl<Curve: EllipticCurve> fmt::Debug for ECCPrivateKey<Curve> {
}
}
/// A generic private key.
pub enum ECDSAPrivate {
P192(ECCPrivateKey<P192>),
P224(ECCPrivateKey<P224>),
@@ -32,11 +34,14 @@ macro_rules! generate_privates
($curve: ident, $base: ident, $sig: ident, $dbl: ident, $quad: ident) => {
impl ECCPrivateKey<$curve>
{
/// Generate a new private key using the given private scalar.
pub fn new(d: $base) -> ECCPrivateKey<$curve>
{
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>
where
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 std::cmp::min;
/// 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 {
P192(ECCPublicKey<P192>),
P224(ECCPublicKey<P224>),
@@ -21,6 +24,8 @@ pub enum ECDSAPublic {
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
@@ -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)]
pub enum ECDSADecodeErr {
ASN1DecodeErr(ASN1DecodeErr),
@@ -50,11 +57,14 @@ macro_rules! public_impl {
($curve: ident, $un: ident, $si: ident) => {
impl ECCPublicKey<$curve>
{
/// Generate a new public key object from the given public point.
pub fn new(q: Point<$curve>) -> ECCPublicKey<$curve>
{
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
where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,

View File

@@ -1,8 +1,6 @@
use cryptonum::signed::*;
use cryptonum::unsigned::*;
use ecdsa::{ECDSAPair,ECDSAPublic,ECCPublicKey,ECDSAPrivate,ECCPrivateKey};
use ecdsa::curve::{P256,P384,P521};
use ecdsa::point::Point;
use ecdsa::{EllipticCurve,P256,P384,P521};
use std::io::{Read,Write};
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
use ssh::frame::*;
@@ -33,7 +31,7 @@ impl SSHKey for ECDSAPair {
}
let x = U256::from_bytes(&val[1..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);
Ok(ECDSAPublic::P256(pbl))
}
@@ -44,7 +42,7 @@ impl SSHKey for ECDSAPair {
}
let x = U384::from_bytes(&val[1..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);
Ok(ECDSAPublic::P384(pbl))
}
@@ -55,7 +53,7 @@ impl SSHKey for ECDSAPair {
}
let x = U576::from_bytes(&val[1..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);
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::{L3072N256,L2048N256,L2048N224,L1024N160};
use ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPublicKey};
use ecdsa::curve::{P192,P224,P256,P384,P521};
use ecdsa::{P192,P224,P256,P384,P521};
use num::BigUint;
use rsa::RSAPublic;
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1,