associate diffie_hellman, generate_public, generate_secret with the Ephemeral type; implement Mul for Ephemeral; create SharedSecret type & implement drop; change docs to reflect new methods on the Ephemeral type

This commit is contained in:
DebugSteven 2018-11-10 15:29:17 -05:00
parent e93a7125d9
commit 1b64afd83d
2 changed files with 73 additions and 62 deletions

View file

@ -32,21 +32,20 @@
//! incantations, the kittens will be able to secretly organise to find their
//! mittens, and then spend the rest of the afternoon nomming some yummy pie!
//!
//! First, Alice uses `x25519_dalek::generate_secret()` and
//! `x25519_dalek::generate_public()` to produce her secret and public keys:
//! First, Alice uses `x25519_dalek::Ephemeral::generate_secret()` and
//! `x25519_dalek::Ephemeral::generate_public()` to produce her secret and public keys:
//!
//! ```
//! extern crate x25519_dalek;
//! extern crate rand;
//!
//! # fn main() {
//! use x25519_dalek::generate_secret;
//! use x25519_dalek::generate_public;
//! use x25519_dalek::Ephemeral;
//! use rand::thread_rng;
//!
//! let mut alice_csprng = thread_rng();
//! let alice_secret = generate_secret(&mut alice_csprng);
//! let alice_public = generate_public(&alice_secret);
//! let alice_secret = Ephemeral::generate_secret(&mut alice_csprng);
//! let alice_public = Ephemeral::generate_public(&alice_secret);
//! # }
//! ```
//!
@ -57,13 +56,12 @@
//! # extern crate rand;
//! #
//! # fn main() {
//! # use x25519_dalek::generate_secret;
//! # use x25519_dalek::generate_public;
//! # use x25519_dalek::Ephemeral;
//! # use rand::thread_rng;
//! #
//! let mut bob_csprng = thread_rng();
//! let bob_secret = generate_secret(&mut bob_csprng);
//! let bob_public = generate_public(&bob_secret);
//! let bob_secret = Ephemeral::generate_secret(&mut bob_csprng);
//! let bob_public = Ephemeral::generate_public(&bob_secret);
//! # }
//! ```
//!
@ -76,21 +74,19 @@
//! # extern crate rand;
//! #
//! # fn main() {
//! # use x25519_dalek::generate_secret;
//! # use x25519_dalek::generate_public;
//! # use x25519_dalek::Ephemeral;
//! # use rand::thread_rng;
//! #
//! # let mut alice_csprng = thread_rng();
//! # let alice_secret = generate_secret(&mut alice_csprng);
//! # let alice_public = generate_public(&alice_secret);
//! # let alice_secret = Ephemeral::generate_secret(&mut alice_csprng);
//! # let alice_public = Ephemeral::generate_public(&alice_secret);
//! #
//! # let mut bob_csprng = thread_rng();
//! # let bob_secret = generate_secret(&mut bob_csprng);
//! # let bob_public = generate_public(&bob_secret);
//! # let bob_secret = Ephemeral::generate_secret(&mut bob_csprng);
//! # let bob_public = Ephemeral::generate_public(&bob_secret);
//! #
//! use x25519_dalek::diffie_hellman;
//!
//! let shared_secret = diffie_hellman(&alice_secret, &bob_public.as_bytes());
//! let shared_secret = Ephemeral::diffie_hellman(&alice_secret, &bob_public);
//! # }
//! ```
//!
@ -101,20 +97,18 @@
//! # extern crate rand;
//! #
//! # fn main() {
//! # use x25519_dalek::diffie_hellman;
//! # use x25519_dalek::generate_secret;
//! # use x25519_dalek::generate_public;
//! # use x25519_dalek::Ephemeral;
//! # use rand::thread_rng;
//! #
//! # let mut alice_csprng = thread_rng();
//! # let alice_secret = generate_secret(&mut alice_csprng);
//! # let alice_public = generate_public(&alice_secret);
//! # let alice_secret = Ephemeral::generate_secret(&mut alice_csprng);
//! # let alice_public = Ephemeral::generate_public(&alice_secret);
//! #
//! # let mut bob_csprng = thread_rng();
//! # let bob_secret = generate_secret(&mut bob_csprng);
//! # let bob_public = generate_public(&bob_secret);
//! # let bob_secret = Ephemeral::generate_secret(&mut bob_csprng);
//! # let bob_public = Ephemeral::generate_public(&bob_secret);
//! #
//! let shared_secret = diffie_hellman(&bob_secret, &alice_public.as_bytes());
//! let shared_secret = Ephemeral::diffie_hellman(&bob_secret, &alice_public);
//! # }
//! ```
//!

View file

