One of the most popular elliptic cruves is Curve 25519. With this we have a base point (\(G)\)) and then take a secret key (\(n\)) and produce a public key of \(nG\). For key exchange for ECDH, Alice generates a secret of \(a\) and produces a public key of \(A=aG\). Bob generates a secret of \(b\) and produces a public key of \(B=bG\). The shared key is then \(shared_{alice}=aB\) and which is the same as \(shared_{bob}=bA\). In the following we use Rust to determine the public key values and the shared key.
Curve 25519 and ECDH in Rust |
Test vectors
The vectors are tested against the vectors [here] and [here]:
Private= "a8abababababababababababababababababababababababababababababab6b" Public="e3712d851a0e5d79b831c5e34ab22b41a198171de209b8b8faca23a11c624859" Private="c8cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd4d" Public="b5bea823d9c9ff576091c54b7c596c0ae296884f0e150290e88455d7fba6126f" Shared="235101b705734aae8d4c2d9d0f1baf90bbb2a8c233d831a80d43815bb47ead10"
and:
Alice's private key, a: 77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a Alice's public key, X25519(a, 9): 8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a Bob's private key, b: 5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb Bob's public key, X25519(b, 9): de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f Their shared secret, K: 4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742
An outline of the Rust code is:
extern crate crypto; extern crate hex; use crypto::curve25519::{curve25519_base,curve25519}; use rustc_serialize::hex::FromHex; use std::env; fn hex_to_bytes(s: &str) -> Vec<u8> { s.from_hex().unwrap() } fn main() { let mut akey= "a8abababababababababababababababababababababababababababababab6b"; let mut bkey= "c8cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd4d"; let args: Vec<String> = env::args().collect(); if args.len() >1 { akey = args[1].as_str();} if args.len() >2 { bkey = args[2].as_str();} let mut out = vec![0; 32]; let a = hex_to_bytes(akey); let b = hex_to_bytes(bkey); // [u8; 32] let A = curve25519_base(a.as_ref()); let B = curve25519_base(b.as_ref()); println!("== Curve 25519 ==="); println!("Alice key: {}",akey); println!("Alice Public key: {:X?}",hex::encode(A.as_ref())); println!("Bob key: {}",bkey); println!("Alice Public key: {:X?}",hex::encode(B.as_ref())); let shared = curve25519(&a,&B); println!("\n== Key exchange ==="); println!("Shared key {:X?}",hex::encode(shared.as_ref())); }
Finally we simply build with:
cargo build
A sample run is:
== Curve 25519 === Alice key: 77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a Alice Public key: "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a" Bob key: 5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb Alice Public key: "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f" == Key exchange === Shared key "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
and:
== Curve 25519 === Alice key: a8abababababababababababababababababababababababababababababab6b Alice Public key: "e3712d851a0e5d79b831c5e34ab22b41a198171de209b8b8faca23a11c624859" Bob key: c8cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd4d Alice Public key: "b5bea823d9c9ff576091c54b7c596c0ae296884f0e150290e88455d7fba6126f" == Key exchange === Shared key "235101b705734aae8d4c2d9d0f1baf90bbb2a8c233d831a80d43815bb47ead10"