Initial commit.

This commit is contained in:
Isis Lovecruft 2017-09-14 00:25:34 +00:00
commit 3702a7c598
Failed to extract signature
9 changed files with 531 additions and 0 deletions

14
.gitignore vendored Normal file
View file

@ -0,0 +1,14 @@
target/
**/*.rs.bk
Cargo.lock
.cargo
*~
\#*
.\#*
*.swp
*.orig
*.bak
*.s

19
.travis.yml Normal file
View file

@ -0,0 +1,19 @@
language: rust
rust:
- nightly
env:
- TEST_COMMAND=test EXTRA_FLAGS='' FEATURES=''
- TEST_COMMAND=bench EXTRA_FLAGS='' FEATURES='bench'
- TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='nightly'
matrix:
include:
- rust: stable
env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std'
- rust: beta
env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std'
script:
- cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS

28
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,28 @@
# Contributing to curve25519-dalek
If you have questions or comments, please feel free to email the
authors.
For feature requests, suggestions, and bug reports, please open an issue on
[our Github](https://github.com/isislovecruft/x25519-dalek). (Or, send us
an email if you're opposed to using Github for whatever reason.)
Patches are welcomed as pull requests on
[our Github](https://github.com/isislovecruft/x25519-dalek), as well as by
email (preferably sent to all of the authors listed in `Cargo.toml`).
All issues on curve25519-dalek are mentored, if you want help with a bug just
ask @isislovecruft.
Some issues are easier than others. The `easy` label can be used to find the
easy issues. If you want to work on an issue, please leave a comment so that we
can assign it to you!
# Code of Conduct
We follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html),
with the following additional clauses:
* We respect the rights to privacy and anonymity for contributors and people in
the community. If someone wishes to contribute under a pseudonym different to
their primary identity, that wish is to be respected by all contributors.

32
Cargo.toml Normal file
View file

@ -0,0 +1,32 @@
[package]
name = "x25519-dalek"
version = "0.0.0"
authors = ["Isis Lovecruft <isis@patternsinthevoid.net>"]
readme = "README.md"
license = "BSD-3-Clause"
repository = "https://github.com/isislovecruft/x25519-dalek"
documentation = "https://docs.rs/x25519-dalek"
categories = ["cryptography", "no-std"]
keywords = ["cryptography", "curve25519", "key-exchange", "x25519", "diffie-hellman"]
description = "X25519 elliptic curve Diffie-Hellman key exchange in pure-Rust, using curve25519-dalek."
exclude = [
".gitignore",
".travis.yml",
"CONTRIBUTING.md",
]
[badges]
travis-ci = { repository = "isislovecruft/x25519-dalek", branch = "master"}
[dependencies.curve25519-dalek]
version = "^0.12"
[dependencies.rand]
optional = true
version = "^0.3"
[features]
bench = []
default = ["std", "nightly"]
std = ["rand", "curve25519-dalek/std"]
nightly = ["curve25519-dalek/nightly"]

28
LICENSE Normal file
View file

@ -0,0 +1,28 @@
Copyright (c) 2017 Isis Agora Lovecruft. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

98
README.md Normal file
View file

@ -0,0 +1,98 @@
# x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![](https://travis-ci.org/isislovecruft/x25519-dalek.svg?branch=master)](https://travis-ci.org/isislovecruft/x25519-dalek)
A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key exchange,
as specified by Mike Hamburg and Adam Langley in
[RFC7748](https://tools.ietf.org/html/rfc7748), using
[curve25519-dalek](https://github.com/isislovecruft/curve25519-dalek).
## Examples
[![](https://raw.githubusercontent.com/isislovecruft/x25519-dalek/master/res/bubblesort-zines-secret-messages-cover.jpeg)](https://shop.bubblesort.io)
"Secret Messages" cover image and [zine](https://shop.bubblesort.io/products/secret-messages-zine)
copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg))
Alice and Bob are two adorable kittens who have lost their mittens, and they
wish to be able to send secret messages to each other to coordinate finding
them, otherwise—if their caretaker cat finds out—they will surely be called
naughty kittens and be given no pie!
But the two kittens are quite clever. Even though their paws are still too big
and the rest of them is 90% fuzziness, these clever kittens have been studying
up on modern public key cryptography and have learned a nifty trick called
*elliptic curve Diffie-Hellman key exchange*. With the right 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 then
`x25519_dalek::generate_public()` to produce her secret and public keys:
```rust
extern crate x25519_dalek;
extern crate rand;
use x25519_dalek::generate_secret;
use x25519_dalek::generate_public;
use rand::OsRng;
let mut alice_csprng = OsRng::new().unwrap();
let alice_secret = generate_secret(&mut alice_csprng);
let alice_public = generate_public(&alice_secret);
```
Bob does the same:
```rust
let mut bob_csprng = OsRng::new().unwrap();
let bob_secret = generate_secret(&mut bob_csprng);
let bob_public = generate_public(&bob_secret);
```
Alice meows across the room, telling `alice_public` to Bob, and Bob
loudly meows `bob_public` back to Alice. Alice now computes her
shared secret with Bob by doing:
```rust
use x25519_dalek::diffie_hellman;
let shared_secret = diffie_hellman(&alice_secret, &bob_public.as_bytes());
```
Similarly, Bob computes the same shared secret by doing:
```rust
let shared_secret = diffie_hellman(&bob_secret, &alice_public.as_bytes());
```
Voilá! Alice and Bob can now use their shared secret to encrypt their
meows, for example, by using it to generate a key and nonce for an
authenticated-encryption cipher.
# Warnings
[Our elliptic curve library](https://github.com/isislovecruft/curve25519-dalek)
(which this code uses) has received *one* formal cryptographic and security
review. It has not yet received what we would consider *sufficient* peer
review by other qualified cryptographers to be considered in any way, shape,
or form, safe.
This code matches the test vectors, as specified in
[RFC7748](https://tools.ietf.org/html/rfc7748), however:
**USE AT YOUR OWN RISK.**
# Documentation
Documentation is available [here](https://docs.rs/x25519-dalek).
# Installation
To install, add the following to your project's `Cargo.toml`:
[dependencies.x25519-dalek]
version = "^0.0"
Then, in your library or executable source, add:
extern crate x25519_dalek

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

140
src/lib.rs Normal file
View file

@ -0,0 +1,140 @@
// -*- mode: rust; -*-
//
// This file is part of x25519-dalek.
// Copyright (c) 2017 Isis Lovecruft
// See LICENSE for licensing information.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
//! x25519 Diffie-Hellman key exchange
//!
//! A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key
//! exchange as specified by Mike Hamburg and Adam Langley in
//! [RFC7748](https://tools.ietf.org/html/rfc7748).
//!
//! # Examples
//!
//! [![](https://raw.githubusercontent.com/isislovecruft/x25519-dalek/master/res/bubblesort-zines-secret-messages-cover.jpeg)](https://shop.bubblesort.io)
//!
//! "Secret Messages" cover image and [zine](https://shop.bubblesort.io/products/secret-messages-zine)
//! copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg))
//!
//! Alice and Bob are two adorable kittens who have lost their mittens, and they
//! wish to be able to send secret messages to each other to coordinate finding
//! them, otherwise—if their caretaker cat finds out—they will surely be called
//! naughty kittens and be given no pie!
//!
//! But the two kittens are quite clever. Even though their paws are still too
//! big and the rest of them is 90% fuzziness, these clever kittens have been
//! studying up on modern public key cryptography and have learned a nifty trick
//! called *elliptic curve Diffie-Hellman key exchange*. With the right
//! 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:
//!
//! ```
//! extern crate x25519_dalek;
//! extern crate rand;
//!
//! # fn main() {
//! use x25519_dalek::generate_secret;
//! use x25519_dalek::generate_public;
//! use rand::OsRng;
//!
//! let mut alice_csprng = OsRng::new().unwrap();
//! let alice_secret = generate_secret(&mut alice_csprng);
//! let alice_public = generate_public(&alice_secret);
//! # }
//! ```
//!
//! Bob does the same:
//!
//! ```
//! # extern crate x25519_dalek;
//! # extern crate rand;
//! #
//! # fn main() {
//! # use x25519_dalek::generate_secret;
//! # use x25519_dalek::generate_public;
//! # use rand::OsRng;
//! #
//! let mut bob_csprng = OsRng::new().unwrap();
//! let bob_secret = generate_secret(&mut bob_csprng);
//! let bob_public = generate_public(&bob_secret);
//! # }
//! ```
//!
//! Alice meows across the room, telling `alice_public` to Bob, and Bob
//! loudly meows `bob_public` back to Alice. Alice now computes her
//! shared secret with Bob by doing:
//!
//! ```
//! # extern crate x25519_dalek;
//! # extern crate rand;
//! #
//! # fn main() {
//! # use x25519_dalek::generate_secret;
//! # use x25519_dalek::generate_public;
//! # use rand::OsRng;
//! #
//! # let mut alice_csprng = OsRng::new().unwrap();
//! # let alice_secret = generate_secret(&mut alice_csprng);
//! # let alice_public = generate_public(&alice_secret);
//! #
//! # let mut bob_csprng = OsRng::new().unwrap();
//! # let bob_secret = generate_secret(&mut bob_csprng);
//! # let bob_public = generate_public(&bob_secret);
//! #
//! use x25519_dalek::diffie_hellman;
//!
//! let shared_secret = diffie_hellman(&alice_secret, &bob_public.as_bytes());
//! # }
//! ```
//!
//! Similarly, Bob computes the same shared secret by doing:
//!
//! ```
//! # extern crate x25519_dalek;
//! # extern crate rand;
//! #
//! # fn main() {
//! # use x25519_dalek::diffie_hellman;
//! # use x25519_dalek::generate_secret;
//! # use x25519_dalek::generate_public;
//! # use rand::OsRng;
//! #
//! # let mut alice_csprng = OsRng::new().unwrap();
//! # let alice_secret = generate_secret(&mut alice_csprng);
//! # let alice_public = generate_public(&alice_secret);
//! #
//! # let mut bob_csprng = OsRng::new().unwrap();
//! # let bob_secret = generate_secret(&mut bob_csprng);
//! # let bob_public = generate_public(&bob_secret);
//! #
//! let shared_secret = diffie_hellman(&bob_secret, &alice_public.as_bytes());
//! # }
//! ```
//!
//! Voilá! Alice and Bob can now use their shared secret to encrypt their
//! meows, for example, by using it to generate a key and nonce for an
//! authenticated-encryption cipher.
#![no_std]
#![cfg_attr(feature = "bench", feature(test))]
#![deny(missing_docs)]
extern crate curve25519_dalek;
#[cfg(feature = "std")]
extern crate rand;
#[cfg(all(test, feature = "bench"))]
extern crate test;
mod x25519;
#[allow(missing_docs)]
pub use x25519::*;

172
src/x25519.rs Normal file
View file

@ -0,0 +1,172 @@
// -*- mode: rust; -*-
//
// This file is part of x25519-dalek.
// Copyright (c) 2017 Isis Lovecruft
// See LICENSE for licensing information.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
//! x25519 Diffie-Hellman key exchange
//!
//! This implements x25519 key exchange as specified by Mike Hamburg
//! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748).
use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE;
use curve25519_dalek::montgomery::CompressedMontgomeryU;
use curve25519_dalek::montgomery::MontgomeryPoint;
use curve25519_dalek::scalar::Scalar;
#[cfg(feature = "std")]
use rand::Rng;
/// "Decode" a scalar from a 32-byte array.
///
/// By "decode" here, what is really meant is applying key clamping by twiddling
/// some bits.
///
/// # Returns
///
/// A `Scalar`.
fn decode_scalar(scalar: &[u8; 32]) -> Scalar {
let mut s: [u8; 32] = scalar.clone();
s[0] &= 248;
s[31] &= 127;
s[31] |= 64;
Scalar(s)
}
/// Generate an x25519 secret key.
#[cfg(feature = "std")]
pub fn generate_secret<T: Rng>(csprng: &mut T) -> [u8; 32] {
let mut bytes = [0u8; 32];
csprng.fill_bytes(&mut bytes);
bytes
}
/// Given an x25519 secret key, compute its corresponding public key.
pub fn generate_public(secret: &[u8; 32]) -> CompressedMontgomeryU {
(&decode_scalar(secret) * &ED25519_BASEPOINT_TABLE).to_montgomery().compress()
}
/// The x25519 function, as specified in RFC7748.
pub fn x25519(scalar: &Scalar, point: &CompressedMontgomeryU) -> CompressedMontgomeryU {
let k: Scalar = decode_scalar(scalar.as_bytes());
let u: MontgomeryPoint = point.decompress();
(&k * &u).compress()
}
/// Utility function to make it easier to call `x25519()` with byte arrays as
/// inputs and outputs.
pub fn diffie_hellman(my_secret: &[u8; 32], their_public: &[u8; 32]) -> [u8; 32] {
x25519(&Scalar(*my_secret), &CompressedMontgomeryU(*their_public)).to_bytes()
}
#[cfg(test)]
mod test {
use curve25519_dalek::constants::BASE_COMPRESSED_MONTGOMERY;
use super::*;
fn do_rfc7748_ladder_test1(input_scalar: &Scalar,
input_point: &CompressedMontgomeryU,
expected: &[u8; 32]) {
let result = x25519(&input_scalar, &input_point);
assert_eq!(result.0, *expected);
}
#[test]
fn rfc7748_ladder_test1_vectorset1() {
let input_scalar: Scalar = Scalar([
0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d,
0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd,
0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18,
0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4, ]);
let input_point: CompressedMontgomeryU = CompressedMontgomeryU([
0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb,
0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c,
0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b,
0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c, ]);
let expected: [u8; 32] = [
0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90,
0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f,
0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7,
0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52, ];
do_rfc7748_ladder_test1(&input_scalar, &input_point, &expected);
}
#[test]
fn rfc7748_ladder_test1_vectorset2() {
let input_scalar: Scalar = Scalar([
0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c,
0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, 0x6a, 0xf5,
0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4,
0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, 0xba, 0x0d, ]);
let input_point: CompressedMontgomeryU = CompressedMontgomeryU([
0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3,
0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, 0xae, 0x2c,
0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e,
0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x93, ]);
let expected: [u8; 32] = [
0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d,
0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, 0x73, 0xf8,
0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52,
0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, 0x79, 0x57, ];
do_rfc7748_ladder_test1(&input_scalar, &input_point, &expected);
}
#[test]
#[ignore] // Run only if you want to burn a lot of CPU doing 1,000,000 DH operations
fn rfc7748_ladder_test2() {
let mut k: Scalar = Scalar(BASE_COMPRESSED_MONTGOMERY.0);
let mut u: CompressedMontgomeryU = BASE_COMPRESSED_MONTGOMERY;
let mut result: CompressedMontgomeryU;
macro_rules! do_iterations {
($n:expr) => (
for _ in 0..$n {
result = x25519(&k, &u);
// OBVIOUS THING THAT I'M GOING TO NOTE ANYWAY BECAUSE I'VE
// SEEN PEOPLE DO THIS WITH GOLANG'S STDLIB AND YOU SURE AS
// HELL SHOULDN'T DO HORRIBLY STUPID THINGS LIKE THIS WITH
// MY LIBRARY:
//
// NEVER EVER TREAT SCALARS AS POINTS AND/OR VICE VERSA.
//
// ↓↓ DON'T DO THIS ↓↓
u = CompressedMontgomeryU(k.as_bytes().clone());
k = Scalar(result.to_bytes());
}
)
}
// After one iteration:
// 422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079
// After 1,000 iterations:
// 684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51
// After 1,000,000 iterations:
// 7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424
do_iterations!(1);
assert_eq!(k.as_bytes(), &[ 0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc,
0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, 0x27, 0x9f,
0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78,
0x3c, 0x60, 0xe8, 0x03, 0x11, 0xae, 0x30, 0x79, ]);
do_iterations!(999);
assert_eq!(k.as_bytes(), &[ 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55,
0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, 0x4d, 0x3c,
0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87,
0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51, ]);
do_iterations!(999_000);
assert_eq!(k.as_bytes(), &[ 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd,
0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, 0x5e, 0x6f,
0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf,
0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24, ]);
}
}