did_utils/crypto/
format.rs1use crate::{
2 crypto::{
3 ed25519::Ed25519KeyPair,
4 errors::Error as CryptoError,
5 traits::{Generate, KeyMaterial, BYTES_LENGTH_32},
6 x25519::X25519KeyPair,
7 },
8 jwk::{
9 Bytes, Jwk, Key, Parameters, Secret, {Okp, OkpCurves},
10 },
11};
12
13use multibase::Base::Base64Url;
14
15#[derive(Default)]
16pub enum PublicKeyFormat {
17 #[default]
18 Multikey,
19 Jwk,
20}
21
22impl TryFrom<Ed25519KeyPair> for Jwk {
24 type Error = CryptoError;
25
26 fn try_from(keypair: Ed25519KeyPair) -> Result<Self, Self::Error> {
36 Ok(Jwk {
37 key: Key::Okp(Okp {
38 crv: OkpCurves::Ed25519,
39 x: Bytes::from(keypair.public_key_bytes()?.to_vec()),
40 d: Some(Secret::from(keypair.private_key_bytes()?.to_vec())),
41 }),
42 prm: Parameters::default(),
43 })
44 }
45}
46
47impl TryFrom<Jwk> for Ed25519KeyPair {
49 type Error = CryptoError;
50
51 fn try_from(jwk: Jwk) -> Result<Self, Self::Error> {
61 match jwk.key {
62 Key::Okp(okp) => {
63 if okp.crv != OkpCurves::Ed25519 {
64 return Err(CryptoError::InvalidCurve);
65 }
66 match okp.d {
67 Some(secret_key) => {
68 let secret = secret_key;
69
70 let secret_key_vec = secret.to_vec();
71
72 let bytes: [u8; 32] = secret_key_vec.try_into().map_err(|_| CryptoError::InvalidSecretKey)?;
73 Ed25519KeyPair::from_secret_key(&bytes)
74 }
75 None => {
76 let public_key = okp.x;
77 let public_key_vec = public_key.to_vec();
78 Ed25519KeyPair::from_public_key(&public_key_vec.try_into().map_err(|_| CryptoError::InvalidPublicKey)?)
79 }
80 }
81 }
82 _ => Err(CryptoError::Unsupported),
83 }
84 }
85}
86
87impl TryFrom<X25519KeyPair> for Jwk {
89 type Error = CryptoError;
90
91 fn try_from(keypair: X25519KeyPair) -> Result<Self, Self::Error> {
101 Ok(Jwk {
102 key: Key::Okp(Okp {
103 crv: OkpCurves::X25519,
104 x: Bytes::from(keypair.public_key_bytes()?.to_vec()),
105 d: Some(Secret::from(keypair.private_key_bytes()?.to_vec())),
106 }),
107 prm: Parameters::default(),
108 })
109 }
110}
111
112impl TryFrom<Jwk> for X25519KeyPair {
114 type Error = CryptoError;
115
116 fn try_from(jwk: Jwk) -> Result<Self, Self::Error> {
126 match jwk.key {
127 Key::Okp(okp) => {
128 if okp.crv != OkpCurves::X25519 {
129 return Err(CryptoError::InvalidCurve);
130 }
131 match okp.d {
132 Some(secret_key) => {
133 let secret = secret_key;
134
135 let secret_key_vec = secret.to_vec();
136
137 let bytes: [u8; 32] = secret_key_vec.try_into().map_err(|_| CryptoError::InvalidSecretKey)?;
138 X25519KeyPair::from_secret_key(&bytes)
139 }
140 None => {
141 let public_key = okp.x;
142 let public_key_vec = public_key.to_vec();
143 X25519KeyPair::from_public_key(&public_key_vec.try_into().map_err(|_| CryptoError::InvalidPublicKey)?)
144 }
145 }
146 }
147 _ => Err(CryptoError::Unsupported),
148 }
149 }
150}
151
152#[allow(dead_code)]
162fn base64url_to_bytes(key: &str) -> Result<[u8; BYTES_LENGTH_32], ()> {
163 let key: Vec<u8> = Base64Url.decode(key).map_err(|_| ())?;
164 let key: [u8; BYTES_LENGTH_32] = key.try_into().map_err(|_| ())?;
165 Ok(key)
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171 use crate::crypto::{CoreSign, Generate, ECDH};
172
173 #[test]
175 fn test_conversion_ed25519_jwk() -> Result<(), CryptoError> {
176 let seed = b"TMwLj2p2qhcuVhaFAj3QkkJGhK6pdyKx";
177 let payload = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
178
179 let keypair = Ed25519KeyPair::new_with_seed(seed)?;
180 let signature = keypair.sign(payload).unwrap();
181
182 let jwk: Jwk = keypair.try_into()?;
183 let keypair: Ed25519KeyPair = jwk.try_into()?;
184 assert!(keypair.verify(payload, &signature).is_ok());
185
186 Ok(())
187 }
188
189 #[test]
191 fn test_conversion_ed25519_jwk_with_external_signature() -> Result<(), CryptoError> {
192 let jwk: Jwk = serde_json::from_str(
193 r#"{
194 "kty": "OKP",
195 "crv": "Ed25519",
196 "x": "tjOTPcs4OEMNrmn2ScYZDS-aCCbRFhJgaAmGnRsdmEo"
197 }"#,
198 )
199 .unwrap();
200
201 let payload = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
202 let signature = "2QH7Qrt8clEn4ETh9lgcGUyo26cJj1U8U0CBFQvgCWHe1dwXXXb16SzPTVNVGm-J6m6eALjWrxuJfmbApdoBAQ";
203 let signature = Base64Url.decode(signature).unwrap();
204
205 let keypair: Ed25519KeyPair = jwk.try_into()?;
206 assert!(keypair.verify(payload, &signature).is_ok());
207
208 Ok(())
209 }
210
211 #[test]
213 fn test_conversion_x25519_jwk() -> Result<(), CryptoError> {
214 let alice_seed = b"TMwLj2p2qhcuVhaFAj3QkkJGhK6pdyKx";
215 let bob_seed = b"NWB6DbnIlewWVp5jIJOSgyX8msXNPPAL";
216
217 let alice = X25519KeyPair::new_with_seed(alice_seed)?;
218 let bob = X25519KeyPair::new_with_seed(bob_seed)?;
219
220 let alice_shared_secret = alice.key_exchange(&bob);
221
222 let alice_jwk: Jwk = alice.try_into()?;
223 let alice: X25519KeyPair = alice_jwk.try_into()?;
224 let bob_jwk: Jwk = bob.try_into()?;
225 let bob: X25519KeyPair = bob_jwk.try_into()?;
226
227 let bob_shared_secret = bob.key_exchange(&alice);
228
229 assert_eq!(alice_shared_secret, bob_shared_secret);
230 Ok(())
231 }
232}