simploxide_client/crypto/
native.rs1use poly1305::{
2 Block as MacBlock, Poly1305,
3 universal_hash::{KeyInit, UniversalHash},
4};
5use salsa20::{
6 XSalsa20,
7 cipher::{Array, KeyIvInit, StreamCipher, typenum::U10},
8 hsalsa,
9};
10use subtle::ConstantTimeEq as _;
11use zeroize::{Zeroize as _, Zeroizing};
12
13use super::{Poly1305Tag, SimplexSecretBox, XSalsa20Key, XSalsa20Nonce};
14
15pub struct SecretBox {
16 cipher: XSalsa20,
17 mac: Poly1305,
18 mac_tail: Zeroizing<[u8; 16]>,
20 mac_tail_len: usize,
21}
22
23impl SecretBox {
24 fn update_mac(&mut self, data: &[u8]) {
27 let mut pos = 0;
28
29 if self.mac_tail_len > 0 {
31 let rem = std::cmp::min(16 - self.mac_tail_len, data.len());
32 self.mac_tail[self.mac_tail_len..self.mac_tail_len + rem].copy_from_slice(&data[..rem]);
33
34 self.mac_tail_len += rem;
35 pos = rem;
36
37 if self.mac_tail_len == 16 {
38 self.mac
39 .update(&[MacBlock::clone_from_slice(self.mac_tail.as_ref())]);
40
41 self.mac_tail_len = 0;
42 }
43 }
44
45 let mut chunks = data[pos..].chunks_exact(16);
47
48 for chunk in &mut chunks {
49 self.mac.update(&[MacBlock::clone_from_slice(chunk)]);
50 }
51
52 let tail = chunks.remainder();
53
54 if !tail.is_empty() {
55 self.mac_tail[..tail.len()].copy_from_slice(tail);
56 self.mac_tail_len += tail.len();
57 }
58 }
59}
60
61impl SimplexSecretBox for SecretBox {
62 fn init(key: &XSalsa20Key, nonce: &XSalsa20Nonce) -> Self {
63 let mut intermediate = hsalsa::<U10>(&Array(*key), &Array([0u8; 16]));
64 let mut cipher = XSalsa20::new(&intermediate, &Array(*nonce));
65 let mut poly_key = [0u8; 32];
66
67 cipher.apply_keystream(&mut poly_key);
68 let mac = Poly1305::new_from_slice(&poly_key).unwrap();
69
70 intermediate.zeroize();
71 poly_key.zeroize();
72
73 Self {
74 cipher,
75 mac,
76 mac_tail: Zeroizing::new([0u8; 16]),
77 mac_tail_len: 0,
78 }
79 }
80
81 fn encrypt_chunk(&mut self, chunk: impl AsRef<[u8]>, mut output: impl AsMut<[u8]>) {
82 let chunk = chunk.as_ref();
83 let output = output.as_mut();
84
85 output[..chunk.len()].copy_from_slice(chunk);
86 self.cipher.apply_keystream(&mut output[..chunk.len()]);
87 self.update_mac(&output[..chunk.len()]);
88 }
89
90 fn decrypt_chunk(&mut self, chunk: impl AsRef<[u8]>, mut output: impl AsMut<[u8]>) {
91 let chunk = chunk.as_ref();
92 let output = output.as_mut();
93
94 output[..chunk.len()].copy_from_slice(chunk);
95 self.cipher.apply_keystream(&mut output[..chunk.len()]);
96 self.update_mac(chunk); }
98
99 fn auth_tag(&mut self) -> Poly1305Tag {
100 self.mac
101 .clone()
102 .compute_unpadded(&self.mac_tail[..self.mac_tail_len])
103 .into()
104 }
105
106 fn verify_tag(&mut self, in_tag: &Poly1305Tag) -> bool {
107 let tag = self.auth_tag();
108 tag.as_slice().ct_eq(in_tag.as_slice()).into()
109 }
110}