ssh_key/private/
ed25519.rs

1//! Ed25519 private keys.
2//!
3//! Edwards Digital Signature Algorithm (EdDSA) over Curve25519.
4
5use 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/// Ed25519 private key.
15// TODO(tarcieri): use `ed25519::PrivateKey`? (doesn't exist yet)
16#[derive(Clone)]
17pub struct Ed25519PrivateKey([u8; Self::BYTE_SIZE]);
18
19impl Ed25519PrivateKey {
20    /// Size of an Ed25519 private key in bytes.
21    pub const BYTE_SIZE: usize = 32;
22
23    /// Generate a random Ed25519 private key.
24    #[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    /// Parse Ed25519 private key from bytes.
32    pub fn from_bytes(bytes: &[u8; Self::BYTE_SIZE]) -> Self {
33        Self(*bytes)
34    }
35
36    /// Convert to the inner byte array.
37    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/// Ed25519 private/public keypair.
145#[derive(Clone)]
146pub struct Ed25519Keypair {
147    /// Public key.
148    pub public: Ed25519PublicKey,
149
150    /// Private key.
151    pub private: Ed25519PrivateKey,
152}
153
154impl Ed25519Keypair {
155    /// Size of an Ed25519 keypair in bytes.
156    pub const BYTE_SIZE: usize = 64;
157
158    /// Generate a random Ed25519 private keypair.
159    #[cfg(feature = "ed25519")]
160    pub fn random(rng: &mut impl CryptoRngCore) -> Self {
161        Ed25519PrivateKey::random(rng).into()
162    }
163
164    /// Expand a keypair from a 32-byte seed value.
165    #[cfg(feature = "ed25519")]
166    pub fn from_seed(seed: &[u8; Ed25519PrivateKey::BYTE_SIZE]) -> Self {
167        Ed25519PrivateKey::from_bytes(seed).into()
168    }
169
170    /// Parse Ed25519 keypair from 64-bytes which comprise the serialized
171    /// private and public keys.
172    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        // Validate the public key if possible
178        #[cfg(feature = "ed25519")]
179        if Ed25519PublicKey::from(&private) != public {
180            return Err(Error::Crypto);
181        }
182
183        Ok(Ed25519Keypair { private, public })
184    }
185
186    /// Serialize an Ed25519 keypair as bytes.
187    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        // Decode private key
214        let public = Ed25519PublicKey::decode(reader)?;
215
216        // The OpenSSH serialization of Ed25519 keys is repetitive and includes
217        // a serialization of `private_key[32] || public_key[32]` immediately
218        // following the public key.
219        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        // Ensure public key matches the one one the keypair
225        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}