1use std::{ffi::NulError, fmt};
2
3use x25519_dalek::{PublicKey, StaticSecret};
4
5#[derive(Eq, PartialEq, Debug, Clone)]
7pub struct InvalidKey;
8
9impl std::error::Error for InvalidKey {}
10
11impl fmt::Display for InvalidKey {
12 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
13 write!(f, "Invalid key format")
14 }
15}
16
17impl From<NulError> for InvalidKey {
18 fn from(_: NulError) -> Self {
19 InvalidKey {}
20 }
21}
22
23#[derive(PartialEq, Eq, Clone, Hash)]
32pub struct Key(pub [u8; 32]);
33
34impl Key {
35 pub fn generate_private() -> Self {
37 use rand_core::{OsRng, RngCore};
38
39 let mut bytes = [0u8; 32];
40 OsRng.fill_bytes(&mut bytes);
41
42 bytes[0] &= 248;
44 bytes[31] &= 127;
45 bytes[31] |= 64;
46 Self(bytes)
47 }
48
49 #[must_use]
51 pub fn generate_preshared() -> Self {
52 use rand_core::{OsRng, RngCore};
53
54 let mut key = [0u8; 32];
55 OsRng.fill_bytes(&mut key);
56 Self(key)
57 }
58
59 #[must_use]
61 pub fn get_public(&self) -> Self {
62 let secret = StaticSecret::from(self.0);
63 let public = PublicKey::from(&secret);
64
65 Self(public.to_bytes())
66 }
67
68 #[must_use]
70 pub fn zero() -> Self {
71 Self([0u8; 32])
72 }
73
74 pub fn as_bytes(&self) -> &[u8] {
75 &self.0
76 }
77
78 pub fn to_base64(&self) -> String {
80 base64::encode(self.0)
81 }
82
83 pub fn from_base64(key: &str) -> Result<Self, crate::InvalidKey> {
88 let mut key_bytes = [0u8; 32];
89 let decoded_bytes = base64::decode(key).map_err(|_| InvalidKey)?;
90
91 if decoded_bytes.len() != 32 {
92 return Err(InvalidKey);
93 }
94
95 key_bytes.copy_from_slice(&decoded_bytes[..]);
96 Ok(Self(key_bytes))
97 }
98
99 pub fn from_hex(hex_str: &str) -> Result<Self, crate::InvalidKey> {
100 let mut sized_bytes = [0u8; 32];
101 hex::decode_to_slice(hex_str, &mut sized_bytes).map_err(|_| InvalidKey)?;
102 Ok(Self(sized_bytes))
103 }
104}
105
106#[cfg(test)]
107mod test {
108 use super::*;
109
110 #[test]
111 fn test_pubkey_generation() {
112 let privkey = "SGb+ojrRNDuMePufwtIYhXzA//k6wF3R21tEBgKlzlM=";
113 let pubkey = "DD5yKRfzExcV5+kDnTroDgCU15latdMjiQ59j1hEuk8=";
114
115 let private = Key::from_base64(privkey).unwrap();
116 let public = Key::get_public(&private);
117
118 assert_eq!(public.to_base64(), pubkey);
119 }
120
121 #[test]
122 fn test_rng_sanity_private() {
123 let first = Key::generate_private();
124 assert!(first.as_bytes() != [0u8; 32]);
125 for _ in 0..100_000 {
126 let key = Key::generate_private();
127 assert!(first != key);
128 assert!(key.as_bytes() != [0u8; 32]);
129 }
130 }
131
132 #[test]
133 fn test_rng_sanity_preshared() {
134 let first = Key::generate_preshared();
135 assert!(first.as_bytes() != [0u8; 32]);
136 for _ in 0..100_000 {
137 let key = Key::generate_preshared();
138 assert!(first != key);
139 assert!(key.as_bytes() != [0u8; 32]);
140 }
141 }
142}
143
144#[derive(Debug, PartialEq, Eq, Clone)]
149pub struct KeyPair {
150 pub private: Key,
152 pub public: Key,
154}
155
156impl fmt::Debug for Key {
157 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
158 write!(f, "Key(\"{}\")", self.to_base64())
159 }
160}
161
162impl KeyPair {
163 pub fn generate() -> Self {
164 let private = Key::generate_private();
165 let public = private.get_public();
166 KeyPair { private, public }
167 }
168
169 pub fn from_private(key: Key) -> Self {
170 let public = key.get_public();
171 KeyPair {
172 private: key,
173 public,
174 }
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 #[test]
181 fn test_key_zero() {
182 use crate::key::Key;
183
184 let key = Key::generate_preshared();
185 assert_ne!(key.as_bytes(), &[0u8; 32]);
186 }
187
188 #[test]
189 fn test_key_base64() {
190 use crate::key::Key;
191
192 let key = Key::generate_preshared();
193 let key_b64 = key.to_base64();
194 let key_new = Key::from_base64(&key_b64).unwrap();
195
196 assert_eq!(key, key_new);
197 }
198
199 #[test]
200 fn test_invalid_key() {
201 use crate::key::{InvalidKey, Key};
202
203 let key_b64: String = Key::generate_preshared()
204 .to_base64()
205 .chars()
206 .rev()
207 .collect();
208
209 assert_eq!(Key::from_base64(&key_b64), Err(InvalidKey));
210 }
211
212 #[test]
213 fn test_generate_keypair_basic() {
214 use crate::key::Key;
215
216 let privkey = Key::generate_private();
217 let pubkey = privkey.get_public();
218
219 assert_ne!(privkey, pubkey);
220 }
221
222 #[test]
223 fn test_generate_keypair_helper() {
224 use crate::key::KeyPair;
225 let pair = KeyPair::generate();
226
227 assert_ne!(pair.private, pair.public);
228 }
229}