From 60cc41f9e3d8558c2e45963acaaa2ba175c77337 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Sun, 11 Jun 2023 11:20:45 +0800
Subject: [PATCH] WIP dalek

---
 Cargo.toml                     |   8 +-
 embassy/demos/picow/Cargo.lock |   2 +-
 embassy/demos/std/Cargo.lock   | 188 +++++++++++++++++++++++++++++----
 src/kex.rs                     |  17 ++-
 4 files changed, 186 insertions(+), 29 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 16ddef4..c146d9e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -51,7 +51,12 @@ cipher = { version = "0.4", features = ["zeroize"] }
 subtle = { version = "2.4", default-features = false }
 # ed25519/x25519
 # fork allows hashing by parts (sign/verify from sshwire), and zeroize
-salty = { version = "0.2", git = "https://github.com/mkj/salty", branch = "sunset" }
+# salty = { version = "0.2", git = "https://github.com/mkj/salty", branch = "sunset" }
+salty = { version = "0.2", path = "/home/matt/3rd/rs/salty" }
+ed25519-dalek = { version = "1", default-features = false }
+x25519-dalek = { version = "1", default-features = false }
+curve25519-dalek = { version = "3", default-features = false, features = [ "u32_backend"]}
+
 rsa = { version = "0.8", default-features = false, optional = true, features = ["sha2"] }
 # TODO: getrandom feature is a workaround for missing ssh-key dependency with rsa. fixed in pending 0.6
 ssh-key = { version = "0.5", default-features = false, optional = true, features = ["getrandom"] }
@@ -84,3 +89,4 @@ simplelog = { version = "0.12", features = ["test"] }
 
 
 [patch.crates-io]
+curve25519-dalek = { path = "/home/matt/3rd/rs/crypto/curve25519-dalek" }
diff --git a/embassy/demos/picow/Cargo.lock b/embassy/demos/picow/Cargo.lock
index afd5804..42b0367 100644
--- a/embassy/demos/picow/Cargo.lock
+++ b/embassy/demos/picow/Cargo.lock
@@ -1551,8 +1551,8 @@ checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
 [[package]]
 name = "salty"
 version = "0.2.0"
