From 6b11c19ff9d41c398caafaf4b54bceb92ce48f10 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Sun, 11 Jun 2023 23:17:29 +0800
Subject: [PATCH] more dalek

---
 Cargo.toml                         |   8 +-
 embassy/demos/common/Cargo.toml    |   3 +-
 embassy/demos/common/src/config.rs |   8 +-
 embassy/demos/picow/Cargo.lock     |  60 ++++++++++-
 embassy/demos/picow/Cargo.toml     |   4 +
 embassy/demos/picow/build.rs       |   2 +-
 embassy/demos/std/Cargo.lock       | 106 ++++++++----------
 embassy/demos/std/Cargo.toml       |   4 +
 src/kex.rs                         |   2 +-
 src/sign.rs                        | 168 ++++++++++++++++-------------
 10 files changed, 220 insertions(+), 145 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index c146d9e..52c2110 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -53,9 +53,9 @@ subtle = { version = "2.4", default-features = false }
 # 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", 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"]}
+ed25519-dalek = { version = "2.0.0-rc.2", default-features = false, features = ["zeroize", "rand_core", "hazmat"] }
+x25519-dalek = { version = "2.0.0-rc.2", default-features = false, features = ["zeroize"] }
+curve25519-dalek = { version = "4.0.0-rc.2", default-features = false, features = ["zeroize"] }
 
 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
@@ -90,3 +90,5 @@ simplelog = { version = "0.12", features = ["test"] }
 
 [patch.crates-io]
 curve25519-dalek = { path = "/home/matt/3rd/rs/crypto/curve25519-dalek" }
+x25519-dalek = { path = "/home/matt/3rd/rs/crypto/x25519-dalek" }
+ed25519-dalek = { path = "/home/matt/3rd/rs/crypto/ed25519-dalek" }
diff --git a/embassy/demos/common/Cargo.toml b/embassy/demos/common/Cargo.toml
index 01e3aa5..dab227b 100644
--- a/embassy/demos/common/Cargo.toml
+++ b/embassy/demos/common/Cargo.toml
@@ -24,8 +24,8 @@ heapless = "0.7.15"
 embedded-io = { version = "0.4", features = ["async"] }
 sha2 = { version = "0.10", default-features = false }
 hmac = { version = "0.12", default-features = false }
-# TODO: has zeroize
 bcrypt = { version = "0.14", default-features = false }
+ed25519-dalek = { version = "2.0.0-rc.2", default-features = false }
 
 defmt = { version = "0.3", optional = true }
 log = "0.4"
@@ -39,3 +39,4 @@ log = ["embassy-net/log"]
 embassy-futures = { git = "https://github.com/embassy-rs/embassy", rev = "1d34078fa11839f88dd2e47a9355c6b35755128f" }
 embassy-net = { git = "https://github.com/embassy-rs/embassy", rev = "1d34078fa11839f88dd2e47a9355c6b35755128f" }
 embassy-net-driver = { git = "https://github.com/embassy-rs/embassy", rev = "1d34078fa11839f88dd2e47a9355c6b35755128f" }
