1use der_parser::der::*;
2use der_parser::error::BerError;
3
4use der_parser::oid::Oid;
5use der_parser::*;
6use nom::combinator::{complete, eof};
7use nom::IResult;
8
9use std::convert::{From, TryInto};
10
11use curve25519_dalek::edwards::CompressedEdwardsY;
12use curve25519_dalek::montgomery::MontgomeryPoint;
13use sha2::{Digest, Sha512};
14pub use x25519_dalek::{PublicKey, StaticSecret};
16
17use rand_core::{CryptoRng, RngCore};
18
19use std::fmt;
20
21const ED_25519_OID: Oid<'static> = oid!(1.3.101 .112);
22const X_25519_OID: Oid<'static> = oid!(1.3.101 .110);
23
24#[derive(Debug)]
27pub enum Curve25519ParserError {
28 BerError(der_parser::error::BerError),
30 PemError(pem::PemError),
32 NomError(nom::Err<der_parser::error::BerError>),
34 UnknownOid,
35 InvalidData,
36 InvalidPEMTag,
37}
38impl From<der_parser::error::BerError> for Curve25519ParserError {
39 fn from(error: der_parser::error::BerError) -> Self {
40 Curve25519ParserError::BerError(error)
41 }
42}
43
44impl From<pem::PemError> for Curve25519ParserError {
45 fn from(error: pem::PemError) -> Self {
46 Curve25519ParserError::PemError(error)
47 }
48}
49
50impl From<nom::Err<der_parser::error::BerError>> for Curve25519ParserError {
51 fn from(error: nom::Err<der_parser::error::BerError>) -> Self {
52 Curve25519ParserError::NomError(error)
53 }
54}
55
56impl fmt::Display for Curve25519ParserError {
57 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58 write!(f, "{self:?}")
60 }
61}
62
63#[derive(Debug, PartialEq)]
88struct Der25519PrivateHeader<'a> {
89 tag: DerObject<'a>,
90}
91
92#[derive(Debug, PartialEq)]
93struct Der25519PrivateStruct<'a> {
94 header: Der25519PrivateHeader<'a>,
95 data: DerObject<'a>,
96}
97
98fn parse_25519_private_header(i: &[u8]) -> IResult<&[u8], Der25519PrivateHeader, BerError> {
99 parse_der_container(|i: &[u8], hdr| {
100 if hdr.tag() != Tag::Sequence {
101 return Err(nom::Err::Error(BerError::InvalidTag));
102 }
103 let (i, tag) = parse_der_oid(i)?;
104 eof(i)?;
105 Ok((i, Der25519PrivateHeader { tag }))
106 })(i)
107}
108
109fn parse_25519_private(i: &[u8]) -> IResult<&[u8], Der25519PrivateStruct, BerError> {
110 parse_der_container(|i: &[u8], hdr| {
111 if hdr.tag() != Tag::Sequence {
112 return Err(nom::Err::Error(BerError::InvalidTag));
113 }
114 let (i, _unk) = parse_der_integer(i)?;
115 let (i, header) = complete(parse_25519_private_header)(i)?;
116 let (i, data) = parse_der_octetstring(i)?;
117 eof(i)?;
118 Ok((i, Der25519PrivateStruct { header, data }))
119 })(i)
120}
121
122const TAG_OCTETSTRING: u8 = 4;
123
124pub fn parse_openssl_25519_privkey_der(data: &[u8]) -> Result<StaticSecret, Curve25519ParserError> {
127 let (_remain, private) = parse_25519_private(data)?;
128 let data = private.data.content.as_slice()?;
129 if data.len() != 34 || data[0] != TAG_OCTETSTRING || data[1] != 32 {
132 return Err(Curve25519ParserError::InvalidData);
133 }
134 let mut key_data = [0u8; 32];
135
136 let read_oid = private.header.tag.as_oid()?;
137 if read_oid == &ED_25519_OID {
138 key_data.copy_from_slice(&Sha512::digest(&data[2..34])[0..32]);
139 } else if read_oid == &X_25519_OID {
140 key_data.copy_from_slice(&data[2..34]);
141 } else {
142 return Err(Curve25519ParserError::UnknownOid);
143 }
144 Ok(StaticSecret::from(key_data))
145}
146
147#[derive(Debug, PartialEq)]
171struct DerEd25519PublicHeader<'a> {
172 tag: DerObject<'a>,
173}
174
175#[derive(Debug, PartialEq)]
176struct DerEd25519PublicStruct<'a> {
177 header: DerEd25519PublicHeader<'a>,
178 data: DerObject<'a>,
179}
180
181fn parse_25519_public_header(i: &[u8]) -> IResult<&[u8], DerEd25519PublicHeader, BerError> {
182 parse_der_container(|i: &[u8], hdr| {
183 if hdr.tag() != Tag::Sequence {
184 return Err(nom::Err::Error(BerError::InvalidTag));
185 }
186 let (i, tag) = parse_der_oid(i)?;
187 eof(i)?;
188 Ok((i, DerEd25519PublicHeader { tag }))
189 })(i)
190}
191
192fn parse_25519_public(i: &[u8]) -> IResult<&[u8], DerEd25519PublicStruct, BerError> {
193 parse_der_container(|i: &[u8], hdr| {
194 if hdr.tag() != Tag::Sequence {
195 return Err(nom::Err::Error(BerError::InvalidTag));
196 }
197 let (i, header) = complete(parse_25519_public_header)(i)?;
198 let (i, data) = parse_der_bitstring(i)?;
199 eof(i)?;
200 Ok((i, DerEd25519PublicStruct { header, data }))
201 })(i)
202}
203
204pub fn parse_openssl_25519_pubkey_der(data: &[u8]) -> Result<PublicKey, Curve25519ParserError> {
207 let (_remain, ed25519_public) = parse_25519_public(data)?;
208 let data = ed25519_public.data.content.as_slice()?;
209 let data: [u8; 32] = data
210 .try_into()
211 .map_err(|_| Curve25519ParserError::InvalidData)?;
212 let read_oid = ed25519_public.header.tag.as_oid()?;
213 if read_oid == &ED_25519_OID {
214 CompressedEdwardsY::from_slice(&data)
215 .ok()
216 .and_then(|c| c.decompress())
217 .map(|v| PublicKey::from(v.to_montgomery().to_bytes()))
218 .ok_or(Curve25519ParserError::InvalidData)
219 } else if read_oid == &X_25519_OID {
220 Ok(PublicKey::from(MontgomeryPoint(data).to_bytes()))
221 } else {
222 Err(Curve25519ParserError::UnknownOid)
223 }
224}
225
226const PUBLIC_TAG: &[u8] = b"PUBLIC KEY";
229const PRIVATE_TAG: &[u8] = b"PRIVATE KEY";
230
231pub fn parse_openssl_25519_pubkey(data: &[u8]) -> Result<PublicKey, Curve25519ParserError> {
233 if let Ok(pem_data) = pem::parse(data) {
234 if pem_data.tag().as_bytes() != PUBLIC_TAG {
236 return Err(Curve25519ParserError::InvalidPEMTag);
237 }
238 parse_openssl_25519_pubkey_der(pem_data.contents())
239 } else {
240 parse_openssl_25519_pubkey_der(data)
242 }
243}
244
245pub fn parse_openssl_25519_privkey(data: &[u8]) -> Result<StaticSecret, Curve25519ParserError> {
247 if let Ok(pem_data) = pem::parse(data) {
248 if pem_data.tag().as_bytes() != PRIVATE_TAG {
250 return Err(Curve25519ParserError::InvalidPEMTag);
251 }
252 parse_openssl_25519_privkey_der(pem_data.contents())
253 } else {
254 parse_openssl_25519_privkey_der(data)
256 }
257}
258
259pub fn parse_openssl_25519_pubkeys_pem_many(
261 data: &[u8],
262) -> Result<Vec<PublicKey>, Curve25519ParserError> {
263 let mut output = Vec::new();
264 for pem_data in pem::parse_many(data)? {
265 if pem_data.tag().as_bytes() != PUBLIC_TAG {
266 return Err(Curve25519ParserError::InvalidPEMTag);
267 }
268 output.push(parse_openssl_25519_pubkey_der(pem_data.contents())?);
269 }
270 Ok(output)
271}
272
273const PRIV_KEY_PREFIX: &[u8] = b"\x30\x2e\x02\x01\x00\x30\x05\x06\x03\x2b\x65\x6e\x04\x22\x04\x20";
279const PUB_KEY_PREFIX: &[u8] = b"\x30\x2a\x30\x05\x06\x03\x2b\x65\x6e\x03\x21\x00";
280const PRIV_KEY_TAG: &str = "PRIVATE KEY";
281const PUB_KEY_TAG: &str = "PUBLIC KEY";
282
283pub struct KeyPair {
284 pub public_der: [u8; PUB_KEY_PREFIX.len() + 32],
285 pub private_der: [u8; PRIV_KEY_PREFIX.len() + 32],
286}
287
288impl KeyPair {
289 pub fn public_as_pem(&self) -> String {
290 let out = pem::Pem::new(PUB_KEY_TAG, self.public_der.to_vec());
291 pem::encode(&out)
292 }
293
294 pub fn private_as_pem(&self) -> String {
295 let out = pem::Pem::new(PRIV_KEY_TAG, self.private_der.to_vec());
296 pem::encode(&out)
297 }
298}
299
300pub fn generate_keypair<T>(csprng: &mut T) -> Option<KeyPair>
302where
303 T: RngCore + CryptoRng,
304{
305 let mut private = [0u8; 32];
307 csprng.fill_bytes(&mut private);
308
309 let priv_key = StaticSecret::from(private);
311 let pubkey = PublicKey::from(&priv_key);
312
313 let public = pubkey.as_bytes();
316
317 let mut private_der = [0u8; PRIV_KEY_PREFIX.len() + 32];
318 private_der[..PRIV_KEY_PREFIX.len()].copy_from_slice(PRIV_KEY_PREFIX);
319 private_der[PRIV_KEY_PREFIX.len()..].copy_from_slice(&private);
320
321 let mut public_der = [0u8; PUB_KEY_PREFIX.len() + 32];
322 public_der[..PUB_KEY_PREFIX.len()].copy_from_slice(PUB_KEY_PREFIX);
323 public_der[PUB_KEY_PREFIX.len()..].copy_from_slice(&public[..]);
324
325 Some(KeyPair {
326 public_der,
327 private_der,
328 })
329}
330
331#[cfg(test)]
332mod tests {
333 use super::*;
334 use rand::rngs::OsRng;
335 use x25519_dalek::PublicKey;
336
337 static X_DER_PRIV: &[u8] = include_bytes!("../../samples/test_x25519.der");
340 static X_DER_PUB: &[u8] = include_bytes!("../../samples/test_x25519_pub.der");
342
343 static ED_DER_PRIV: &[u8] = include_bytes!("../../samples/test_ed25519.der");
345 static ED_DER_PUB: &[u8] = include_bytes!("../../samples/test_ed25519_pub.der");
347
348 static PEM_PUB: &[u8] = include_bytes!("../../samples/test_ed25519_pub.pem");
350 static PEM_PRIV: &[u8] = include_bytes!("../../samples/test_ed25519.pem");
352
353 static PEM_PUB_MANY: &[u8] = include_bytes!("../../samples/test_25519_pub_many.pem");
355
356 #[test]
357 fn parse_and_check_ed_pubkeys_der() {
358 let priv_key = parse_openssl_25519_privkey_der(ED_DER_PRIV).unwrap();
359 let pub_key = parse_openssl_25519_pubkey_der(ED_DER_PUB).unwrap();
360 let computed_pub_key = PublicKey::from(&priv_key);
361 assert_eq!(pub_key.as_bytes().len(), 32);
362 assert_eq!(priv_key.to_bytes().len(), 32);
363 assert_eq!(computed_pub_key.as_bytes(), pub_key.as_bytes());
364 }
365
366 #[test]
367 fn parse_and_check_x_pubkeys_der() {
368 let priv_key = parse_openssl_25519_privkey_der(X_DER_PRIV).unwrap();
369 let pub_key = parse_openssl_25519_pubkey_der(X_DER_PUB).unwrap();
370 let computed_pub_key = PublicKey::from(&priv_key);
371 assert_eq!(pub_key.as_bytes().len(), 32);
372 assert_eq!(priv_key.to_bytes().len(), 32);
373 assert_eq!(computed_pub_key.as_bytes(), pub_key.as_bytes());
374 }
375
376 #[test]
377 fn parse_and_check_pubkeys_multi_format() {
378 let pub_key_pem = parse_openssl_25519_pubkey(PEM_PUB).unwrap();
379 let pub_key_der = parse_openssl_25519_pubkey(ED_DER_PUB).unwrap();
380 assert_eq!(pub_key_der.as_bytes().len(), 32);
381 assert_eq!(pub_key_der.as_bytes(), pub_key_pem.as_bytes());
382 let priv_key_pem = parse_openssl_25519_privkey(PEM_PRIV).unwrap();
383 let priv_key_der = parse_openssl_25519_privkey(ED_DER_PRIV).unwrap();
384 assert_eq!(priv_key_der.to_bytes().len(), 32);
385 assert_eq!(priv_key_der.to_bytes(), priv_key_pem.to_bytes());
386 }
387
388 #[test]
389 fn parse_many_pubkeys() {
390 let pub_keys_pem = parse_openssl_25519_pubkeys_pem_many(PEM_PUB).unwrap();
391 assert_eq!(pub_keys_pem.len(), 1);
392 let pub_key_der = parse_openssl_25519_pubkey(ED_DER_PUB).unwrap();
393 assert_eq!(pub_key_der.as_bytes().len(), 32);
394 assert_eq!(pub_key_der.as_bytes(), pub_keys_pem[0].as_bytes());
395
396 let pub_keys_pem = parse_openssl_25519_pubkeys_pem_many(PEM_PUB_MANY).unwrap();
397 assert_eq!(pub_keys_pem.len(), 3);
398 assert_eq!(pub_key_der.as_bytes(), pub_keys_pem[0].as_bytes());
399 assert_ne!(pub_key_der.as_bytes(), pub_keys_pem[1].as_bytes());
400
401 let pub_x_key_der = parse_openssl_25519_pubkey(X_DER_PUB).unwrap();
402 assert_eq!(pub_x_key_der.as_bytes(), pub_keys_pem[2].as_bytes());
403 }
404
405 #[test]
406 fn exports() {
407 let mut csprng = OsRng {};
408 let keypair = generate_keypair(&mut csprng).unwrap();
409
410 let priv_key = parse_openssl_25519_privkey_der(&keypair.private_der).unwrap();
411 let pub_key = parse_openssl_25519_pubkey_der(&keypair.public_der).unwrap();
412 let computed_pub_key = PublicKey::from(&priv_key);
413 assert_eq!(pub_key.as_bytes().len(), 32);
414 assert_eq!(priv_key.to_bytes().len(), 32);
415 assert_eq!(computed_pub_key.as_bytes(), pub_key.as_bytes());
416
417 let pub_pem_key = keypair.public_as_pem();
418 assert_eq!(
419 parse_openssl_25519_pubkey(pub_pem_key.as_bytes())
420 .unwrap()
421 .as_bytes(),
422 pub_key.as_bytes()
423 );
424 let priv_pem_key = keypair.private_as_pem();
425 assert_eq!(
426 &parse_openssl_25519_privkey(priv_pem_key.as_bytes())
427 .unwrap()
428 .to_bytes(),
429 &priv_key.to_bytes()
430 );
431 }
432}