-source = "git+https://github.com/mkj/salty?branch=sunset#24b9b1e3bb9cca873ed63ef379c552dbe55633e3"
 dependencies = [
+ "defmt",
  "ed25519",
  "subtle",
  "zeroize",
diff --git a/embassy/demos/std/Cargo.lock b/embassy/demos/std/Cargo.lock
index a5e023f..76e991d 100644
--- a/embassy/demos/std/Cargo.lock
+++ b/embassy/demos/std/Cargo.lock
@@ -151,6 +151,15 @@ version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
+[[package]]
+name = "block-buffer"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
+dependencies = [
+ "generic-array 0.14.6",
+]
+
 [[package]]
 name = "block-buffer"
 version = "0.10.3"
@@ -262,6 +271,19 @@ dependencies = [
  "cipher",
 ]
 
+[[package]]
+name = "curve25519-dalek"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
+dependencies = [
+ "byteorder",
+ "digest 0.9.0",
+ "rand_core 0.5.1",
+ "subtle",
+ "zeroize",
+]
+
 [[package]]
 name = "darling"
 version = "0.13.4"
@@ -297,13 +319,54 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "defmt"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "956673bd3cb347512bf988d1e8d89ac9a82b64f6eec54d3c01c3529dac019882"
+dependencies = [
+ "bitflags",
+ "defmt-macros",
+]
+
+[[package]]
+name = "defmt-macros"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4abc4821bd84d3d8f49945ddb24d029be9385ed9b77c99bf2f6296847a6a9f0"
+dependencies = [
+ "defmt-parser",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "defmt-parser"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "269924c02afd7f94bc4cecbfa5c379f6ffcf9766b3408fe63d22c728654eccd0"
+dependencies = [
+ "thiserror",
+]
+
+[[package]]
+name = "digest"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
+dependencies = [
+ "generic-array 0.14.6",
+]
+
 [[package]]
 name = "digest"
 version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
 dependencies = [
- "block-buffer",
+ "block-buffer 0.10.3",
  "crypto-common",
  "subtle",
 ]
@@ -323,6 +386,18 @@ dependencies = [
  "signature 1.6.4",
 ]
 
+[[package]]
+name = "ed25519-dalek"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
+dependencies = [
+ "curve25519-dalek",
+ "ed25519",
+ "sha2 0.9.9",
+ "zeroize",
+]
+
 [[package]]
 name = "embassy-executor"
 version = "0.1.0"
@@ -342,12 +417,12 @@ dependencies = [
 [[package]]
 name = "embassy-futures"
 version = "0.1.0"
-source = "git+https://github.com/embassy-rs/embassy?rev=3e730aa8b06401003202bf9e21a9c83ec6b21b0e#3e730aa8b06401003202bf9e21a9c83ec6b21b0e"
+source = "git+https://github.com/embassy-rs/embassy?rev=1d34078fa11839f88dd2e47a9355c6b35755128f#1d34078fa11839f88dd2e47a9355c6b35755128f"
 
 [[package]]
 name = "embassy-hal-common"
 version = "0.1.0"
-source = "git+https://github.com/embassy-rs/embassy?rev=3e730aa8b06401003202bf9e21a9c83ec6b21b0e#3e730aa8b06401003202bf9e21a9c83ec6b21b0e"
+source = "git+https://github.com/embassy-rs/embassy?rev=1d34078fa11839f88dd2e47a9355c6b35755128f#1d34078fa11839f88dd2e47a9355c6b35755128f"
 dependencies = [
  "num-traits",
 ]
@@ -367,15 +442,15 @@ dependencies = [
 [[package]]
 name = "embassy-net"
 version = "0.1.0"
-source = "git+https://github.com/embassy-rs/embassy?rev=3e730aa8b06401003202bf9e21a9c83ec6b21b0e#3e730aa8b06401003202bf9e21a9c83ec6b21b0e"
+source = "git+https://github.com/embassy-rs/embassy?rev=1d34078fa11839f88dd2e47a9355c6b35755128f#1d34078fa11839f88dd2e47a9355c6b35755128f"
 dependencies = [
  "as-slice 0.2.1",
  "atomic-polyfill 1.0.1",
  "atomic-pool",
  "embassy-hal-common",
  "embassy-net-driver",
- "embassy-sync 0.2.0 (git+https://github.com/embassy-rs/embassy?rev=3e730aa8b06401003202bf9e21a9c83ec6b21b0e)",
- "embassy-time 0.1.1 (git+https://github.com/embassy-rs/embassy?rev=3e730aa8b06401003202bf9e21a9c83ec6b21b0e)",
+ "embassy-sync 0.2.0 (git+https://github.com/embassy-rs/embassy?rev=1d34078fa11839f88dd2e47a9355c6b35755128f)",
+ "embassy-time 0.1.1 (git+https://github.com/embassy-rs/embassy?rev=1d34078fa11839f88dd2e47a9355c6b35755128f)",
  "embedded-io",
  "embedded-nal-async",
  "futures",
@@ -390,7 +465,7 @@ dependencies = [
 [[package]]
 name = "embassy-net-driver"
 version = "0.1.0"
-source = "git+https://github.com/embassy-rs/embassy?rev=3e730aa8b06401003202bf9e21a9c83ec6b21b0e#3e730aa8b06401003202bf9e21a9c83ec6b21b0e"
+source = "git+https://github.com/embassy-rs/embassy?rev=1d34078fa11839f88dd2e47a9355c6b35755128f#1d34078fa11839f88dd2e47a9355c6b35755128f"
 
 [[package]]
 name = "embassy-sync"
@@ -408,7 +483,7 @@ dependencies = [
 [[package]]
 name = "embassy-sync"
 version = "0.2.0"
-source = "git+https://github.com/embassy-rs/embassy?rev=3e730aa8b06401003202bf9e21a9c83ec6b21b0e#3e730aa8b06401003202bf9e21a9c83ec6b21b0e"
+source = "git+https://github.com/embassy-rs/embassy?rev=1d34078fa11839f88dd2e47a9355c6b35755128f#1d34078fa11839f88dd2e47a9355c6b35755128f"
 dependencies = [
  "cfg-if",
  "critical-section",
@@ -435,7 +510,7 @@ dependencies = [
 [[package]]
 name = "embassy-time"
 version = "0.1.1"
-source = "git+https://github.com/embassy-rs/embassy?rev=3e730aa8b06401003202bf9e21a9c83ec6b21b0e#3e730aa8b06401003202bf9e21a9c83ec6b21b0e"
+source = "git+https://github.com/embassy-rs/embassy?rev=1d34078fa11839f88dd2e47a9355c6b35755128f#1d34078fa11839f88dd2e47a9355c6b35755128f"
 dependencies = [
  "atomic-polyfill 1.0.1",
  "cfg-if",
@@ -688,7 +763,7 @@ version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
 dependencies = [
- "digest",
+ "digest 0.10.6",
 ]
 
 [[package]]
@@ -849,6 +924,30 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5"
 
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
 [[package]]
 name = "proc-macro2"
 version = "1.0.51"
@@ -873,9 +972,15 @@ version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
- "rand_core",
+ "rand_core 0.6.4",
 ]
 
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+
 [[package]]
 name = "rand_core"
 version = "0.6.4"
@@ -914,8 +1019,8 @@ dependencies = [
 [[package]]
 name = "salty"
 version = "0.2.0"
-source = "git+https://github.com/mkj/salty?branch=sunset#24b9b1e3bb9cca873ed63ef379c552dbe55633e3"
 dependencies = [
+ "defmt",
  "ed25519",
  "subtle",
  "zeroize",
@@ -933,6 +1038,19 @@ version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
 
+[[package]]
+name = "sha2"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
+dependencies = [
+ "block-buffer 0.9.0",
+ "cfg-if",
+ "cpufeatures",
+ "digest 0.9.0",
+ "opaque-debug",
+]
+
 [[package]]
 name = "sha2"
 version = "0.10.6"
@@ -941,7 +1059,7 @@ checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
 dependencies = [
  "cfg-if",
  "cpufeatures",
- "digest",
+ "digest 0.10.6",
 ]
 
 [[package]]
@@ -1055,7 +1173,9 @@ dependencies = [
  "chacha20",
  "cipher",
  "ctr",
- "digest",
+ "curve25519-dalek",
+ "digest 0.10.6",
+ "ed25519-dalek",
  "embedded-io",
  "futures",
  "getrandom",
@@ -1064,13 +1184,14 @@ dependencies = [
  "log",
  "poly1305",
  "pretty-hex",
- "rand_core",
+ "rand_core 0.6.4",
  "salty",
- "sha2",
+ "sha2 0.10.6",
  "signature 2.0.0",
  "snafu",
  "subtle",
  "sunset-sshwire-derive",
+ "x25519-dalek",
  "zeroize",
 ]
 
@@ -1089,7 +1210,7 @@ dependencies = [
  "hmac",
  "log",
  "pretty-hex",
- "sha2",
+ "sha2 0.10.6",
  "sunset",
  "sunset-embassy",
  "sunset-sshwire-derive",
@@ -1114,7 +1235,7 @@ dependencies = [
  "libc",
  "log",
  "rand",
- "sha2",
+ "sha2 0.10.6",
  "static_cell",
  "sunset",
  "sunset-demo-embassy-common",
@@ -1173,6 +1294,26 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "thiserror"
+version = "1.0.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "typenum"
 version = "1.16.0"
@@ -1328,6 +1469,17 @@ version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
 
+[[package]]
+name = "x25519-dalek"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f"
+dependencies = [
+ "curve25519-dalek",
+ "rand_core 0.5.1",
+ "zeroize",
+]
+
 [[package]]
 name = "zeroize"
 version = "1.5.7"
diff --git a/src/kex.rs b/src/kex.rs
index 0918b84..9c49906 100644
--- a/src/kex.rs
+++ b/src/kex.rs
@@ -11,6 +11,7 @@ use core::fmt;
 use sha2::Sha256;
 use digest::Digest;
 use zeroize::{Zeroize, ZeroizeOnDrop};
+use rand_core::{RngCore, CryptoRng, OsRng};
 
 use crate::*;
 use encrypt::{Cipher, Integ, Keys};
@@ -673,8 +674,8 @@ impl KexOutput {
 #[derive(ZeroizeOnDrop)]
 pub(crate) struct KexCurve25519 {
     // Initialised in `new()`, cleared after deriving the secret
-    ours: Option<salty::agreement::SecretKey>,
-    // TODO: it would be nice to avoid having to store this separately, but seems difficult
+    ours: Option<x25519_dalek::EphemeralSecret>,
+    // pubkey is relatively expensive to compute from the secret key
     pubkey: [u8; 32],
 }
 
@@ -692,8 +693,8 @@ impl KexCurve25519 {
         let mut s = [0u8; 32];
         random::fill_random(s.as_mut_slice())?;
         // TODO: check that pure random bytes are OK
-        let ours = salty::agreement::SecretKey::from_seed(&mut s);
-        let pubkey: salty::agreement::PublicKey = (&ours).into();
+        let ours = x25519_dalek::EphemeralSecret::new(OsRng);
+        let pubkey = x25519_dalek::PublicKey::from(ours);
         let pubkey = pubkey.to_bytes();
         Ok(KexCurve25519 { ours: Some(ours), pubkey })
     }
@@ -709,12 +710,10 @@ impl KexCurve25519 {
         } else {
             return Err(Error::bug());
         };
-        let ours = kex.ours.as_mut().trap()?;
         let theirs: [u8; 32] = theirs.try_into().map_err(|_| Error::BadKex)?;
-        let theirs = theirs.try_into().map_err(|_| Error::BadKex)?;
-        let shsec = ours.agree(&theirs);
-        kex.ours = None;
-        Ok(KexOutput::new(&shsec.to_bytes(), algos, kex_hash))
+        let theirs = theirs.into();
+        let shsec = kex.ours.take().trap()?.diffie_hellman(&theirs);
+        Ok(KexOutput::new(shsec.as_bytes(), algos, kex_hash))
     }
 }