ed25519_compact/
pem.rs

1#[cfg(feature = "std")]
2use ct_codecs::Encoder;
3use ct_codecs::{Base64, Decoder};
4
5use super::{Error, KeyPair, PublicKey, SecretKey, Seed};
6
7const DER_HEADER_SK: [u8; 16] = [48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32];
8
9const DER_HEADER_PK: [u8; 12] = [48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0];
10
11impl KeyPair {
12    /// Import a key pair from an OpenSSL-compatible DER file.
13    pub fn from_der(der: &[u8]) -> Result<Self, Error> {
14        if der.len() != DER_HEADER_SK.len() + Seed::BYTES || der[0..16] != DER_HEADER_SK {
15            return Err(Error::ParseError);
16        }
17        let mut seed = [0u8; Seed::BYTES];
18        seed.copy_from_slice(&der[16..]);
19        let kp = KeyPair::from_seed(Seed::new(seed));
20        Ok(kp)
21    }
22
23    /// Import a key pair from an OpenSSL-compatible PEM file.
24    pub fn from_pem(pem: &str) -> Result<Self, Error> {
25        let mut it = pem.split("-----BEGIN PRIVATE KEY-----");
26        let _ = it.next().ok_or(Error::ParseError)?;
27        let inner = it.next().ok_or(Error::ParseError)?;
28        let mut it = inner.split("-----END PRIVATE KEY-----");
29        let b64 = it.next().ok_or(Error::ParseError)?;
30        let _ = it.next().ok_or(Error::ParseError)?;
31        let mut der = [0u8; 16 + Seed::BYTES];
32        Base64::decode(&mut der, b64, Some(b"\r\n\t ")).map_err(|_| Error::ParseError)?;
33        Self::from_der(&der)
34    }
35
36    /// Export a key pair as an OpenSSL-compatible PEM file.
37    #[cfg(feature = "std")]
38    pub fn to_pem(&self) -> String {
39        format!("{}\n{}\n", self.sk.to_pem().trim(), self.pk.to_pem().trim())
40    }
41}
42
43impl SecretKey {
44    /// Import a secret key from an OpenSSL-compatible DER file.
45    pub fn from_der(der: &[u8]) -> Result<Self, Error> {
46        let kp = KeyPair::from_der(der)?;
47        Ok(kp.sk)
48    }
49
50    /// Import a secret key from an OpenSSL-compatible PEM file.
51    pub fn from_pem(pem: &str) -> Result<Self, Error> {
52        let kp = KeyPair::from_pem(pem)?;
53        Ok(kp.sk)
54    }
55
56    /// Export a secret key as an OpenSSL-compatible DER file.
57    #[cfg(feature = "std")]
58    pub fn to_der(&self) -> Vec<u8> {
59        let mut der = [0u8; 16 + Seed::BYTES];
60        der[0..16].copy_from_slice(&DER_HEADER_SK);
61        der[16..].copy_from_slice(self.seed().as_ref());
62        der.to_vec()
63    }
64
65    /// Export a secret key as an OpenSSL-compatible PEM file.
66    #[cfg(feature = "std")]
67    pub fn to_pem(&self) -> String {
68        let b64 = Base64::encode_to_string(self.to_der()).unwrap();
69        format!(
70            "-----BEGIN PRIVATE KEY-----\n{}\n-----END PRIVATE KEY-----\n",
71            b64
72        )
73    }
74}
75
76impl PublicKey {
77    /// Import a public key from an OpenSSL-compatible DER file.
78    pub fn from_der(der: &[u8]) -> Result<Self, Error> {
79        if der.len() != DER_HEADER_PK.len() + PublicKey::BYTES || der[0..12] != DER_HEADER_PK {
80            return Err(Error::ParseError);
81        }
82        let mut pk = [0u8; PublicKey::BYTES];
83        pk.copy_from_slice(&der[12..]);
84        let pk = PublicKey::new(pk);
85        Ok(pk)
86    }
87
88    /// Import a public key from an OpenSSL-compatible PEM file.
89    pub fn from_pem(pem: &str) -> Result<Self, Error> {
90        let mut it = pem.split("-----BEGIN PUBLIC KEY-----");
91        let _ = it.next().ok_or(Error::ParseError)?;
92        let inner = it.next().ok_or(Error::ParseError)?;
93        let mut it = inner.split("-----END PUBLIC KEY-----");
94        let b64 = it.next().ok_or(Error::ParseError)?;
95        let _ = it.next().ok_or(Error::ParseError)?;
96        let mut der = [0u8; 12 + PublicKey::BYTES];
97        Base64::decode(&mut der, b64, Some(b"\r\n\t ")).map_err(|_| Error::ParseError)?;
98        Self::from_der(&der)
99    }
100
101    /// Export a public key as an OpenSSL-compatible DER file.
102    #[cfg(feature = "std")]
103    pub fn to_der(&self) -> Vec<u8> {
104        let mut der = [0u8; 12 + PublicKey::BYTES];
105        der[0..12].copy_from_slice(&DER_HEADER_PK);
106        der[12..].copy_from_slice(self.as_ref());
107        der.to_vec()
108    }
109
110    /// Export a public key as an OpenSSL-compatible PEM file.
111    #[cfg(feature = "std")]
112    pub fn to_pem(&self) -> String {
113        let b64 = Base64::encode_to_string(self.to_der()).unwrap();
114        format!(
115            "-----BEGIN PUBLIC KEY-----\n{}\n-----END PUBLIC KEY-----\n",
116            b64
117        )
118    }
119}
120
121#[test]
122fn test_pem() {
123    let sk_pem = "-----BEGIN PRIVATE KEY-----
124MC4CAQAwBQYDK2VwBCIEIMXY1NUbUe/3dW2YUoKW5evsnCJPMfj60/q0RzGne3gg
125-----END PRIVATE KEY-----\n";
126    let sk = SecretKey::from_pem(sk_pem).unwrap();
127
128    let pk_pem = "-----BEGIN PUBLIC KEY-----
129MCowBQYDK2VwAyEAyrRjJfTnhMcW5igzYvPirFW5eUgMdKeClGzQhd4qw+Y=
130-----END PUBLIC KEY-----\n";
131    let pk = PublicKey::from_pem(pk_pem).unwrap();
132
133    assert_eq!(sk.public_key(), pk);
134
135    #[cfg(features = "std")]
136    {
137        let sk_pem2 = sk.to_pem();
138        let pk_pem2 = pk.to_pem();
139        assert_eq!(sk_pem, sk_pem2);
140        assert_eq!(pk_pem, pk_pem2);
141    }
142}
143
144#[test]
145fn test_der() {
146    let kp = KeyPair::generate();
147    let sk_der = kp.sk.to_der();
148    let sk2 = SecretKey::from_der(&sk_der).unwrap();
149    let pk_der = kp.pk.to_der();
150    let pk2 = PublicKey::from_der(&pk_der).unwrap();
151    assert_eq!(kp.sk, sk2);
152    assert_eq!(kp.pk, pk2);
153}