1#![no_std]
13
14pub mod sensitive;
15
16use sensitive::Sensitive;
17
18use noise_protocol::*;
19#[cfg(feature = "x25519")]
20use x25519_dalek::{PublicKey, StaticSecret};
21
22#[cfg(feature = "x25519")]
23pub enum X25519 {}
24
25#[cfg(feature = "x25519")]
26impl DH for X25519 {
27 type Key = Sensitive<[u8; 32]>;
28 type Pubkey = [u8; 32];
29 type Output = Sensitive<[u8; 32]>;
30
31 fn name() -> &'static str {
32 "25519"
33 }
34
35 fn genkey() -> Self::Key {
36 Self::Key::from_slice(StaticSecret::random().as_bytes())
37 }
38
39 fn pubkey(k: &Self::Key) -> Self::Pubkey {
40 let static_secret = StaticSecret::from(**k);
41 *PublicKey::from(&static_secret).as_bytes()
42 }
43
44 fn dh(k: &Self::Key, pk: &Self::Pubkey) -> Result<Self::Output, ()> {
45 let k = StaticSecret::from(**k);
46 let pk = PublicKey::from(*pk);
47 Ok(Self::Output::from_slice(k.diffie_hellman(&pk).as_bytes()))
48 }
49}
50
51#[cfg(feature = "use-chacha20poly1305")]
52pub enum ChaCha20Poly1305 {}
53
54#[cfg(feature = "use-chacha20poly1305")]
55impl Cipher for ChaCha20Poly1305 {
56 fn name() -> &'static str {
57 "ChaChaPoly"
58 }
59
60 type Key = Sensitive<[u8; 32]>;
61
62 fn encrypt(k: &Self::Key, nonce: u64, ad: &[u8], plaintext: &[u8], out: &mut [u8]) {
63 assert!(plaintext.len().checked_add(16) == Some(out.len()));
64
65 let mut full_nonce = [0u8; 12];
66 full_nonce[4..].copy_from_slice(&nonce.to_le_bytes());
67
68 let (in_out, tag_out) = out.split_at_mut(plaintext.len());
69 in_out.copy_from_slice(plaintext);
70
71 use chacha20poly1305::{AeadInPlace, KeyInit};
72 let tag = chacha20poly1305::ChaCha20Poly1305::new(&(**k).into())
73 .encrypt_in_place_detached(&full_nonce.into(), ad, in_out)
74 .unwrap();
75
76 tag_out.copy_from_slice(tag.as_ref())
77 }
78
79 fn encrypt_in_place(
80 k: &Self::Key,
81 nonce: u64,
82 ad: &[u8],
83 in_out: &mut [u8],
84 plaintext_len: usize,
85 ) -> usize {
86 assert!(plaintext_len
87 .checked_add(16)
88 .map_or(false, |l| l <= in_out.len()));
89
90 let mut full_nonce = [0u8; 12];
91 full_nonce[4..].copy_from_slice(&nonce.to_le_bytes());
92
93 let (in_out, tag_out) = in_out[..plaintext_len + 16].split_at_mut(plaintext_len);
94
95 use chacha20poly1305::{AeadInPlace, KeyInit};
96 let tag = chacha20poly1305::ChaCha20Poly1305::new(&(**k).into())
97 .encrypt_in_place_detached(&full_nonce.into(), ad, in_out)
98 .unwrap();
99 tag_out.copy_from_slice(tag.as_ref());
100
101 plaintext_len + 16
102 }
103
104 fn decrypt(
105 k: &Self::Key,
106 nonce: u64,
107 ad: &[u8],
108 ciphertext: &[u8],
109 out: &mut [u8],
110 ) -> Result<(), ()> {
111 assert!(ciphertext.len().checked_sub(16) == Some(out.len()));
112
113 let mut full_nonce = [0u8; 12];
114 full_nonce[4..].copy_from_slice(&nonce.to_le_bytes());
115
116 out.copy_from_slice(&ciphertext[..out.len()]);
117 let tag = &ciphertext[out.len()..];
118
119 use chacha20poly1305::{AeadInPlace, KeyInit};
120 chacha20poly1305::ChaCha20Poly1305::new(&(**k).into())
121 .decrypt_in_place_detached(&full_nonce.into(), ad, out, tag.into())
122 .map_err(|_| ())
123 }
124
125 fn decrypt_in_place(
126 k: &Self::Key,
127 nonce: u64,
128 ad: &[u8],
129 in_out: &mut [u8],
130 ciphertext_len: usize,
131 ) -> Result<usize, ()> {
132 assert!(ciphertext_len <= in_out.len());
133 assert!(ciphertext_len >= 16);
134
135 let mut full_nonce = [0u8; 12];
136 full_nonce[4..].copy_from_slice(&nonce.to_le_bytes());
137
138 let (in_out, tag) = in_out[..ciphertext_len].split_at_mut(ciphertext_len - 16);
139
140 use chacha20poly1305::{AeadInPlace, KeyInit};
141 chacha20poly1305::ChaCha20Poly1305::new(&(**k).into())
142 .decrypt_in_place_detached(&full_nonce.into(), ad, in_out, tag.as_ref().into())
143 .map_err(|_| ())?;
144
145 Ok(in_out.len())
146 }
147}
148
149#[cfg(feature = "use-aes-256-gcm")]
150pub enum Aes256Gcm {}
151
152#[cfg(feature = "use-aes-256-gcm")]
153impl Cipher for Aes256Gcm {
154 fn name() -> &'static str {
155 "AESGCM"
156 }
157
158 type Key = Sensitive<[u8; 32]>;
159
160 fn encrypt(k: &Self::Key, nonce: u64, ad: &[u8], plaintext: &[u8], out: &mut [u8]) {
161 assert!(plaintext.len().checked_add(16) == Some(out.len()));
162
163 let mut full_nonce = [0u8; 12];
164 full_nonce[4..].copy_from_slice(&nonce.to_be_bytes());
165
166 let (in_out, tag_out) = out.split_at_mut(plaintext.len());
167 in_out.copy_from_slice(plaintext);
168
169 use aes_gcm::{AeadInPlace, KeyInit};
170 let tag = aes_gcm::Aes256Gcm::new(&(**k).into())
171 .encrypt_in_place_detached(&full_nonce.into(), ad, in_out)
172 .unwrap();
173
174 tag_out.copy_from_slice(tag.as_ref())
175 }
176
177 fn encrypt_in_place(
178 k: &Self::Key,
179 nonce: u64,
180 ad: &[u8],
181 in_out: &mut [u8],
182 plaintext_len: usize,
183 ) -> usize {
184 assert!(plaintext_len
185 .checked_add(16)
186 .map_or(false, |l| l <= in_out.len()));
187
188 let mut full_nonce = [0u8; 12];
189 full_nonce[4..].copy_from_slice(&nonce.to_be_bytes());
190
191 let (in_out, tag_out) = in_out[..plaintext_len + 16].split_at_mut(plaintext_len);
192
193 use aes_gcm::{AeadInPlace, KeyInit};
194 let tag = aes_gcm::Aes256Gcm::new(&(**k).into())
195 .encrypt_in_place_detached(&full_nonce.into(), ad, in_out)
196 .unwrap();
197 tag_out.copy_from_slice(tag.as_ref());
198
199 plaintext_len + 16
200 }
201
202 fn decrypt(
203 k: &Self::Key,
204 nonce: u64,
205 ad: &[u8],
206 ciphertext: &[u8],
207 out: &mut [u8],
208 ) -> Result<(), ()> {
209 assert!(ciphertext.len().checked_sub(16) == Some(out.len()));
210
211 let mut full_nonce = [0u8; 12];
212 full_nonce[4..].copy_from_slice(&nonce.to_be_bytes());
213
214 out.copy_from_slice(&ciphertext[..out.len()]);
215 let tag = &ciphertext[out.len()..];
216
217 use aes_gcm::{AeadInPlace, KeyInit};
218 aes_gcm::Aes256Gcm::new(&(**k).into())
219 .decrypt_in_place_detached(&full_nonce.into(), ad, out, tag.into())
220 .map_err(|_| ())
221 }
222
223 fn decrypt_in_place(
224 k: &Self::Key,
225 nonce: u64,
226 ad: &[u8],
227 in_out: &mut [u8],
228 ciphertext_len: usize,
229 ) -> Result<usize, ()> {
230 assert!(ciphertext_len <= in_out.len());
231 assert!(ciphertext_len >= 16);
232
233 let mut full_nonce = [0u8; 12];
234 full_nonce[4..].copy_from_slice(&nonce.to_be_bytes());
235
236 let (in_out, tag) = in_out[..ciphertext_len].split_at_mut(ciphertext_len - 16);
237
238 use aes_gcm::{AeadInPlace, KeyInit};
239 aes_gcm::Aes256Gcm::new(&(**k).into())
240 .decrypt_in_place_detached(&full_nonce.into(), ad, in_out, tag.as_ref().into())
241 .map_err(|_| ())?;
242
243 Ok(in_out.len())
244 }
245}
246
247#[cfg(feature = "use-sha2")]
248#[derive(Default, Clone)]
249pub struct Sha256(sha2::Sha256);
250
251#[cfg(feature = "use-sha2")]
252impl Hash for Sha256 {
253 fn name() -> &'static str {
254 "SHA256"
255 }
256
257 type Block = [u8; 64];
258 type Output = Sensitive<[u8; 32]>;
259
260 fn input(&mut self, data: &[u8]) {
261 use sha2::Digest;
262 self.0.update(data);
263 }
264
265 fn result(&mut self) -> Self::Output {
266 use sha2::Digest;
267 Self::Output::from_slice(self.0.finalize_reset().as_ref())
268 }
269}
270
271#[cfg(feature = "use-sha2")]
272#[derive(Default, Clone)]
273pub struct Sha512(sha2::Sha512);
274
275#[cfg(feature = "use-sha2")]
276impl Hash for Sha512 {
277 fn name() -> &'static str {
278 "SHA512"
279 }
280
281 type Block = [u8; 128];
282 type Output = Sensitive<[u8; 64]>;
283
284 fn input(&mut self, data: &[u8]) {
285 use sha2::Digest;
286 self.0.update(data);
287 }
288
289 fn result(&mut self) -> Self::Output {
290 use sha2::Digest;
291 Self::Output::from_slice(self.0.finalize_reset().as_ref())
292 }
293}
294
295#[cfg(feature = "use-blake2")]
296#[derive(Default, Clone)]
297pub struct Blake2s(blake2::Blake2s256);
298
299#[cfg(feature = "use-blake2")]
300impl Hash for Blake2s {
301 fn name() -> &'static str {
302 "BLAKE2s"
303 }
304
305 type Block = [u8; 64];
306 type Output = Sensitive<[u8; 32]>;
307
308 fn input(&mut self, data: &[u8]) {
309 use blake2::Digest;
310 self.0.update(data);
311 }
312
313 fn result(&mut self) -> Self::Output {
314 use blake2::Digest;
315 Self::Output::from_slice(self.0.finalize_reset().as_ref())
316 }
317}
318
319#[cfg(feature = "use-blake2")]
320#[derive(Default, Clone)]
321pub struct Blake2b(blake2::Blake2b512);
322
323#[cfg(feature = "use-blake2")]
324impl Hash for Blake2b {
325 fn name() -> &'static str {
326 "BLAKE2b"
327 }
328
329 type Block = [u8; 128];
330 type Output = Sensitive<[u8; 64]>;
331
332 fn input(&mut self, data: &[u8]) {
333 use blake2::Digest;
334 self.0.update(data);
335 }
336
337 fn result(&mut self) -> Self::Output {
338 use blake2::Digest;
339 Self::Output::from_slice(self.0.finalize_reset().as_ref())
340 }
341}