1use std::fmt;
4
5use ed25519_dalek::{
6 PUBLIC_KEY_LENGTH, SecretKey, Signer, SigningKey, Verifier as _,
7 VerifyingKey as Ed25519VerifyingKey, ed25519::Signature as Ed25519Signature,
8 pkcs8::ALGORITHM_OID,
9};
10use pkcs8::{
11 DecodePrivateKey, EncodePrivateKey, ObjectIdentifier, PrivateKeyInfo, der::zeroize::Zeroizing,
12};
13use rand::TryCryptoRng;
14use ruma_common::{SigningKeyAlgorithm, SigningKeyId};
15use thiserror::Error;
16
17use crate::{KeyPair, Signature, verify::Verifier};
18
19#[cfg(feature = "ring-compat")]
20mod compat;
21
22pub struct Ed25519KeyPair {
24 signing_key: SigningKey,
25 version: String,
27}
28
29impl Ed25519KeyPair {
30 pub fn new(
32 oid: ObjectIdentifier,
33 privkey: &[u8],
34 pubkey: Option<&[u8]>,
35 version: String,
36 ) -> Result<Self, Ed25519KeyPairParseError> {
37 if oid != ALGORITHM_OID {
38 return Err(Ed25519KeyPairParseError::InvalidOid {
39 expected: ALGORITHM_OID,
40 found: oid,
41 });
42 }
43
44 let secret_key = Self::correct_privkey_from_octolet(privkey)?;
45 let signing_key = SigningKey::from_bytes(secret_key);
46
47 if let Some(oak_key) = pubkey {
48 let verifying_key = signing_key.verifying_key();
50
51 if oak_key != verifying_key.as_bytes() {
52 return Err(Ed25519KeyPairParseError::PublicKeyMismatch {
53 derived: verifying_key.as_bytes().to_vec(),
54 parsed: oak_key.to_owned(),
55 });
56 }
57 }
58
59 Ok(Self { signing_key, version })
60 }
61
62 pub fn from_der(document: &[u8], version: String) -> Result<Self, Ed25519KeyPairParseError> {
81 #[cfg(feature = "ring-compat")]
82 use self::compat::CompatibleDocument;
83
84 let signing_key;
85
86 #[cfg(feature = "ring-compat")]
87 {
88 signing_key = match CompatibleDocument::from_bytes(document) {
89 CompatibleDocument::WellFormed(bytes) => SigningKey::from_pkcs8_der(bytes)?,
90 CompatibleDocument::CleanedFromRing(vec) => SigningKey::from_pkcs8_der(&vec)?,
91 }
92 }
93 #[cfg(not(feature = "ring-compat"))]
94 {
95 signing_key = SigningKey::from_pkcs8_der(document)?;
96 }
97
98 Ok(Self { signing_key, version })
99 }
100
101 pub fn from_pkcs8_oak(
103 oak: PrivateKeyInfo<'_>,
104 version: String,
105 ) -> Result<Self, Ed25519KeyPairParseError> {
106 Self::new(oak.algorithm.oid, oak.private_key, oak.public_key, version)
107 }
108
109 pub fn from_pkcs8_pki(
111 oak: PrivateKeyInfo<'_>,
112 version: String,
113 ) -> Result<Self, Ed25519KeyPairParseError> {
114 Self::new(oak.algorithm.oid, oak.private_key, None, version)
115 }
116
117 fn correct_privkey_from_octolet(key: &[u8]) -> Result<&SecretKey, Ed25519KeyPairParseError> {
122 if key.len() == 34 && key[..2] == [0x04, 0x20] {
123 Ok(key[2..].try_into().unwrap())
124 } else {
125 key.try_into().map_err(|_| Ed25519KeyPairParseError::InvalidSecretKeyLength {
126 expected: ed25519_dalek::SECRET_KEY_LENGTH,
127 found: key.len(),
128 })
129 }
130 }
131
132 pub fn generate() -> Zeroizing<Vec<u8>> {
142 let signing_key = generate_signing_key(&mut rand::rngs::SysRng).unwrap();
143 signing_key.to_pkcs8_der().unwrap().to_bytes()
144 }
145
146 pub fn version(&self) -> &str {
148 &self.version
149 }
150
151 pub fn public_key(&self) -> [u8; PUBLIC_KEY_LENGTH] {
153 self.signing_key.verifying_key().to_bytes()
154 }
155}
156
157fn generate_signing_key<R: TryCryptoRng + ?Sized>(csprng: &mut R) -> Result<SigningKey, R::Error> {
160 let mut secret = SecretKey::default();
161 csprng.try_fill_bytes(&mut secret)?;
162 Ok(SigningKey::from_bytes(&secret))
163}
164
165impl KeyPair for Ed25519KeyPair {
166 fn sign(&self, message: &[u8]) -> Signature {
167 Signature {
168 key_id: SigningKeyId::from_parts(
169 SigningKeyAlgorithm::Ed25519,
170 self.version.as_str().into(),
171 ),
172 signature: self.signing_key.sign(message).to_bytes().to_vec(),
173 }
174 }
175}
176
177impl fmt::Debug for Ed25519KeyPair {
178 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
179 formatter
180 .debug_struct("Ed25519KeyPair")
181 .field("verifying_key", &self.signing_key.verifying_key().as_bytes())
182 .field("version", &self.version)
183 .finish()
184 }
185}
186
187#[derive(Debug, Error)]
189#[non_exhaustive]
190pub enum Ed25519KeyPairParseError {
191 #[error("algorithm OID does not match ed25519 algorithm: expected {expected}, found {found}")]
195 InvalidOid {
196 expected: ObjectIdentifier,
198
199 found: ObjectIdentifier,
201 },
202
203 #[error("invalid ed25519 secret key length: expected {expected}, found {found}")]
205 InvalidSecretKeyLength {
206 expected: usize,
208
209 found: usize,
211 },
212
213 #[error("PKCS#8 Document public key does not match public key derived from private key: derived {0:X?} (len {}), parsed {1:X?} (len {})", .derived.len(), .parsed.len())]
216 PublicKeyMismatch {
217 derived: Vec<u8>,
219
220 parsed: Vec<u8>,
222 },
223
224 #[error("invalid PKCS#8 document: {0}")]
226 Pkcs8(#[from] pkcs8::Error),
227}
228
229#[derive(Debug, Default)]
231pub(crate) struct Ed25519Verifier;
232
233impl Verifier for Ed25519Verifier {
234 type Error = Ed25519VerificationError;
235
236 fn verify_json(
237 &self,
238 public_key: &[u8],
239 signature: &[u8],
240 message: &[u8],
241 ) -> Result<(), Self::Error> {
242 Ed25519VerifyingKey::try_from(public_key)
243 .map_err(Ed25519VerificationError::InvalidPublicKey)?
244 .verify(
245 message,
246 &Ed25519Signature::from_bytes(&signature.try_into().map_err(|_| {
247 Ed25519VerificationError::InvalidSignatureLength {
248 expected: Ed25519Signature::BYTE_SIZE,
249 found: signature.len(),
250 }
251 })?),
252 )
253 .map_err(Ed25519VerificationError::SignatureVerification)
254 }
255}
256
257#[derive(Debug, Error)]
259#[non_exhaustive]
260pub enum Ed25519VerificationError {
261 #[error("Invalid ed25519 public key: {0}")]
263 InvalidPublicKey(#[source] ed25519_dalek::SignatureError),
264
265 #[error("Invalid ed25519 signature length: expected {expected}, found {found}")]
267 InvalidSignatureLength {
268 expected: usize,
270
271 found: usize,
273 },
274
275 #[error("ed25519 signature verification failed: {0}")]
277 SignatureVerification(#[source] ed25519_dalek::SignatureError),
278}
279
280#[cfg(test)]
281mod tests {
282 use super::Ed25519KeyPair;
283
284 const WELL_FORMED_DOC: &[u8] = &[
285 0x30, 0x72, 0x02, 0x01, 0x01, 0x30, 0x05, 0x06, 0x03, 0x2B, 0x65, 0x70, 0x04, 0x22, 0x04,
286 0x20, 0xD4, 0xEE, 0x72, 0xDB, 0xF9, 0x13, 0x58, 0x4A, 0xD5, 0xB6, 0xD8, 0xF1, 0xF7, 0x69,
287 0xF8, 0xAD, 0x3A, 0xFE, 0x7C, 0x28, 0xCB, 0xF1, 0xD4, 0xFB, 0xE0, 0x97, 0xA8, 0x8F, 0x44,
288 0x75, 0x58, 0x42, 0xA0, 0x1F, 0x30, 0x1D, 0x06, 0x0A, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
289 0x01, 0x09, 0x09, 0x14, 0x31, 0x0F, 0x0C, 0x0D, 0x43, 0x75, 0x72, 0x64, 0x6C, 0x65, 0x20,
290 0x43, 0x68, 0x61, 0x69, 0x72, 0x73, 0x81, 0x21, 0x00, 0x19, 0xBF, 0x44, 0x09, 0x69, 0x84,
291 0xCD, 0xFE, 0x85, 0x41, 0xBA, 0xC1, 0x67, 0xDC, 0x3B, 0x96, 0xC8, 0x50, 0x86, 0xAA, 0x30,
292 0xB6, 0xB6, 0xCB, 0x0C, 0x5C, 0x38, 0xAD, 0x70, 0x31, 0x66, 0xE1,
293 ];
294
295 const WELL_FORMED_PUBKEY: &[u8] = &[
296 0x19, 0xBF, 0x44, 0x09, 0x69, 0x84, 0xCD, 0xFE, 0x85, 0x41, 0xBA, 0xC1, 0x67, 0xDC, 0x3B,
297 0x96, 0xC8, 0x50, 0x86, 0xAA, 0x30, 0xB6, 0xB6, 0xCB, 0x0C, 0x5C, 0x38, 0xAD, 0x70, 0x31,
298 0x66, 0xE1,
299 ];
300
301 #[test]
302 fn generate_key() {
303 Ed25519KeyPair::generate();
305 }
306
307 #[test]
308 fn well_formed_key() {
309 let keypair = Ed25519KeyPair::from_der(WELL_FORMED_DOC, "".to_owned()).unwrap();
310
311 assert_eq!(keypair.public_key(), WELL_FORMED_PUBKEY);
312 }
313
314 #[cfg(feature = "ring-compat")]
315 mod ring_compat {
316 use super::Ed25519KeyPair;
317
318 const RING_DOC: &[u8] = &[
319 0x30, 0x53, 0x02, 0x01, 0x01, 0x30, 0x05, 0x06, 0x03, 0x2B, 0x65, 0x70, 0x04, 0x22,
320 0x04, 0x20, 0x61, 0x9E, 0xD8, 0x25, 0xA6, 0x1D, 0x32, 0x29, 0xD7, 0xD8, 0x22, 0x03,
321 0xC6, 0x0E, 0x37, 0x48, 0xE9, 0xC9, 0x11, 0x96, 0x3B, 0x03, 0x15, 0x94, 0x19, 0x3A,
322 0x86, 0xEC, 0xE6, 0x2D, 0x73, 0xC0, 0xA1, 0x23, 0x03, 0x21, 0x00, 0x3D, 0xA6, 0xC8,
323 0xD1, 0x76, 0x2F, 0xD6, 0x49, 0xB8, 0x4F, 0xF6, 0xC6, 0x1D, 0x04, 0xEA, 0x4A, 0x70,
324 0xA8, 0xC9, 0xF0, 0x8F, 0x96, 0x7F, 0x6B, 0xD7, 0xDA, 0xE5, 0x2E, 0x88, 0x8D, 0xBA,
325 0x3E,
326 ];
327
328 const RING_PUBKEY: &[u8] = &[
329 0x3D, 0xA6, 0xC8, 0xD1, 0x76, 0x2F, 0xD6, 0x49, 0xB8, 0x4F, 0xF6, 0xC6, 0x1D, 0x04,
330 0xEA, 0x4A, 0x70, 0xA8, 0xC9, 0xF0, 0x8F, 0x96, 0x7F, 0x6B, 0xD7, 0xDA, 0xE5, 0x2E,
331 0x88, 0x8D, 0xBA, 0x3E,
332 ];
333
334 #[test]
335 fn ring_key() {
336 let keypair = Ed25519KeyPair::from_der(RING_DOC, "".to_owned()).unwrap();
337
338 assert_eq!(keypair.public_key(), RING_PUBKEY);
339 }
340 }
341}