vodozemac/types/
curve25519.rs1use std::fmt::Display;
16
17use base64::decoded_len_estimate;
18use matrix_pickle::{Decode, DecodeError};
19use rand::rng;
20use serde::{Deserialize, Serialize};
21use x25519_dalek::{EphemeralSecret, PublicKey, ReusableSecret, SharedSecret, StaticSecret};
22use zeroize::Zeroize;
23
24use super::KeyError;
25use crate::utilities::{base64_decode, base64_encode};
26
27#[derive(Clone, Deserialize, Serialize)]
29#[serde(transparent)]
30pub struct Curve25519SecretKey(Box<StaticSecret>);
31
32impl Curve25519SecretKey {
33 pub fn new() -> Self {
35 let mut rng = rng();
36
37 Self(Box::new(StaticSecret::random_from_rng(&mut rng)))
38 }
39
40 pub fn from_slice(bytes: &[u8; 32]) -> Self {
42 Self(Box::new(StaticSecret::from(*bytes)))
44 }
45
46 pub fn diffie_hellman(&self, their_public_key: &Curve25519PublicKey) -> Option<SharedSecret> {
53 let shared_secret = self.0.diffie_hellman(&their_public_key.inner);
54
55 if shared_secret.was_contributory() { Some(shared_secret) } else { None }
56 }
57
58 pub fn to_bytes(&self) -> Box<[u8; 32]> {
63 let mut key = Box::new([0u8; 32]);
64 let mut bytes = self.0.to_bytes();
65 key.copy_from_slice(&bytes);
66
67 bytes.zeroize();
68
69 key
70 }
71}
72
73impl Default for Curve25519SecretKey {
74 fn default() -> Self {
75 Self::new()
76 }
77}
78
79#[derive(Serialize, Deserialize, Clone)]
80#[serde(from = "Curve25519KeypairPickle")]
81#[serde(into = "Curve25519KeypairPickle")]
82pub(crate) struct Curve25519Keypair {
83 pub secret_key: Curve25519SecretKey,
84 pub public_key: Curve25519PublicKey,
85}
86
87impl Curve25519Keypair {
88 pub fn new() -> Self {
89 let secret_key = Curve25519SecretKey::new();
90 let public_key = Curve25519PublicKey::from(&secret_key);
91
92 Self { secret_key, public_key }
93 }
94
95 pub fn from_secret_key(key: &[u8; 32]) -> Self {
96 let secret_key = Curve25519SecretKey::from_slice(key);
97 let public_key = Curve25519PublicKey::from(&secret_key);
98
99 Curve25519Keypair { secret_key, public_key }
100 }
101
102 pub const fn secret_key(&self) -> &Curve25519SecretKey {
103 &self.secret_key
104 }
105
106 pub const fn public_key(&self) -> Curve25519PublicKey {
107 self.public_key
108 }
109}
110
111#[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)]
113#[serde(transparent)]
114pub struct Curve25519PublicKey {
115 pub(crate) inner: PublicKey,
116}
117
118impl Decode for Curve25519PublicKey {
119 fn decode(reader: &mut impl std::io::Read) -> Result<Self, DecodeError> {
120 let key = <[u8; 32]>::decode(reader)?;
121
122 Ok(Curve25519PublicKey::from(key))
123 }
124}
125
126impl Curve25519PublicKey {
127 pub const LENGTH: usize = 32;
129
130 const BASE64_LENGTH: usize = 43;
131 const PADDED_BASE64_LENGTH: usize = 44;
132
133 #[inline]
135 pub fn to_bytes(&self) -> [u8; Self::LENGTH] {
136 self.inner.to_bytes()
137 }
138
139 #[inline]
141 pub fn as_bytes(&self) -> &[u8; Self::LENGTH] {
142 self.inner.as_bytes()
143 }
144
145 pub fn to_vec(&self) -> Vec<u8> {
147 self.inner.as_bytes().to_vec()
148 }
149
150 pub fn from_bytes(bytes: [u8; 32]) -> Self {
152 Self { inner: PublicKey::from(bytes) }
153 }
154
155 pub fn from_base64(input: &str) -> Result<Curve25519PublicKey, KeyError> {
158 if input.len() != Self::BASE64_LENGTH && input.len() != Self::PADDED_BASE64_LENGTH {
159 Err(KeyError::InvalidKeyLength {
160 key_type: "Curve25519",
161 expected_length: Self::LENGTH,
162 length: decoded_len_estimate(input.len()),
163 })
164 } else {
165 let key = base64_decode(input)?;
166 Self::from_slice(&key)
167 }
168 }
169
170 pub fn from_slice(slice: &[u8]) -> Result<Curve25519PublicKey, KeyError> {
172 let key_len = slice.len();
173
174 if key_len == Self::LENGTH {
175 let mut key = [0u8; Self::LENGTH];
176 key.copy_from_slice(slice);
177
178 Ok(Self::from(key))
179 } else {
180 Err(KeyError::InvalidKeyLength {
181 key_type: "Curve25519",
182 expected_length: Self::LENGTH,
183 length: key_len,
184 })
185 }
186 }
187
188 pub fn to_base64(&self) -> String {
190 base64_encode(self.inner.as_bytes())
191 }
192}
193
194impl Display for Curve25519PublicKey {
195 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
196 write!(f, "{}", self.to_base64())
197 }
198}
199
200impl std::fmt::Debug for Curve25519PublicKey {
201 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 let s = format!("curve25519:{self}");
203 <str as std::fmt::Debug>::fmt(&s, f)
204 }
205}
206
207impl From<[u8; Self::LENGTH]> for Curve25519PublicKey {
208 fn from(bytes: [u8; Self::LENGTH]) -> Curve25519PublicKey {
209 Curve25519PublicKey { inner: PublicKey::from(bytes) }
210 }
211}
212
213impl<'a> From<&'a Curve25519SecretKey> for Curve25519PublicKey {
214 fn from(secret: &'a Curve25519SecretKey) -> Curve25519PublicKey {
215 Curve25519PublicKey { inner: PublicKey::from(secret.0.as_ref()) }
216 }
217}
218
219impl<'a> From<&'a EphemeralSecret> for Curve25519PublicKey {
220 fn from(secret: &'a EphemeralSecret) -> Curve25519PublicKey {
221 Curve25519PublicKey { inner: PublicKey::from(secret) }
222 }
223}
224
225impl<'a> From<&'a ReusableSecret> for Curve25519PublicKey {
226 fn from(secret: &'a ReusableSecret) -> Curve25519PublicKey {
227 Curve25519PublicKey { inner: PublicKey::from(secret) }
228 }
229}
230
231#[derive(Serialize, Deserialize)]
232#[serde(transparent)]
233pub(crate) struct Curve25519KeypairPickle(Curve25519SecretKey);
234
235impl From<Curve25519KeypairPickle> for Curve25519Keypair {
236 fn from(pickle: Curve25519KeypairPickle) -> Self {
237 let secret_key = pickle.0;
238 let public_key = Curve25519PublicKey::from(&secret_key);
239
240 Self { secret_key, public_key }
241 }
242}
243
244impl From<Curve25519Keypair> for Curve25519KeypairPickle {
245 fn from(key: Curve25519Keypair) -> Self {
246 Curve25519KeypairPickle(key.secret_key)
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use assert_matches2::assert_matches;
253 use insta::assert_debug_snapshot;
254
255 use super::Curve25519PublicKey;
256 use crate::{Curve25519SecretKey, KeyError, utilities::DecodeError};
257
258 #[test]
259 fn decoding_invalid_base64_fails() {
260 let base64_payload = "a";
261 assert_matches!(
262 Curve25519PublicKey::from_base64(base64_payload),
263 Err(KeyError::InvalidKeyLength { .. })
264 );
265
266 let base64_payload = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ";
267 assert_matches!(
268 Curve25519PublicKey::from_base64(base64_payload),
269 Err(KeyError::Base64Error(DecodeError::InvalidByte(..)))
270 );
271
272 let base64_payload = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ";
273 assert_matches!(
274 Curve25519PublicKey::from_base64(base64_payload),
275 Err(KeyError::Base64Error(DecodeError::InvalidLastSymbol(..)))
276 );
277 }
278
279 #[test]
280 fn decoding_incorrect_num_of_bytes_fails() {
281 let base64_payload = "aaaa";
282 assert_matches!(
283 Curve25519PublicKey::from_base64(base64_payload),
284 Err(KeyError::InvalidKeyLength { .. })
285 );
286 }
287
288 #[test]
289 fn decoding_of_correct_num_of_bytes_succeeds() {
290 let base64_payload = "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
291 assert_matches!(Curve25519PublicKey::from_base64(base64_payload), Ok(..));
292 }
293
294 #[test]
295 fn byte_decoding_roundtrip_succeeds_for_public_key() {
296 let bytes = *b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
297 let key = Curve25519PublicKey::from_bytes(bytes);
298 assert_eq!(key.to_bytes(), bytes);
299 assert_eq!(key.as_bytes(), &bytes);
300 assert_eq!(key.to_vec(), bytes.to_vec());
301 }
302
303 #[test]
304 fn byte_decoding_roundtrip_succeeds_for_secret_key() {
305 let bytes = *b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
306 let key = Curve25519SecretKey::from_slice(&bytes);
307 assert_eq!(*(key.to_bytes()), bytes);
308 }
309
310 #[test]
311 fn snapshot_public_key_debug() {
312 let key = Curve25519PublicKey::from_bytes([0; 32]);
313 assert_debug_snapshot!(key);
314 }
315}