Some more ECDSA documentation.
This commit is contained in:
@@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user