ssh_key/private/
ed25519.rs1use crate::{public::Ed25519PublicKey, Error, Result};
6use core::fmt;
7use encoding::{CheckedSum, Decode, Encode, Reader, Writer};
8use subtle::{Choice, ConstantTimeEq};
9use zeroize::{Zeroize, Zeroizing};
10
11#[cfg(feature = "rand_core")]
12use rand_core::CryptoRngCore;
13
14#[derive(Clone)]
17pub struct Ed25519PrivateKey([u8; Self::BYTE_SIZE]);
18
19impl Ed25519PrivateKey {
20 pub const BYTE_SIZE: usize = 32;
22
23 #[cfg(feature = "rand_core")]
25 pub fn random(rng: &mut impl CryptoRngCore) -> Self {
26 let mut key_bytes = [0u8; Self::BYTE_SIZE];
27 rng.fill_bytes(&mut key_bytes);
28 Self(key_bytes)
29 }
30
31 pub fn from_bytes(bytes: &[u8; Self::BYTE_SIZE]) -> Self {
33 Self(*bytes)
34 }
35
36 pub fn to_bytes(&self) -> [u8; Self::BYTE_SIZE] {
38 self.0
39 }
40}
41
42impl AsRef<[u8; Self::BYTE_SIZE]> for Ed25519PrivateKey {
43 fn as_ref(&self) -> &[u8; Self::BYTE_SIZE] {
44 &self.0
45 }
46}
47
48impl ConstantTimeEq for Ed25519PrivateKey {
49 fn ct_eq(&self, other: &Self) -> Choice {
50 self.as_ref().ct_eq(other.as_ref())
51 }
52}
53
54impl Eq for Ed25519PrivateKey {}
55
56impl PartialEq for Ed25519PrivateKey {
57 fn eq(&self, other: &Self) -> bool {
58 self.ct_eq(other).into()
59 }
60}
61
62impl TryFrom<&[u8]> for Ed25519PrivateKey {
63 type Error = Error;
64
65 fn try_from(bytes: &[u8]) -> Result<Self> {
66 Ok(Ed25519PrivateKey::from_bytes(bytes.try_into()?))
67 }
68}
69
70impl fmt::Debug for Ed25519PrivateKey {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 f.debug_struct("Ed25519PrivateKey").finish_non_exhaustive()
73 }
74}
75
76impl fmt::LowerHex for Ed25519PrivateKey {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 for byte in self.as_ref() {
79 write!(f, "{byte:02x}")?;
80 }
81 Ok(())
82 }
83}
84
85impl fmt::UpperHex for Ed25519PrivateKey {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 for byte in self.as_ref() {
88 write!(f, "{byte:02X}")?;
89 }
90 Ok(())
91 }
92}
93
94impl Drop for Ed25519PrivateKey {
95 fn drop(&mut self) {
96 self.0.zeroize();
97 }
98}
99
100#[cfg(feature = "ed25519")]
101impl From<Ed25519PrivateKey> for ed25519_dalek::SigningKey {
102 fn from(key: Ed25519PrivateKey) -> ed25519_dalek::SigningKey {
103 ed25519_dalek::SigningKey::from(&key)
104 }
105}
106
107#[cfg(feature = "ed25519")]
108impl From<&Ed25519PrivateKey> for ed25519_dalek::SigningKey {
109 fn from(key: &Ed25519PrivateKey) -> ed25519_dalek::SigningKey {
110 ed25519_dalek::SigningKey::from_bytes(key.as_ref())
111 }
112}
113
114#[cfg(feature = "ed25519")]
115impl From<ed25519_dalek::SigningKey> for Ed25519PrivateKey {
116 fn from(key: ed25519_dalek::SigningKey) -> Ed25519PrivateKey {
117 Ed25519PrivateKey::from(&key)
118 }
119}
120
121#[cfg(feature = "ed25519")]
122impl From<&ed25519_dalek::SigningKey> for Ed25519PrivateKey {
123 fn from(key: &ed25519_dalek::SigningKey) -> Ed25519PrivateKey {
124 Ed25519PrivateKey(key.to_bytes())
125 }
126}
127
128#[cfg(feature = "ed25519")]
129impl From<Ed25519PrivateKey> for Ed25519PublicKey {
130 fn from(private: Ed25519PrivateKey) -> Ed25519PublicKey {
131 Ed25519PublicKey::from(&private)
132 }
133}
134
135#[cfg(feature = "ed25519")]
136impl From<&Ed25519PrivateKey> for Ed25519PublicKey {
137 fn from(private: &Ed25519PrivateKey) -> Ed25519PublicKey {
138 ed25519_dalek::SigningKey::from(private)
139 .verifying_key()
140 .into()
141 }
142}
143
144#[derive(Clone)]
146pub struct Ed25519Keypair {
147 pub public: Ed25519PublicKey,
149
150 pub private: Ed25519PrivateKey,
152}
153
154impl Ed25519Keypair {
155 pub const BYTE_SIZE: usize = 64;
157
158 #[cfg(feature = "ed25519")]
160 pub fn random(rng: &mut impl CryptoRngCore) -> Self {
161 Ed25519PrivateKey::random(rng).into()
162 }
163
164 #[cfg(feature = "ed25519")]
166 pub fn from_seed(seed: &[u8; Ed25519PrivateKey::BYTE_SIZE]) -> Self {
167 Ed25519PrivateKey::from_bytes(seed).into()
168 }
169
170 pub fn from_bytes(bytes: &[u8; Self::BYTE_SIZE]) -> Result<Self> {
173 let (priv_bytes, pub_bytes) = bytes.split_at(Ed25519PrivateKey::BYTE_SIZE);
174 let private = Ed25519PrivateKey::try_from(priv_bytes)?;
175 let public = Ed25519PublicKey::try_from(pub_bytes)?;
176
177 #[cfg(feature = "ed25519")]
179 if Ed25519PublicKey::from(&private) != public {
180 return Err(Error::Crypto);
181 }
182
183 Ok(Ed25519Keypair { private, public })
184 }
185
186 pub fn to_bytes(&self) -> [u8; Self::BYTE_SIZE] {
188 let mut result = [0u8; Self::BYTE_SIZE];
189 result[..(Self::BYTE_SIZE / 2)].copy_from_slice(self.private.as_ref());
190 result[(Self::BYTE_SIZE / 2)..].copy_from_slice(self.public.as_ref());
191 result
192 }
193}
194
195impl ConstantTimeEq for Ed25519Keypair {
196 fn ct_eq(&self, other: &Self) -> Choice {
197 Choice::from((self.public == other.public) as u8) & self.private.ct_eq(&other.private)
198 }
199}
200
201impl Eq for Ed25519Keypair {}
202
203impl PartialEq for Ed25519Keypair {
204 fn eq(&self, other: &Self) -> bool {
205 self.ct_eq(other).into()
206 }
207}
208
209impl Decode for Ed25519Keypair {
210 type Error = Error;
211
212 fn decode(reader: &mut impl Reader) -> Result<Self> {
213 let public = Ed25519PublicKey::decode(reader)?;
215
216 let mut bytes = Zeroizing::new([0u8; Self::BYTE_SIZE]);
220 reader.read_prefixed(|reader| reader.read(&mut *bytes))?;
221
222 let keypair = Self::from_bytes(&bytes)?;
223
224 if keypair.public == public {
226 Ok(keypair)
227 } else {
228 Err(Error::Crypto)
229 }
230 }
231}
232
233impl Encode for Ed25519Keypair {
234 fn encoded_len(&self) -> encoding::Result<usize> {
235 [4, self.public.encoded_len()?, Self::BYTE_SIZE].checked_sum()
236 }
237
238 fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
239 self.public.encode(writer)?;
240 Zeroizing::new(self.to_bytes()).as_ref().encode(writer)?;
241 Ok(())
242 }
243}
244
245impl From<Ed25519Keypair> for Ed25519PublicKey {
246 fn from(keypair: Ed25519Keypair) -> Ed25519PublicKey {
247 keypair.public
248 }
249}
250
251impl From<&Ed25519Keypair> for Ed25519PublicKey {
252 fn from(keypair: &Ed25519Keypair) -> Ed25519PublicKey {
253 keypair.public
254 }
255}
256
257impl TryFrom<&[u8]> for Ed25519Keypair {
258 type Error = Error;
259
260 fn try_from(bytes: &[u8]) -> Result<Self> {
261 Ed25519Keypair::from_bytes(bytes.try_into()?)
262 }
263}
264
265impl fmt::Debug for Ed25519Keypair {
266 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267 f.debug_struct("Ed25519Keypair")
268 .field("public", &self.public)
269 .finish_non_exhaustive()
270 }
271}
272
273#[cfg(feature = "ed25519")]
274impl From<Ed25519PrivateKey> for Ed25519Keypair {
275 fn from(private: Ed25519PrivateKey) -> Ed25519Keypair {
276 let secret = ed25519_dalek::SigningKey::from(&private);
277 let public = secret.verifying_key().into();
278 Ed25519Keypair { private, public }
279 }
280}
281
282#[cfg(feature = "ed25519")]
283impl TryFrom<Ed25519Keypair> for ed25519_dalek::SigningKey {
284 type Error = Error;
285
286 fn try_from(key: Ed25519Keypair) -> Result<ed25519_dalek::SigningKey> {
287 ed25519_dalek::SigningKey::try_from(&key)
288 }
289}
290
291#[cfg(feature = "ed25519")]
292impl TryFrom<&Ed25519Keypair> for ed25519_dalek::SigningKey {
293 type Error = Error;
294
295 fn try_from(key: &Ed25519Keypair) -> Result<ed25519_dalek::SigningKey> {
296 let signing_key = ed25519_dalek::SigningKey::from(&key.private);
297 let verifying_key = ed25519_dalek::VerifyingKey::try_from(&key.public)?;
298
299 if signing_key.verifying_key() == verifying_key {
300 Ok(signing_key)
301 } else {
302 Err(Error::PublicKey)
303 }
304 }
305}
306
307#[cfg(feature = "ed25519")]
308impl From<ed25519_dalek::SigningKey> for Ed25519Keypair {
309 fn from(key: ed25519_dalek::SigningKey) -> Ed25519Keypair {
310 Ed25519Keypair::from(&key)
311 }
312}
313
314#[cfg(feature = "ed25519")]
315impl From<&ed25519_dalek::SigningKey> for Ed25519Keypair {
316 fn from(key: &ed25519_dalek::SigningKey) -> Ed25519Keypair {
317 Ed25519Keypair {
318 private: key.into(),
319 public: key.verifying_key().into(),
320 }
321 }
322}