@ -12,7 +12,8 @@
//! This implements x25519 key exchange as specified by Mike Hamburg
//! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748).
use core::fmt::{Debug};
use core::mem;
use core::ops::Mul;
use clear_on_drop::clear::Clear;
@ -23,52 +24,80 @@ use curve25519_dalek::scalar::Scalar;
use rand_core::RngCore;
use rand_core::CryptoRng;
/// The length of a curve25519 EdDSA `SecretKey`, in bytes.
pub const SECRET_KEY_LENGTH: usize = 32;
/// An EdDSA secret key.
/// A DH ephemeral key.
#[repr(C)]
#[derive(Default)] // we derive Default in order to use the clear() method in Drop
pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]);
pub struct Ephemeral(pub (crate) Scalar);
impl Debug for SecretKey {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "SecretKey: {:?}", &self.0[..])
}
}
/// Overwrite secret key material with null bytes when it goes out of scope.
impl Drop for SecretKey {
/// Overwrite ephemeral key material with null bytes when it goes out of scope.
impl Drop for Ephemeral {
fn drop(&mut self) {
self.0.clear();
}
}
impl SecretKey {
/// Convert this secret key to a byte array.
/// Multiply this `Ephemeral` key by a `MontgomeryPoint`.
impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Ephemeral {
type Output = Ephemeral;
fn mul(self, point: &'b MontgomeryPoint) -> Ephemeral {
Ephemeral(Scalar::from_bits((point * self.to_bytes()).to_bytes()))
}
}
impl Ephemeral {
/// Convert this `Ephemeral` key to a `Scalar`.
#[inline]
pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] {
pub fn to_bytes(&self) -> Scalar {
self.0
}
/// View this secret key as a byte array.
/// View this `Ephemeral` key as a `Scalar`.
#[inline]
pub fn as_bytes<'a>(&'a self) -> &'a [u8; SECRET_KEY_LENGTH] {
pub fn as_bytes<'a>(&'a self) -> &'a Scalar {
&self.0
}
/// Generate an x25519 secret key.
pub fn generate<T>(csprng: &mut T) -> SecretKey
/// Utility function to make it easier to call `x25519()` with
/// an ephemeral secret key and montegomery point as input and
/// a shared secret as the output.
pub fn diffie_hellman(&self, their_public: &MontgomeryPoint) -> SharedSecret {
SharedSecret(x25519(self.as_bytes(), &MontgomeryPoint(*their_public.as_bytes())))
}
/// Generate an x25519 `Ephemeral` secret key.
pub fn generate_secret<T>(csprng: &mut T) -> Self
where T: RngCore + CryptoRng
{
let mut sk: SecretKey = SecretKey([0u8; 32]);
let mut bytes = [0u8; 32];
csprng.fill_bytes(&mut sk.0);
csprng.fill_bytes(&mut bytes);
sk
Ephemeral(decode_scalar(&bytes))
}
/// Given an x25519 `Ephemeral` secret key, compute its corresponding public key.
pub fn generate_public(&self) -> MontgomeryPoint {
(self.as_bytes() * &ED25519_BASEPOINT_TABLE).to_montgomery()
}
}
#[repr(C)]
/// A DH SharedSecret
pub struct SharedSecret(pub (crate) MontgomeryPoint);
/// Overwrite shared secret material with null bytes when it goes out of scope.
impl Drop for SharedSecret {
fn drop(&mut self) {
let bytes: &mut [u8; 32] = unsafe {
mem::transmute::<&mut MontgomeryPoint, &mut [u8; 32]>
(&mut self.0)
};
bytes.clear();
}
}
/// "Decode" a scalar from a 32-byte array.
///
/// By "decode" here, what is really meant is applying key clamping by twiddling
@ -87,11 +116,6 @@ fn decode_scalar(scalar: &[u8; 32]) -> Scalar {
Scalar::from_bits(s)
}
/// Given an x25519 secret key, compute its corresponding public key.
pub fn generate_public(secret: &SecretKey) -> MontgomeryPoint {
(&decode_scalar(secret.as_bytes()) * &ED25519_BASEPOINT_TABLE).to_montgomery()
}
/// The x25519 function, as specified in RFC7748.
pub fn x25519(scalar: &Scalar, point: &MontgomeryPoint) -> MontgomeryPoint {
let k: Scalar = decode_scalar(scalar.as_bytes());
@ -99,13 +123,6 @@ pub fn x25519(scalar: &Scalar, point: &MontgomeryPoint) -> MontgomeryPoint {
(k * point)
}
/// Utility function to make it easier to call `x25519()` with byte arrays as
/// inputs and outputs.
pub fn diffie_hellman(my_secret: &SecretKey, their_public: &[u8; 32]) -> [u8; 32] {
x25519(&decode_scalar(my_secret.as_bytes()), &MontgomeryPoint(*their_public)).to_bytes()
}
#[cfg(test)]
mod test {
use super::*;