1use crate::classic::crypto_secretbox_impl::*;
35use crate::constants::{
36 CRYPTO_SECRETBOX_KEYBYTES, CRYPTO_SECRETBOX_MACBYTES, CRYPTO_SECRETBOX_NONCEBYTES,
37};
38use crate::error::Error;
39use crate::rng::copy_randombytes;
40use crate::types::*;
41
42pub type Mac = [u8; CRYPTO_SECRETBOX_MACBYTES];
44pub type Nonce = [u8; CRYPTO_SECRETBOX_NONCEBYTES];
46pub type Key = [u8; CRYPTO_SECRETBOX_KEYBYTES];
48
49pub fn crypto_secretbox_keygen_inplace(key: &mut Key) {
51 copy_randombytes(key)
52}
53
54pub fn crypto_secretbox_keygen() -> Key {
57 Key::gen()
58}
59
60pub fn crypto_secretbox_detached(
64 ciphertext: &mut [u8],
65 mac: &mut Mac,
66 message: &[u8],
67 nonce: &Nonce,
68 key: &Key,
69) {
70 ciphertext[..message.len()].copy_from_slice(message);
71 crypto_secretbox_detached_inplace(ciphertext, mac, nonce, key);
72}
73
74pub fn crypto_secretbox_open_detached(
78 message: &mut [u8],
79 mac: &Mac,
80 ciphertext: &[u8],
81 nonce: &Nonce,
82 key: &Key,
83) -> Result<(), Error> {
84 let c_len = ciphertext.len();
85 message[..c_len].copy_from_slice(ciphertext);
86 crypto_secretbox_open_detached_inplace(message, mac, nonce, key)
87}
88
89pub fn crypto_secretbox_easy(
93 ciphertext: &mut [u8],
94 message: &[u8],
95 nonce: &Nonce,
96 key: &Key,
97) -> Result<(), Error> {
98 let mut mac = Mac::default();
99 crypto_secretbox_detached(
100 &mut ciphertext[CRYPTO_SECRETBOX_MACBYTES..],
101 &mut mac,
102 message,
103 nonce,
104 key,
105 );
106
107 ciphertext[..CRYPTO_SECRETBOX_MACBYTES].copy_from_slice(&mac);
108
109 Ok(())
110}
111
112pub fn crypto_secretbox_open_easy(
116 message: &mut [u8],
117 ciphertext: &[u8],
118 nonce: &Nonce,
119 key: &Key,
120) -> Result<(), Error> {
121 if ciphertext.len() < CRYPTO_SECRETBOX_MACBYTES {
122 Err(dryoc_error!(format!(
123 "Impossibly small box ({} < {}",
124 ciphertext.len(),
125 CRYPTO_SECRETBOX_MACBYTES
126 )))
127 } else {
128 let (mac, ciphertext) = ciphertext.split_at(CRYPTO_SECRETBOX_MACBYTES);
129 let mac = ByteArray::as_array(mac);
130 crypto_secretbox_open_detached(message, mac, ciphertext, nonce, key)
131 }
132}
133
134pub fn crypto_secretbox_easy_inplace(
137 data: &mut [u8],
138 nonce: &Nonce,
139 key: &Key,
140) -> Result<(), Error> {
141 data.rotate_right(CRYPTO_SECRETBOX_MACBYTES);
142 let (mac, data) = data.split_at_mut(CRYPTO_SECRETBOX_MACBYTES);
143 let mac = MutByteArray::as_mut_array(mac);
144
145 crypto_secretbox_detached_inplace(data, mac, nonce, key);
146
147 Ok(())
148}
149
150pub fn crypto_secretbox_open_easy_inplace(
153 ciphertext: &mut [u8],
154 nonce: &Nonce,
155 key: &Key,
156) -> Result<(), Error> {
157 if ciphertext.len() < CRYPTO_SECRETBOX_MACBYTES {
158 Err(dryoc_error!(format!(
159 "Impossibly small box ({} < {}",
160 ciphertext.len(),
161 CRYPTO_SECRETBOX_MACBYTES
162 )))
163 } else {
164 let (mac, data) = ciphertext.split_at_mut(CRYPTO_SECRETBOX_MACBYTES);
165 let mac = ByteArray::as_array(mac);
166
167 crypto_secretbox_open_detached_inplace(data, mac, nonce, key)?;
168
169 ciphertext.rotate_left(CRYPTO_SECRETBOX_MACBYTES);
170
171 Ok(())
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178
179 #[test]
180 fn test_crypto_secretbox_easy() {
181 for i in 0..20 {
182 use base64::Engine as _;
183 use base64::engine::general_purpose;
184 use sodiumoxide::crypto::secretbox;
185 use sodiumoxide::crypto::secretbox::{Key as SOKey, Nonce as SONonce};
186
187 let key: Key = crypto_secretbox_keygen();
188 let nonce = Nonce::gen();
189
190 let words = vec!["love Doge".to_string(); i];
191 let message = words.join(" <3 ");
192
193 let mut ciphertext = vec![0u8; message.len() + CRYPTO_SECRETBOX_MACBYTES];
194 crypto_secretbox_easy(&mut ciphertext, message.as_bytes(), &nonce, &key)
195 .expect("encrypt failed");
196 let so_ciphertext = secretbox::seal(
197 message.as_bytes(),
198 &SONonce::from_slice(&nonce).unwrap(),
199 &SOKey::from_slice(&key).unwrap(),
200 );
201 assert_eq!(
202 general_purpose::STANDARD.encode(&ciphertext),
203 general_purpose::STANDARD.encode(&so_ciphertext)
204 );
205
206 let mut decrypted = vec![0u8; message.len()];
207 crypto_secretbox_open_easy(&mut decrypted, &ciphertext, &nonce, &key)
208 .expect("decrypt failed");
209 let so_decrypted = secretbox::open(
210 &ciphertext,
211 &SONonce::from_slice(&nonce).unwrap(),
212 &SOKey::from_slice(&key).unwrap(),
213 )
214 .unwrap();
215
216 assert_eq!(decrypted, message.as_bytes());
217 assert_eq!(decrypted, so_decrypted);
218 }
219 }
220
221 #[test]
222 fn test_crypto_secretbox_easy_inplace() {
223 for i in 0..20 {
224 use base64::Engine as _;
225 use base64::engine::general_purpose;
226 use sodiumoxide::crypto::secretbox;
227 use sodiumoxide::crypto::secretbox::{Key as SOKey, Nonce as SONonce};
228
229 let key = crypto_secretbox_keygen();
230 let nonce = Nonce::gen();
231
232 let words = vec!["love Doge".to_string(); i];
233 let message: Vec<u8> = words.join(" <3 ").into();
234 let message_copy = message.clone();
235
236 let mut ciphertext = message.clone();
237 ciphertext.resize(message.len() + CRYPTO_SECRETBOX_MACBYTES, 0);
238 crypto_secretbox_easy_inplace(&mut ciphertext, &nonce, &key).expect("encrypt failed");
239 let so_ciphertext = secretbox::seal(
240 &message_copy,
241 &SONonce::from_slice(&nonce).unwrap(),
242 &SOKey::from_slice(&key).unwrap(),
243 );
244 assert_eq!(
245 general_purpose::STANDARD.encode(&ciphertext),
246 general_purpose::STANDARD.encode(&so_ciphertext)
247 );
248
249 let mut decrypted = ciphertext.clone();
250 crypto_secretbox_open_easy_inplace(&mut decrypted, &nonce, &key)
251 .expect("decrypt failed");
252 decrypted.resize(ciphertext.len() - CRYPTO_SECRETBOX_MACBYTES, 0);
253 let so_decrypted = secretbox::open(
254 &ciphertext,
255 &SONonce::from_slice(&nonce).unwrap(),
256 &SOKey::from_slice(&key).unwrap(),
257 )
258 .expect("decrypt failed");
259
260 assert_eq!(&decrypted, &message_copy);
261 assert_eq!(decrypted, so_decrypted);
262 }
263 }
264}