diff --git a/Cargo.lock b/Cargo.lock index c4f194a..0a68f4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -290,6 +290,32 @@ dependencies = [ "subtle", ] +[[package]] +name = "curve25519-dalek" +version = "5.0.0-pre.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335f1947f241137a14106b6f5acc5918a5ede29c9d71d3f2cb1678d5075d9fc3" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "darling" version = "0.20.11" @@ -412,11 +438,10 @@ name = "dhkem" version = "0.1.0-rc.0" source = "git+https://github.com/RustCrypto/KEMs?rev=5b84cfb1c94ef4eeecd77d3281d18833d095978b#5b84cfb1c94ef4eeecd77d3281d18833d095978b" dependencies = [ - "elliptic-curve", "hkdf", - "k256", "kem", "rand_core", + "x25519-dalek", "zeroize", ] @@ -655,6 +680,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fiat-crypto" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -1467,6 +1498,15 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustcrypto-ff" version = "0.14.0-rc.1" @@ -1545,6 +1585,7 @@ dependencies = [ "elliptic-curve", "k256", "sha2 0.11.0-rc.5", + "x25519-dalek", ] [[package]] @@ -2265,6 +2306,17 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "x25519-dalek" +version = "3.0.0-pre.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d5d6ff67acd3945b933e592bfa7143db4fcbb2f871754b6b9fbd7847fc5aea" +dependencies = [ + "curve25519-dalek", + "rand_core", + "zeroize", +] + [[package]] name = "zeroize" version = "1.8.2" diff --git a/sachy-crypto/Cargo.toml b/sachy-crypto/Cargo.toml index dab2dc9..9720716 100644 --- a/sachy-crypto/Cargo.toml +++ b/sachy-crypto/Cargo.toml @@ -13,9 +13,13 @@ alloc = ["chacha20poly1305/alloc"] [dependencies] chacha20poly1305 = { version = "=0.11.0-rc.3", default-features = false, features = ["getrandom"] } k256 = { version = "=0.14.0-rc.8", default-features = false, features = ["ecdh", "getrandom"] } +x25519-dalek = { version = "=3.0.0-pre.6", default-features = false, features = ["zeroize"] } sha2 = { version = "=0.11.0-rc.5", default-features = false, features = [] } -dhkem = { version = "0.1.0-rc.0", features = ["getrandom", "k256"] } +dhkem = { version = "0.1.0-rc.0", features = ["getrandom", "x25519"] } elliptic-curve = { version = "0.14.0-rc.28", default-features = false, features = ["ecdh"] } [dev-dependencies] -chacha20poly1305 = { version = "=0.11.0-rc.3", default-features = false, features = ["getrandom", "alloc"] } +chacha20poly1305 = { version = "=0.11.0-rc.3", default-features = false, features = [ + "getrandom", + "alloc", +] } diff --git a/sachy-crypto/src/lib.rs b/sachy-crypto/src/lib.rs index 72c8175..361b85c 100644 --- a/sachy-crypto/src/lib.rs +++ b/sachy-crypto/src/lib.rs @@ -4,21 +4,13 @@ use core::ops::BitXor; use chacha20poly1305::{AeadInOut, ChaCha20Poly1305, KeyInit, aead}; use dhkem::{ - Encapsulate, Kem, Secp256k1DecapsulationKey, Secp256k1EncapsulationKey, Secp256k1Kem, - TryDecapsulate, - kem::{Ciphertext, SharedKey}, + Encapsulate, Expander, Kem, X25519DecapsulationKey, X25519EncapsulationKey, X25519Kem, + kem::{Ciphertext, Decapsulate, Key, KeyExport, SharedKey, TryKeyInit}, }; -use elliptic_curve::{ - sec1::{FromSec1Point, ToSec1Point}, - subtle::ConstantTimeEq, -}; -use k256::Secp256k1; +use elliptic_curve::subtle::ConstantTimeEq; extern crate alloc; -pub type SharedSecret = elliptic_curve::ecdh::SharedSecret; -pub type Sec1Point = elliptic_curve::sec1::Sec1Point; - /// Error type. /// /// This type is deliberately opaque as to avoid potential side-channel @@ -40,9 +32,9 @@ impl From for ProtoError { } } -pub struct ClientHandshake(Secp256k1DecapsulationKey); +pub struct ClientHandshake(X25519DecapsulationKey); -pub struct EncapsulatedPublicKey(Secp256k1EncapsulationKey); +pub struct EncapsulatedPublicKey(X25519EncapsulationKey); /// The role of the participant, whether sending/receiving during handshake, /// and then whether sending/receiving during communication. @@ -72,24 +64,24 @@ impl BitXor for Role { } impl EncapsulatedPublicKey { - pub fn serialize(&self) -> Sec1Point { - self.0.to_sec1_point(true) + pub fn serialize(&self) -> Key { + self.0.to_bytes() } pub fn deserialize(buf: &[u8]) -> Result { Ok(Self( - Secp256k1EncapsulationKey::from_sec1_bytes(buf).map_err(|_| ProtoError)?, + X25519EncapsulationKey::new_from_slice(buf).map_err(|_| ProtoError)?, )) } - pub fn encapsulate(&self) -> (Ciphertext, SharedKey) { + pub fn encapsulate(&self) -> (Ciphertext, SharedKey) { self.0.encapsulate() } } impl ClientHandshake { pub fn send() -> (EncapsulatedPublicKey, Self) { - let (decap, encap) = Secp256k1Kem::generate_keypair(); + let (decap, encap) = X25519Kem::generate_keypair(); (EncapsulatedPublicKey(encap), Self(decap)) } @@ -97,17 +89,17 @@ impl ClientHandshake { pub fn finish(self, ciphertext: &[u8], psk: &[u8; 32]) -> Result { let shared = self .0 - .try_decapsulate_slice(ciphertext) + .decapsulate_slice(ciphertext) .map_err(|_| ProtoError)?; TransportState::init(psk, shared, Role::Sender) } } -pub struct ServerHandshake(SharedKey); +pub struct ServerHandshake(SharedKey); impl ServerHandshake { - pub fn receive(buf: &[u8]) -> Result<(Ciphertext, Self), ProtoError> { + pub fn receive(buf: &[u8]) -> Result<(Ciphertext, Self), ProtoError> { let encap = EncapsulatedPublicKey::deserialize(buf)?; let (ciphertext, sk) = encap.encapsulate(); @@ -189,17 +181,17 @@ pub struct TransportState { impl TransportState { pub fn init( psk: &[u8; 32], - shared: impl Into, + shared: SharedKey, role: Role, ) -> Result { - let noncer = shared.into(); - let kdf = noncer.extract::(Some(psk)); + let kdf = Expander::::new_labeled_hpke(psk, b"Sachy-Crypto", &shared) + .map_err(|_| ProtoError)?; let mut key = [0u8; 32]; let mut client = aead::Nonce::::default(); let mut server = aead::Nonce::::default(); - kdf.expand(b"SachY-Crypt0", &mut key) + kdf.expand(b"SecretKey012", &mut key) .map_err(|_| ProtoError)?; kdf.expand(b"NonceClient*", &mut client) .map_err(|_| ProtoError)?; @@ -354,7 +346,7 @@ mod tests { let (ek, client) = ClientHandshake::send(); // Pretend to send ek across the webz: client -> server - let (ciphertext, server) = ServerHandshake::receive(ek.serialize().as_bytes())?; + let (ciphertext, server) = ServerHandshake::receive(&ek.serialize())?; // Pretend to send ciphertext across the webz: server -> client let alice = client.finish(&ciphertext, &psk)?;