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