+ed25519-dalek = { path = "/home/matt/3rd/rs/crypto/ed25519-dalek" }
diff --git a/embassy/demos/common/src/config.rs b/embassy/demos/common/src/config.rs
index 034febc..0406fa5 100644
--- a/embassy/demos/common/src/config.rs
+++ b/embassy/demos/common/src/config.rs
@@ -29,7 +29,7 @@ pub const KEY_SLOTS: usize = 3;
 // Be sure to bump CURRENT_VERSION
 // if this struct changes (or encode/decode impls).
 // BUF_SIZE will probably also need updating.
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone)]
 pub struct SSHConfig {
     pub hostkey: SignKey,
 
@@ -112,7 +112,7 @@ impl SSHConfig {
 fn enc_signkey(k: &SignKey, s: &mut dyn SSHSink) -> WireResult<()> {
     // need to add a variant field if we support more key types.
     match k {
-        SignKey::Ed25519(seed) => seed.enc(s),
+        SignKey::Ed25519(k) => k.to_bytes().enc(s),
         _ => Err(WireError::UnknownVariant),
     }
 }
@@ -121,7 +121,9 @@ fn dec_signkey<'de, S>(s: &mut S) -> WireResult<SignKey>
 where
     S: SSHSource<'de>,
 {
-    Ok(SignKey::Ed25519(SSHDecode::dec(s)?))
+    let k: ed25519_dalek::SecretKey = SSHDecode::dec(s)?;
+    let k = ed25519_dalek::SigningKey::from_bytes(&k);
+    Ok(SignKey::Ed25519(k))
 }
 
 // encode Option<T> as a bool then maybe a value
diff --git a/embassy/demos/picow/Cargo.lock b/embassy/demos/picow/Cargo.lock
index 42b0367..ddd2861 100644
--- a/embassy/demos/picow/Cargo.lock
+++ b/embassy/demos/picow/Cargo.lock
@@ -348,6 +348,19 @@ dependencies = [
  "cipher",
 ]
 
+[[package]]
+name = "curve25519-dalek"
+version = "4.0.0-rc.2"
+dependencies = [
+ "cfg-if",
+ "digest",
+ "fiat-crypto",
+ "platforms",
+ "rustc_version 0.4.0",
+ "subtle",
+ "zeroize",
+]
+
 [[package]]
 name = "cyw43"
 version = "0.1.0"
@@ -511,6 +524,26 @@ dependencies = [
  "signature 1.6.4",
 ]
 
+[[package]]
+name = "ed25519"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963"
+dependencies = [
+ "signature 2.0.0",
+]
+
+[[package]]
+name = "ed25519-dalek"
+version = "2.0.0-rc.2"
+dependencies = [
+ "curve25519-dalek",
+ "ed25519 2.2.1",
+ "rand_core",
+ "sha2",
+ "zeroize",
+]
+
 [[package]]
 name = "either"
 version = "1.8.1"
@@ -840,6 +873,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "fiat-crypto"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77"
+
 [[package]]
 name = "fixed"
 version = "1.23.1"
@@ -1355,6 +1394,12 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "platforms"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630"
+
 [[package]]
 name = "poly1305"
 version = "0.8.0"
@@ -1553,7 +1598,7 @@ name = "salty"
 version = "0.2.0"
 dependencies = [
  "defmt",
- "ed25519",
+ "ed25519 1.5.3",
  "subtle",
  "zeroize",
 ]
@@ -1730,8 +1775,10 @@ dependencies = [
  "chacha20",
  "cipher",
  "ctr",
+ "curve25519-dalek",
  "defmt",
  "digest",
+ "ed25519-dalek",
  "embedded-io",
  "futures",
  "getrandom",
@@ -1747,6 +1794,7 @@ dependencies = [
  "snafu",
  "subtle",
  "sunset-sshwire-derive",
+ "x25519-dalek",
  "zeroize",
 ]
 
@@ -1756,6 +1804,7 @@ version = "0.1.0"
 dependencies = [
  "bcrypt",
  "defmt",
+ "ed25519-dalek",
  "embassy-futures",
  "embassy-net",
  "embassy-net-driver",
@@ -2185,6 +2234,15 @@ version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
 
+[[package]]
+name = "x25519-dalek"
+version = "2.0.0-rc.2"
+dependencies = [
+ "curve25519-dalek",
+ "rand_core",
+ "zeroize",
+]
+
 [[package]]
 name = "zeroize"
 version = "1.5.7"
diff --git a/embassy/demos/picow/Cargo.toml b/embassy/demos/picow/Cargo.toml
index 694ecab..b977705 100644
--- a/embassy/demos/picow/Cargo.toml
+++ b/embassy/demos/picow/Cargo.toml
@@ -94,6 +94,10 @@ embassy-net-driver = { git = "https://github.com/embassy-rs/embassy", rev = "1d3
 bcrypt = { version = "0.14", git = "https://github.com/mkj/rust-bcrypt", branch = "noalloc" }
 #bcrypt = { path = "/home/matt/3rd/rs/bcrypt" }
 
+curve25519-dalek = { path = "/home/matt/3rd/rs/crypto/curve25519-dalek" }
+x25519-dalek = { path = "/home/matt/3rd/rs/crypto/x25519-dalek" }
+ed25519-dalek = { path = "/home/matt/3rd/rs/crypto/ed25519-dalek" }
+
 [profile.dev]
 debug = 2
 debug-assertions = true
diff --git a/embassy/demos/picow/build.rs b/embassy/demos/picow/build.rs
index 7ba8277..7b19e11 100644
--- a/embassy/demos/picow/build.rs
+++ b/embassy/demos/picow/build.rs
@@ -49,5 +49,5 @@ fn git() {
         .unwrap_or("(unknown)".to_string());
 
     println!("cargo:rustc-env=GIT_REV={git_rev}");
-    println!("cargo:rerun-if-changed=.git/HEAD");
+    println!("cargo:rerun-if-changed=../../../.git/HEAD");
 }
diff --git a/embassy/demos/std/Cargo.lock b/embassy/demos/std/Cargo.lock
index 76e991d..771263c 100644
--- a/embassy/demos/std/Cargo.lock
+++ b/embassy/demos/std/Cargo.lock
@@ -151,15 +151,6 @@ 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"
@@ -273,13 +264,13 @@ dependencies = [
 
 [[package]]
 name = "curve25519-dalek"
-version = "3.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
+version = "4.0.0-rc.2"
 dependencies = [
- "byteorder",
- "digest 0.9.0",
- "rand_core 0.5.1",
+ "cfg-if",
+ "digest",
+ "fiat-crypto",
+ "platforms",
+ "rustc_version",
  "subtle",
  "zeroize",
 ]
@@ -351,22 +342,13 @@ 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 0.10.3",
+ "block-buffer",
  "crypto-common",
  "subtle",
 ]
@@ -387,14 +369,22 @@ dependencies = [
 ]
 
 [[package]]
-name = "ed25519-dalek"
-version = "1.0.1"
+name = "ed25519"
+version = "2.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
+checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963"
+dependencies = [
+ "signature 2.0.0",
+]
+
+[[package]]
+name = "ed25519-dalek"
+version = "2.0.0-rc.2"
 dependencies = [
  "curve25519-dalek",
- "ed25519",
- "sha2 0.9.9",
+ "ed25519 2.2.1",
+ "rand_core",
+ "sha2",
  "zeroize",
 ]
 
@@ -587,6 +577,12 @@ dependencies = [
  "instant",
 ]
 
+[[package]]
+name = "fiat-crypto"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77"
+
 [[package]]
 name = "fnv"
 version = "1.0.7"
@@ -763,7 +759,7 @@ version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
 dependencies = [
- "digest 0.10.6",
+ "digest",
 ]
 
 [[package]]
@@ -893,6 +889,12 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
+[[package]]
+name = "platforms"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630"
+
 [[package]]
 name = "polling"
 version = "2.5.2"
@@ -972,15 +974,9 @@ version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
- "rand_core 0.6.4",
+ "rand_core",
 ]
 
-[[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"
@@ -1021,7 +1017,7 @@ name = "salty"
 version = "0.2.0"
 dependencies = [
  "defmt",
- "ed25519",
+ "ed25519 1.5.3",
  "subtle",
  "zeroize",
 ]
@@ -1038,19 +1034,6 @@ 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"
@@ -1059,7 +1042,7 @@ checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
 dependencies = [
  "cfg-if",
  "cpufeatures",
- "digest 0.10.6",
+ "digest",
 ]
 
 [[package]]
@@ -1174,7 +1157,7 @@ dependencies = [
  "cipher",
  "ctr",
  "curve25519-dalek",
- "digest 0.10.6",
+ "digest",
  "ed25519-dalek",
  "embedded-io",
  "futures",
@@ -1184,9 +1167,9 @@ dependencies = [
  "log",
  "poly1305",
  "pretty-hex",
- "rand_core 0.6.4",
+ "rand_core",
  "salty",
- "sha2 0.10.6",
+ "sha2",
  "signature 2.0.0",
  "snafu",
  "subtle",
@@ -1200,6 +1183,7 @@ name = "sunset-demo-embassy-common"
 version = "0.1.0"
 dependencies = [
  "bcrypt",
+ "ed25519-dalek",
  "embassy-futures",
  "embassy-net",
  "embassy-net-driver",
@@ -1210,7 +1194,7 @@ dependencies = [
  "hmac",
  "log",
  "pretty-hex",
- "sha2 0.10.6",
+ "sha2",
  "sunset",
  "sunset-embassy",
  "sunset-sshwire-derive",
@@ -1235,7 +1219,7 @@ dependencies = [
  "libc",
  "log",
  "rand",
- "sha2 0.10.6",
+ "sha2",
  "static_cell",
  "sunset",
  "sunset-demo-embassy-common",
@@ -1471,12 +1455,10 @@ checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
 
 [[package]]
 name = "x25519-dalek"
-version = "1.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f"
+version = "2.0.0-rc.2"
 dependencies = [
  "curve25519-dalek",
- "rand_core 0.5.1",
+ "rand_core",
  "zeroize",
 ]
 
diff --git a/embassy/demos/std/Cargo.toml b/embassy/demos/std/Cargo.toml
index 0af5512..9b2e2dc 100644
--- a/embassy/demos/std/Cargo.toml
+++ b/embassy/demos/std/Cargo.toml
@@ -44,6 +44,10 @@ embassy-net = { git = "https://github.com/embassy-rs/embassy", rev = "1d34078fa1
 # for tuntap
 embassy-net-driver = { git = "https://github.com/embassy-rs/embassy", rev = "1d34078fa11839f88dd2e47a9355c6b35755128f" }
 
+curve25519-dalek = { path = "/home/matt/3rd/rs/crypto/curve25519-dalek" }
+x25519-dalek = { path = "/home/matt/3rd/rs/crypto/x25519-dalek" }
+ed25519-dalek = { path = "/home/matt/3rd/rs/crypto/ed25519-dalek" }
+
 [profile.dev]
 debug = 2
 debug-assertions = true
diff --git a/src/kex.rs b/src/kex.rs
index 9c49906..2becba9 100644
--- a/src/kex.rs
+++ b/src/kex.rs
@@ -694,7 +694,7 @@ impl KexCurve25519 {
         random::fill_random(s.as_mut_slice())?;
         // TODO: check that pure random bytes are OK
         let ours = x25519_dalek::EphemeralSecret::new(OsRng);
-        let pubkey = x25519_dalek::PublicKey::from(ours);
+        let pubkey = x25519_dalek::PublicKey::from(&ours);
         let pubkey = pubkey.to_bytes();
         Ok(KexCurve25519 { ours: Some(ours), pubkey })
     }
diff --git a/src/sign.rs b/src/sign.rs
index f2c1ba3..6bbdf53 100644
--- a/src/sign.rs
+++ b/src/sign.rs
@@ -1,4 +1,3 @@
-
 #[allow(unused_imports)]
 use {
     crate::error::*,
@@ -7,14 +6,15 @@ use {
 
 use core::ops::Deref;
 
-use signature::Verifier;
+use ed25519_dalek as dalek;
+use ed25519_dalek::{Signer, Verifier};
 use zeroize::ZeroizeOnDrop;
 
 use crate::*;
 use packets::ParseContext;
+use packets::{Ed25519PubKey, PubKey, Signature};
 use sshnames::*;
-use packets::{PubKey, Signature, Ed25519PubKey};
-use sshwire::{BinString, SSHEncode, Blob};
+use sshwire::{BinString, Blob, SSHEncode};
 
 use pretty_hex::PrettyHex;
 
@@ -22,10 +22,10 @@ use core::mem::discriminant;
 
 use digest::Digest;
 
-#[cfg(feature = "rsa")]
-use rsa::signature::{DigestVerifier, DigestSigner};
 #[cfg(feature = "rsa")]
 use packets::RSAPubKey;
+#[cfg(feature = "rsa")]
+use rsa::signature::{DigestSigner, DigestVerifier};
 
 // #[cfg(feature = "rsa")]
 // use rsa::{PublicKey, RsaPrivateKey, RsaPublicKey, PaddingScheme};
@@ -62,8 +62,12 @@ impl SigType {
 
     /// Returns `Ok(())` on success
     pub fn verify(
-        &self, pubkey: &PubKey, msg: &dyn SSHEncode, sig: &Signature, parse_ctx: Option<&ParseContext>) -> Result<()> {
-
+        &self,
+        pubkey: &PubKey,
+        msg: &dyn SSHEncode,
+        sig: &Signature,
+        parse_ctx: Option<&ParseContext>,
+    ) -> Result<()> {
         // Check that the signature type is known
         let sig_type = sig.sig_type().map_err(|_| Error::BadSig)?;
 
@@ -71,44 +75,50 @@ impl SigType {
         // This would also get caught by SignatureMismatch below
         // but that error message is intended for mismatch key vs sig.
         if discriminant(&sig_type) != discriminant(self) {
-            warn!("Received {:?} signature, expecting {}",
-                sig.algorithm_name(), self.algorithm_name());
-            return Err(Error::BadSig)
+            warn!(
+                "Received {:?} signature, expecting {}",
+                sig.algorithm_name(),
+                self.algorithm_name()
+            );
+            return Err(Error::BadSig);
         }
 
         match (self, pubkey, sig) {
-
             (SigType::Ed25519, PubKey::Ed25519(k), Signature::Ed25519(s)) => {
                 let k: &[u8; 32] = &k.key.0;
                 let k: salty::PublicKey = k.try_into().map_err(|_| Error::BadKey)?;
                 let s: &[u8; 64] = s.sig.0.try_into().map_err(|_| Error::BadSig)?;
                 let s: salty::Signature = s.into();
                 k.verify_parts(&s, |h| {
-                    sshwire::hash_ser(h, msg, parse_ctx).map_err(|_| salty::Error::ContextTooLong)
+                    sshwire::hash_ser(h, msg, parse_ctx)
+                        .map_err(|_| salty::Error::ContextTooLong)
                 })
                 .map_err(|_| Error::BadSig)
             }
 
             #[cfg(feature = "rsa")]
             (SigType::RSA, PubKey::RSA(k), Signature::RSA(s)) => {
-                let verifying_key = rsa::pkcs1v15::VerifyingKey::<sha2::Sha256>::new_with_prefix(k.key.clone());
+                let verifying_key =
+                    rsa::pkcs1v15::VerifyingKey::<sha2::Sha256>::new_with_prefix(
+                        k.key.clone(),
+                    );
                 let s: Box<[u8]> = s.sig.0.into();
                 let signature = s.into();
 
                 let mut h = sha2::Sha256::new();
                 sshwire::hash_ser(&mut h, msg, parse_ctx)?;
-                verifying_key.verify_digest(h, &signature)
-                .map_err(|e| {
+                verifying_key.verify_digest(h, &signature).map_err(|e| {
                     trace!("RSA signature failed: {e}");
                     Error::BadSig
                 })
             }
 
             _ => {
-                warn!("Signature \"{:?}\" doesn't match key type \"{:?}\"",
+                warn!(
+                    "Signature \"{:?}\" doesn't match key type \"{:?}\"",
                     sig.algorithm_name(),
                     pubkey.algorithm_name(),
-                    );
+                );
                 Err(Error::BadSig)
             }
         }
@@ -116,8 +126,7 @@ impl SigType {
 }
 
 pub enum OwnedSig {
-    // salty::Signature doesn't let us borrow the inner bytes,
-    // so we just store raw bytes here.
+    // just store raw bytes here.
     Ed25519([u8; 64]),
     #[cfg(feature = "rsa")]
     RSA(rsa::pkcs1v15::Signature),
@@ -151,7 +160,7 @@ impl TryFrom<Signature<'_>> for OwnedSig {
             }
             Signature::Unknown(u) => {
                 debug!("Unknown {u} signature");
-                Err(Error::UnknownMethod {kind: "signature" })
+                Err(Error::UnknownMethod { kind: "signature" })
             }
         }
     }
@@ -168,13 +177,16 @@ pub enum KeyType {
 ///
 /// This may hold the private key part locally
 /// or potentially send the signing requests to an SSH agent or other entity.
-#[derive(ZeroizeOnDrop, Clone, PartialEq)]
+// #[derive(ZeroizeOnDrop, Clone, PartialEq)]
+#[derive(ZeroizeOnDrop, Clone)]
 pub enum SignKey {
-    // 32 byte seed value is the private key
-    Ed25519([u8; 32]),
+    // TODO: we could just have the 32 byte seed here to save memory, but
+    // computing the public part may be slow.
+    #[zeroize(skip)]
+    Ed25519(dalek::SigningKey),
 
     #[zeroize(skip)]
-    AgentEd25519(salty::PublicKey),
+    AgentEd25519(dalek::VerifyingKey),
 
     #[cfg(feature = "rsa")]
     // TODO zeroize doesn't seem supported? though BigUint has Zeroize
@@ -193,42 +205,41 @@ impl SignKey {
                 if bits.unwrap_or(256) != 256 {
                     return Err(Error::msg("Bad key size"));
                 }
-                let mut seed = [0u8; 32];
-                random::fill_random(&mut seed)?;
-                Ok(Self::Ed25519(seed))
-            },
+                let k = dalek::SigningKey::generate(&mut rand_core::OsRng);
+                Ok(Self::Ed25519(k))
+            }
 
             #[cfg(feature = "rsa")]
             KeyType::RSA => {
                 let bits = bits.unwrap_or(config::RSA_DEFAULT_KEYSIZE);
                 if bits < config::RSA_MIN_KEYSIZE
                     || bits > rsa::RsaPublicKey::MAX_SIZE
-                    || (bits % 8 != 0) {
+                    || (bits % 8 != 0)
+                {
                     return Err(Error::msg("Bad key size"));
                 }
 
                 let k = rsa::RsaPrivateKey::new(&mut rand_core::OsRng, bits)
-                .map_err(|e| {
-                    debug!("RSA key generation error {e}");
-                    // RNG shouldn't fail, keysize has been checked
-                    Error::bug()
-                })?;
+                    .map_err(|e| {
+                        debug!("RSA key generation error {e}");
+                        // RNG shouldn't fail, keysize has been checked
+                        Error::bug()
+                    })?;
                 Ok(Self::RSA(k))
-            },
+            }
         }
     }
 
     pub fn pubkey(&self) -> PubKey {
         match self {
-            SignKey::Ed25519(seed) => {
-                let k = salty::Keypair::from(seed);
-                PubKey::Ed25519(Ed25519PubKey
-                { key: Blob(k.public.as_bytes().clone()) } )
-            },
-
-            SignKey::AgentEd25519(pk) => PubKey::Ed25519(Ed25519PubKey
-                { key: Blob(pk.as_bytes().clone()) } ),
+            SignKey::Ed25519(k) => {
+                let pubk = k.verifying_key().to_bytes();
+                PubKey::Ed25519(Ed25519PubKey { key: Blob(pubk) })
+            }
 
+            SignKey::AgentEd25519(pk) => {
+                PubKey::Ed25519(Ed25519PubKey { key: Blob(pk.to_bytes()) })
+            }
 
             #[cfg(feature = "rsa")]
             SignKey::RSA(k) => PubKey::RSA(RSAPubKey { key: k.deref().clone() }),
@@ -241,9 +252,7 @@ impl SignKey {
     #[cfg(feature = "openssh-key")]
     pub fn from_openssh(k: impl AsRef<[u8]>) -> Result<Self> {
         let k = ssh_key::PrivateKey::from_openssh(k)
-            .map_err(|_| {
-                Error::msg("Unsupported OpenSSH key")
-            })?;
+            .map_err(|_| Error::msg("Unsupported OpenSSH key"))?;
 
         k.try_into()
     }
@@ -251,47 +260,60 @@ impl SignKey {
     pub fn from_agent_pubkey(pk: &PubKey) -> Result<Self> {
         match pk {
             PubKey::Ed25519(k) => {
-                let k: salty::PublicKey = k.try_into().map_err(|_| Error::BadKey)?;
+                let k: dalek::VerifyingKey =
+                    k.key.0.as_slice().try_into().map_err(|_| Error::BadKey)?;
                 Ok(Self::AgentEd25519(k))
-            },
+            }
 
-            #[cfg (feature = "rsa")]
+            #[cfg(feature = "rsa")]
             PubKey::RSA(k) => Ok(Self::AgentRSA(k.key.clone())),
 
-            PubKey::Unknown(_) => {
-                Err(Error::msg("Unsupported agent key"))
-            }
+            PubKey::Unknown(_) => Err(Error::msg("Unsupported agent key")),
         }
     }
 
     /// Returns whether this `SignKey` can create a given signature type
     pub(crate) fn can_sign(&self, sig_type: SigType) -> bool {
         match self {
-            | SignKey::Ed25519(_)
-            | SignKey::AgentEd25519(_)
-            => matches!(sig_type, SigType::Ed25519),
+            SignKey::Ed25519(_) | SignKey::AgentEd25519(_) => {
+                matches!(sig_type, SigType::Ed25519)
+            }
 
             #[cfg(feature = "rsa")]
-            | SignKey::RSA(_)
-            | SignKey::AgentRSA(_)
-            => matches!(sig_type, SigType::RSA),
+            SignKey::RSA(_) | SignKey::AgentRSA(_) => {
+                matches!(sig_type, SigType::RSA)
+            }
         }
     }
 
-    pub(crate) fn sign(&self, msg: &impl SSHEncode, parse_ctx: Option<&ParseContext>) -> Result<OwnedSig> {
+    pub(crate) fn sign(
+        &self,
+        msg: &impl SSHEncode,
+        parse_ctx: Option<&ParseContext>,
+    ) -> Result<OwnedSig> {
         let sig: OwnedSig = match self {
-            SignKey::Ed25519(seed) => {
-                let k = salty::Keypair::from(seed);
-                let sig = k.sign_parts(|h| {
-                    sshwire::hash_ser(h, msg, parse_ctx).map_err(|_| salty::Error::ContextTooLong)
-                })
+            SignKey::Ed25519(k) => {
+                let exk = dalek::hazmat::ExpandedSecretKey::from_bytes(
+                    &k.to_keypair_bytes(),
+                );
+                let sig = dalek::hazmat::raw_sign_byupdate::<sha2::Sha512, _>(
+                    &exk,
+                    |h| {
+                        sshwire::hash_ser(h, msg, parse_ctx)
+                            .map_err(|_| dalek::SignatureError::new())
+                    },
+                    &k.verifying_key(),
+                )
                 .trap()?;
-                sig.into()
+                OwnedSig::Ed25519(sig.to_bytes())
             }
 
             #[cfg(feature = "rsa")]
             SignKey::RSA(k) => {
-                let signing_key = rsa::pkcs1v15::SigningKey::<sha2::Sha256>::new_with_prefix(k.clone());
+                let signing_key =
+                    rsa::pkcs1v15::SigningKey::<sha2::Sha256>::new_with_prefix(
+                        k.clone(),
+                    );
                 let mut h = sha2::Sha256::new();
                 sshwire::hash_ser(&mut h, msg, parse_ctx)?;
                 let sig = signing_key.try_sign_digest(h).map_err(|e| {
@@ -302,10 +324,9 @@ impl SignKey {
             }
 
             // callers should check for agent keys first
-            | SignKey::AgentEd25519(_) => return Error::bug_msg("agent sign"),
+            SignKey::AgentEd25519(_) => return Error::bug_msg("agent sign"),
             #[cfg(feature = "rsa")]
-            | SignKey::AgentRSA(_) => return Error::bug_msg("agent sign"),
-
+            SignKey::AgentRSA(_) => return Error::bug_msg("agent sign"),
         };
 
         // {
@@ -367,10 +388,11 @@ impl TryFrom<ssh_key::PrivateKey> for SignKey {
                     (&k.public.e).try_into().map_err(|_| Error::BadKey)?,
                     (&k.private.d).try_into().map_err(|_| Error::BadKey)?,
                     primes,
-                ).map_err(|_| Error::BadKey)?;
+                )
+                .map_err(|_| Error::BadKey)?;
                 Ok(SignKey::RSA(key))
             }
-            _ => Err(Error::NotAvailable { what: k.algorithm().as_str() })
+            _ => Err(Error::NotAvailable { what: k.algorithm().as_str() }),
         }
     }
 }
@@ -379,9 +401,9 @@ impl TryFrom<ssh_key::PrivateKey> for SignKey {
 pub(crate) mod tests {
 
     use crate::*;
-    use sshnames::SSH_NAME_ED25519;
     use packets;
     use sign::*;
+    use sshnames::SSH_NAME_ED25519;
     use sunsetlog::init_test_log;
 
     // TODO: tests for sign()/verify() and invalid signatures
-- 
GitLab