Skip to content

Instantly share code, notes, and snippets.

@lrvick
Last active October 27, 2022 00:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lrvick/d1682c57a79ca71b5dcf85989dc58e12 to your computer and use it in GitHub Desktop.
Save lrvick/d1682c57a79ca71b5dcf85989dc58e12 to your computer and use it in GitHub Desktop.
Example of basic AES256 envelope encryption using ECDH via NIST p-256 in Rust.
[package]
name = "ecdh_p256"
version = "1.0.0"
[dependencies]
p256={version = "0.11.1", features = ["ecdh"]}
hex="0.4.3"
aes-gcm="0.10.1"
rand_chacha="0.3.1"
rand="0.8.5"
sha2="0.10.6"
[[bin]]
name="main"
path="main.rs"
extern crate p256;
extern crate aes_gcm;
extern crate rand;
extern crate rand_chacha;
extern crate sha2;
use p256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret};
use aes_gcm::{Nonce, KeyInit, Aes256Gcm};
use aes_gcm::aes::cipher::consts::U12;
use aes_gcm::aead::{Aead};
use rand::{RngCore,SeedableRng};
use rand_chacha::ChaCha20Rng;
use sha2::{Sha512,Digest};
fn main() {
// Choose a simple RNG source
let mut rng: ChaCha20Rng = ChaCha20Rng::from_entropy();
// Alice generates a random asymmetric keypair
let alice_private = EphemeralSecret::random(&mut rng);
let alice_private_ep = EncodedPoint::from(alice_private.public_key());
let alice_public = PublicKey::from_sec1_bytes(alice_private_ep.as_ref()).expect("Alice's public key invalid");
println!("\nAlice public key {:x?}",hex::encode(alice_private_ep.as_ref()));
// Bob generates a random asymmetric keypair
let bob_private = EphemeralSecret::random(&mut rng);
let bob_private_ep = EncodedPoint::from(bob_private.public_key());
let bob_public = PublicKey::from_sec1_bytes(bob_private_ep.as_ref()).expect("Bob's public key invalid");
println!("\nBob public key {:x?}",hex::encode(bob_private_ep.as_ref()));
// Alice and bob agree on a shared one-time-use number as a nonce.
let nonce_bytes_as_u32: Vec<u32> = (0..3).map(|_| rng.next_u32()).collect();
let nonce_bytes: Vec<u8> = nonce_bytes_as_u32.iter().flat_map(|x| x.to_be_bytes()).collect();
let nonce = Nonce::<U12>::from_slice(&nonce_bytes);
// Bob generates a shared secret using Alice's public key via Diffie Hellman
let bob_shared_dh = bob_private.diffie_hellman(&alice_public);
let bob_shared_bytes = bob_shared_dh.raw_secret_bytes();
let bob_shared_sha512 = Sha512::digest(&bob_shared_bytes).to_vec();
let bob_shared_secret = &bob_shared_sha512[..32];
// Bob generates a shared AES key from this shared secret with the shared IV
let bob_shared_cipher = Aes256Gcm::new_from_slice(&bob_shared_secret).unwrap();
//// Bob encrypts a secret to Alice with the shared AES key
let message = String::from("Secret message");
let encrypted_message = bob_shared_cipher.encrypt(nonce, message.as_bytes()).unwrap();
println!("\nEncrypted message: {:?}",hex::encode(&encrypted_message));
// Alice derives the same shared secret as Bob
let alice_shared_dh = alice_private.diffie_hellman(&bob_public);
let alice_shared_bytes = alice_shared_dh.raw_secret_bytes();
let alice_shared_sha512 = Sha512::digest(&alice_shared_bytes).to_vec();
let alice_shared_secret = &alice_shared_sha512[..32];
// Alice generates the same AES key as Bob from this shared secret and the shared IV
let alice_shared_cipher = Aes256Gcm::new_from_slice(&alice_shared_secret).unwrap();
// Alice decrypts Bob's message
let decrypted_message = alice_shared_cipher.decrypt(nonce, &encrypted_message[..]).unwrap();
println!("\nDecrypted message: {:?}",String::from_utf8_lossy(&decrypted_message));
}
Alice public key "046c61a6de7b51e771e689e995be8ee0a2bdf5da0a46d192acdac68c064bd3126053509b4570f9499e106044aedc1eb8380fd602294dd18f5249a64db40e862e7f"
Bob public key "04bc345ca0b9a18d6e44d8b1d538cede0173d2dafdf97393b92af218b7962331947a6406a817ab108752ee862764fddbd7383b84a91ca81bce40c9785426b71592"
Encrypted message: "95e47d6a8a3de04f380e066f8888ab3fb3f876f421e6334a7ee752fc90b3"
Decrypted message: "Secret message"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment