mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
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:
parent
e93a7125d9
commit
1b64afd83d
2 changed files with 73 additions and 62 deletions
46
src/lib.rs
46
src/lib.rs
|
|
@ -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);
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
|
|
|||
Loading…
Reference in a new issue