1use zeroize::Zeroize;
44
45use super::crypto_generichash::{
46 crypto_generichash_final, crypto_generichash_init, crypto_generichash_update,
47};
48use crate::classic::crypto_box_impl::*;
49use crate::classic::crypto_secretbox::*;
50use crate::classic::crypto_secretbox_impl::*;
51use crate::constants::*;
52use crate::error::Error;
53use crate::types::*;
54
55pub type Mac = [u8; CRYPTO_BOX_MACBYTES];
57
58pub type Nonce = [u8; CRYPTO_BOX_NONCEBYTES];
60pub type PublicKey = [u8; CRYPTO_BOX_PUBLICKEYBYTES];
62pub type SecretKey = [u8; CRYPTO_BOX_SECRETKEYBYTES];
64
65pub fn crypto_box_keypair_inplace(public_key: &mut PublicKey, secret_key: &mut SecretKey) {
67 crypto_box_curve25519xsalsa20poly1305_keypair_inplace(public_key, secret_key)
68}
69
70pub fn crypto_box_seed_keypair_inplace(
72 public_key: &mut PublicKey,
73 secret_key: &mut SecretKey,
74 seed: &[u8],
75) {
76 crypto_box_curve25519xsalsa20poly1305_seed_keypair_inplace(public_key, secret_key, seed)
77}
78
79pub fn crypto_box_keypair() -> (PublicKey, SecretKey) {
82 crypto_box_curve25519xsalsa20poly1305_keypair()
83}
84
85pub fn crypto_box_seed_keypair(seed: &[u8]) -> (PublicKey, SecretKey) {
90 crypto_box_curve25519xsalsa20poly1305_seed_keypair(seed)
91}
92
93pub fn crypto_box_beforenm(public_key: &PublicKey, secret_key: &SecretKey) -> Key {
98 crypto_box_curve25519xsalsa20poly1305_beforenm(public_key, secret_key)
99}
100
101pub fn crypto_box_detached_afternm(
106 ciphertext: &mut [u8],
107 mac: &mut Mac,
108 message: &[u8],
109 nonce: &Nonce,
110 key: &Key,
111) {
112 crypto_secretbox_detached(ciphertext, mac, message, nonce, key)
113}
114
115pub fn crypto_box_detached_afternm_inplace(
117 ciphertext: &mut [u8],
118 mac: &mut Mac,
119 nonce: &Nonce,
120 key: &Key,
121) {
122 crypto_secretbox_detached_inplace(ciphertext, mac, nonce, key)
123}
124
125pub fn crypto_box_detached(
129 ciphertext: &mut [u8],
130 mac: &mut Mac,
131 message: &[u8],
132 nonce: &Nonce,
133 recipient_public_key: &PublicKey,
134 sender_secret_key: &SecretKey,
135) {
136 let mut key = crypto_box_beforenm(recipient_public_key, sender_secret_key);
137
138 crypto_box_detached_afternm(ciphertext, mac, message, nonce, &key);
139
140 key.zeroize();
141}
142
143pub fn crypto_box_detached_inplace(
145 message: &mut [u8],
146 mac: &mut Mac,
147 nonce: &Nonce,
148 recipient_public_key: &PublicKey,
149 sender_secret_key: &SecretKey,
150) -> Result<(), Error> {
151 let mut key = crypto_box_beforenm(recipient_public_key, sender_secret_key);
152
153 crypto_box_detached_afternm_inplace(message, mac, nonce, &key);
154
155 key.zeroize();
156
157 Ok(())
158}
159pub fn crypto_box_easy(
168 ciphertext: &mut [u8],
169 message: &[u8],
170 nonce: &Nonce,
171 recipient_public_key: &PublicKey,
172 sender_secret_key: &SecretKey,
173) -> Result<(), Error> {
174 if ciphertext.len() < CRYPTO_BOX_MACBYTES {
175 Err(dryoc_error!(format!(
176 "ciphertext length {} less than minimum {}",
177 ciphertext.len(),
178 CRYPTO_BOX_MACBYTES
179 )))
180 } else if message.len() > CRYPTO_BOX_MESSAGEBYTES_MAX {
181 Err(dryoc_error!(format!(
182 "message length {} exceeds max message length {}",
183 message.len(),
184 CRYPTO_BOX_MESSAGEBYTES_MAX
185 )))
186 } else {
187 let (mac, ciphertext) = ciphertext.split_at_mut(CRYPTO_BOX_MACBYTES);
188 let mac = MutByteArray::as_mut_array(mac);
189 crypto_box_detached(
190 ciphertext,
191 mac,
192 message,
193 nonce,
194 recipient_public_key,
195 sender_secret_key,
196 );
197
198 Ok(())
199 }
200}
201
202pub(crate) fn crypto_box_seal_nonce(nonce: &mut Nonce, epk: &PublicKey, rpk: &SecretKey) {
203 let mut state = crypto_generichash_init(None, CRYPTO_BOX_NONCEBYTES).expect("state");
204 crypto_generichash_update(&mut state, epk);
205 crypto_generichash_update(&mut state, rpk);
206 crypto_generichash_final(state, nonce).expect("hash error");
207}
208
209pub fn crypto_box_seal(
218 ciphertext: &mut [u8],
219 message: &[u8],
220 recipient_public_key: &PublicKey,
221) -> Result<(), Error> {
222 if ciphertext.len() < message.len() + CRYPTO_BOX_SEALBYTES {
223 Err(dryoc_error!(format!(
224 "ciphertext length invalid ({} != {}",
225 ciphertext.len(),
226 message.len() + CRYPTO_BOX_SEALBYTES,
227 )))
228 } else {
229 let mut nonce = Nonce::new_byte_array();
230 let (mut epk, mut esk) = crypto_box_keypair();
231 crypto_box_seal_nonce(&mut nonce, &epk, recipient_public_key);
232
233 crypto_box_easy(
234 &mut ciphertext[CRYPTO_BOX_PUBLICKEYBYTES..],
235 message,
236 &nonce,
237 recipient_public_key,
238 &esk,
239 )?;
240
241 ciphertext[..CRYPTO_BOX_PUBLICKEYBYTES].copy_from_slice(&epk);
242
243 epk.zeroize();
244 esk.zeroize();
245 nonce.zeroize();
246
247 Ok(())
248 }
249}
250
251pub fn crypto_box_easy_inplace(
265 data: &mut [u8],
266 nonce: &Nonce,
267 recipient_public_key: &PublicKey,
268 sender_secret_key: &SecretKey,
269) -> Result<(), Error> {
270 if data.len() < CRYPTO_BOX_MACBYTES {
271 Err(dryoc_error!(format!(
272 "Message length {} less than {}, impossibly small",
273 data.len(),
274 CRYPTO_BOX_MACBYTES
275 )))
276 } else if data.len() > CRYPTO_BOX_MESSAGEBYTES_MAX {
277 Err(dryoc_error!(format!(
278 "Message length {} exceeds max message length {}",
279 data.len(),
280 CRYPTO_BOX_MESSAGEBYTES_MAX
281 )))
282 } else {
283 data.rotate_right(CRYPTO_BOX_MACBYTES);
284
285 let (mac, data) = data.split_at_mut(CRYPTO_BOX_MACBYTES);
286 let mac = MutByteArray::as_mut_array(mac);
287
288 crypto_box_detached_inplace(data, mac, nonce, recipient_public_key, sender_secret_key)?;
289
290 Ok(())
291 }
292}
293
294pub fn crypto_box_open_detached_afternm(
298 message: &mut [u8],
299 mac: &Mac,
300 ciphertext: &[u8],
301 nonce: &Nonce,
302 key: &Key,
303) -> Result<(), Error> {
304 crypto_secretbox_open_detached(message, mac, ciphertext, nonce, key)
305}
306
307pub fn crypto_box_open_detached_afternm_inplace(
309 data: &mut [u8],
310 mac: &Mac,
311 nonce: &Nonce,
312 key: &Key,
313) -> Result<(), Error> {
314 crypto_secretbox_open_detached_inplace(data, mac, nonce, key)
315}
316
317pub fn crypto_box_open_detached(
321 message: &mut [u8],
322 mac: &Mac,
323 ciphertext: &[u8],
324 nonce: &Nonce,
325 recipient_public_key: &PublicKey,
326 sender_secret_key: &SecretKey,
327) -> Result<(), Error> {
328 let mut key = crypto_box_beforenm(recipient_public_key, sender_secret_key);
329
330 crypto_box_open_detached_afternm(message, mac, ciphertext, nonce, &key)?;
331
332 key.zeroize();
333
334 Ok(())
335}
336
337pub fn crypto_box_open_detached_inplace(
339 data: &mut [u8],
340 mac: &Mac,
341 nonce: &Nonce,
342 recipient_public_key: &PublicKey,
343 sender_secret_key: &SecretKey,
344) -> Result<(), Error> {
345 let mut key = crypto_box_beforenm(recipient_public_key, sender_secret_key);
346
347 crypto_box_open_detached_afternm_inplace(data, mac, nonce, &key)?;
348
349 key.zeroize();
350
351 Ok(())
352}
353
354pub fn crypto_box_open_easy(
359 message: &mut [u8],
360 ciphertext: &[u8],
361 nonce: &Nonce,
362 sender_public_key: &PublicKey,
363 recipient_secret_key: &SecretKey,
364) -> Result<(), Error> {
365 if ciphertext.len() < CRYPTO_BOX_MACBYTES {
366 Err(dryoc_error!(format!(
367 "Impossibly small box ({} < {}",
368 ciphertext.len(),
369 CRYPTO_BOX_MACBYTES
370 )))
371 } else {
372 let (mac, ciphertext) = ciphertext.split_at(CRYPTO_BOX_MACBYTES);
373 let mac = ByteArray::as_array(mac);
374
375 crypto_box_open_detached(
376 message,
377 mac,
378 ciphertext,
379 nonce,
380 sender_public_key,
381 recipient_secret_key,
382 )
383 }
384}
385
386pub fn crypto_box_seal_open(
396 message: &mut [u8],
397 ciphertext: &[u8],
398 recipient_public_key: &PublicKey,
399 recipient_secret_key: &SecretKey,
400) -> Result<(), Error> {
401 if ciphertext.len() < CRYPTO_BOX_SEALBYTES {
402 Err(dryoc_error!(format!(
403 "Impossibly small box ({} < {}",
404 ciphertext.len(),
405 CRYPTO_BOX_SEALBYTES,
406 )))
407 } else if message.len() != ciphertext.len() - CRYPTO_BOX_SEALBYTES {
408 Err(dryoc_error!(format!(
409 "message length invalid ({} != {}",
410 message.len(),
411 ciphertext.len() - CRYPTO_BOX_SEALBYTES,
412 )))
413 } else {
414 let mut nonce = Nonce::new_byte_array();
415 let mut epk = PublicKey::new_byte_array();
416 epk.copy_from_slice(&ciphertext[..CRYPTO_BOX_PUBLICKEYBYTES]);
417
418 crypto_box_seal_nonce(&mut nonce, &epk, recipient_public_key);
419
420 crypto_box_open_easy(
421 message,
422 &ciphertext[CRYPTO_BOX_PUBLICKEYBYTES..],
423 &nonce,
424 &epk,
425 recipient_secret_key,
426 )
427 }
428}
429
430pub fn crypto_box_open_easy_inplace(
443 data: &mut [u8],
444 nonce: &Nonce,
445 sender_public_key: &PublicKey,
446 recipient_secret_key: &SecretKey,
447) -> Result<(), Error> {
448 if data.len() < CRYPTO_BOX_MACBYTES {
449 Err(dryoc_error!(format!(
450 "Impossibly small box ({} < {}",
451 data.len(),
452 CRYPTO_BOX_MACBYTES
453 )))
454 } else {
455 let (mac, d) = data.split_at_mut(CRYPTO_BOX_MACBYTES);
456 let mac = ByteArray::as_array(mac);
457
458 crypto_box_open_detached_inplace(d, mac, nonce, sender_public_key, recipient_secret_key)?;
459
460 data.rotate_left(CRYPTO_BOX_MACBYTES);
461
462 Ok(())
463 }
464}
465
466#[cfg(test)]
467mod tests {
468 use super::*;
469 use crate::rng::*;
470
471 #[test]
472 fn test_crypto_box_easy() {
473 for i in 0..20 {
474 use base64::Engine as _;
475 use base64::engine::general_purpose;
476 use sodiumoxide::crypto::box_;
477 use sodiumoxide::crypto::box_::{Nonce as SONonce, PublicKey, SecretKey};
478
479 let (sender_pk, sender_sk) = crypto_box_keypair();
480 let (recipient_pk, recipient_sk) = crypto_box_keypair();
481 let nonce = Nonce::gen();
482 let words = vec!["hello1".to_string(); i];
483 let message = words.join(" :D ");
484 let mut ciphertext = vec![0u8; message.len() + CRYPTO_BOX_MACBYTES];
485 crypto_box_easy(
486 &mut ciphertext,
487 message.as_bytes(),
488 &nonce,
489 &recipient_pk,
490 &sender_sk,
491 )
492 .expect("encrypt failed");
493
494 let so_ciphertext = box_::seal(
495 message.as_bytes(),
496 &SONonce::from_slice(&nonce).unwrap(),
497 &PublicKey::from_slice(&recipient_pk).unwrap(),
498 &SecretKey::from_slice(&sender_sk).unwrap(),
499 );
500
501 assert_eq!(
502 general_purpose::STANDARD_NO_PAD.encode(&ciphertext),
503 general_purpose::STANDARD_NO_PAD.encode(&so_ciphertext)
504 );
505
506 let mut m = vec![0u8; ciphertext.len() - CRYPTO_BOX_MACBYTES];
507 crypto_box_open_easy(
508 &mut m,
509 ciphertext.as_slice(),
510 &nonce,
511 &sender_pk,
512 &recipient_sk,
513 )
514 .expect("decrypt failed");
515 let so_m = box_::open(
516 ciphertext.as_slice(),
517 &SONonce::from_slice(&nonce).unwrap(),
518 &PublicKey::from_slice(&recipient_pk).unwrap(),
519 &SecretKey::from_slice(&sender_sk).unwrap(),
520 )
521 .unwrap();
522
523 assert_eq!(m, message.as_bytes());
524 assert_eq!(m, so_m);
525 }
526 }
527
528 #[test]
529 fn test_crypto_box_easy_inplace() {
530 for i in 0..20 {
531 use base64::Engine as _;
532 use base64::engine::general_purpose;
533 use sodiumoxide::crypto::box_;
534 use sodiumoxide::crypto::box_::{Nonce as SONonce, PublicKey, SecretKey};
535
536 let (sender_pk, sender_sk) = crypto_box_keypair();
537 let (recipient_pk, recipient_sk) = crypto_box_keypair();
538 let nonce = Nonce::gen();
539 let words = vec!["hello1".to_string(); i];
540 let message: Vec<u8> = words.join(" :D ").as_bytes().to_vec();
541 let message_copy = message.clone();
542
543 let mut ciphertext = message.clone();
544 ciphertext.resize(message.len() + CRYPTO_BOX_MACBYTES, 0);
545 crypto_box_easy_inplace(&mut ciphertext, &nonce, &recipient_pk, &sender_sk)
546 .expect("encrypt failed");
547 let so_ciphertext = box_::seal(
548 message_copy.as_slice(),
549 &SONonce::from_slice(&nonce).unwrap(),
550 &PublicKey::from_slice(&recipient_pk).unwrap(),
551 &SecretKey::from_slice(&sender_sk).unwrap(),
552 );
553
554 assert_eq!(
555 general_purpose::STANDARD_NO_PAD.encode(&ciphertext),
556 general_purpose::STANDARD_NO_PAD.encode(&so_ciphertext)
557 );
558
559 let mut ciphertext_clone = ciphertext.clone();
560 crypto_box_open_easy_inplace(&mut ciphertext_clone, &nonce, &sender_pk, &recipient_sk)
561 .expect("decrypt failed");
562 ciphertext_clone.resize(message.len(), 0);
563
564 let so_m = box_::open(
565 ciphertext.as_slice(),
566 &SONonce::from_slice(&nonce).unwrap(),
567 &PublicKey::from_slice(&recipient_pk).unwrap(),
568 &SecretKey::from_slice(&sender_sk).unwrap(),
569 )
570 .expect("decrypt failed");
571
572 assert_eq!(
573 general_purpose::STANDARD_NO_PAD.encode(&ciphertext_clone),
574 general_purpose::STANDARD_NO_PAD.encode(&message_copy)
575 );
576 assert_eq!(
577 general_purpose::STANDARD_NO_PAD.encode(&so_m),
578 general_purpose::STANDARD_NO_PAD.encode(&message_copy)
579 );
580 }
581 }
582
583 #[test]
584 fn test_crypto_box_easy_invalid() {
585 for _ in 0..20 {
586 let (sender_pk, _sender_sk) = crypto_box_keypair();
587 let (_recipient_pk, recipient_sk) = crypto_box_keypair();
588 let nonce = Nonce::gen();
589
590 let mut ciphertext: Vec<u8> = vec![];
591 let message: Vec<u8> = vec![];
592
593 crypto_box_open_easy(&mut ciphertext, &message, &nonce, &sender_pk, &recipient_sk)
594 .expect_err("expected an error");
595 }
596 }
597 #[test]
598 fn test_crypto_box_easy_inplace_invalid() {
599 for _ in 0..20 {
600 use base64::Engine as _;
601 use base64::engine::general_purpose;
602
603 let (sender_pk, _sender_sk) = crypto_box_keypair();
604 let (_recipient_pk, recipient_sk) = crypto_box_keypair();
605 let nonce = Nonce::gen();
606
607 let mut ciphertext: Vec<u8> = vec![];
608
609 crypto_box_open_easy_inplace(&mut ciphertext, &nonce, &sender_pk, &recipient_sk)
610 .expect_err("expected an error");
611
612 ciphertext.resize(1024, 0);
613 copy_randombytes(ciphertext.as_mut_slice());
614 let ciphertext_copy = ciphertext.clone();
615
616 crypto_box_open_easy_inplace(&mut ciphertext, &nonce, &sender_pk, &recipient_sk)
617 .expect_err("expected an error");
618
619 assert_eq!(ciphertext.len(), ciphertext_copy.len());
620 assert_eq!(
621 general_purpose::STANDARD_NO_PAD.encode(&ciphertext[0..CRYPTO_BOX_MACBYTES]),
622 general_purpose::STANDARD_NO_PAD.encode(&ciphertext_copy[0..CRYPTO_BOX_MACBYTES])
623 );
624 }
625 }
626
627 #[test]
628 fn test_crypto_box_seed_keypair() {
629 use base64::Engine as _;
630 use base64::engine::general_purpose;
631 use sodiumoxide::crypto::box_::{Seed, keypair_from_seed};
632
633 for _ in 0..10 {
634 let seed = randombytes_buf(CRYPTO_BOX_SEEDBYTES);
635
636 let (pk, sk) = crypto_box_seed_keypair(&seed);
637 let (so_pk, so_sk) = keypair_from_seed(&Seed::from_slice(&seed).unwrap());
638
639 assert_eq!(
640 general_purpose::STANDARD_NO_PAD.encode(pk),
641 general_purpose::STANDARD_NO_PAD.encode(so_pk.as_ref())
642 );
643 assert_eq!(
644 general_purpose::STANDARD_NO_PAD.encode(sk),
645 general_purpose::STANDARD_NO_PAD.encode(so_sk.as_ref())
646 );
647 }
648 }
649
650 #[test]
651 fn test_crypto_box_seal() {
652 for i in 0..20 {
653 use sodiumoxide::crypto::box_::{PublicKey, SecretKey};
654 use sodiumoxide::crypto::sealedbox::curve25519blake2bxsalsa20poly1305;
655
656 let (recipient_pk, recipient_sk) = crypto_box_keypair();
657 let words = vec!["hello1".to_string(); i];
658 let message = words.join(" :D ");
659 let mut ciphertext = vec![0u8; message.len() + CRYPTO_BOX_SEALBYTES];
660 crypto_box_seal(&mut ciphertext, message.as_bytes(), &recipient_pk)
661 .expect("encrypt failed");
662
663 let mut m = vec![0u8; ciphertext.len() - CRYPTO_BOX_SEALBYTES];
664 crypto_box_seal_open(&mut m, ciphertext.as_slice(), &recipient_pk, &recipient_sk)
665 .expect("decrypt failed");
666 let so_m = curve25519blake2bxsalsa20poly1305::open(
667 ciphertext.as_slice(),
668 &PublicKey::from_slice(&recipient_pk).unwrap(),
669 &SecretKey::from_slice(&recipient_sk).unwrap(),
670 )
671 .unwrap();
672
673 assert_eq!(m, message.as_bytes());
674 assert_eq!(m, so_m);
675 }
676 }
677
678 #[test]
679 fn test_crypto_box_seal_open() {
680 for i in 0..20 {
681 use sodiumoxide::crypto::box_::{PublicKey, SecretKey};
682 use sodiumoxide::crypto::sealedbox::curve25519blake2bxsalsa20poly1305;
683
684 let (recipient_pk, recipient_sk) = crypto_box_keypair();
685 let words = vec!["hello1".to_string(); i];
686 let message = words.join(" :D ");
687 let so_ciphertext = curve25519blake2bxsalsa20poly1305::seal(
688 message.as_bytes(),
689 &PublicKey::from_slice(&recipient_pk).unwrap(),
690 );
691
692 let mut m = vec![0u8; so_ciphertext.len() - CRYPTO_BOX_SEALBYTES];
693 crypto_box_seal_open(
694 &mut m,
695 so_ciphertext.as_slice(),
696 &recipient_pk,
697 &recipient_sk,
698 )
699 .expect("decrypt failed");
700 let so_m = curve25519blake2bxsalsa20poly1305::open(
701 so_ciphertext.as_slice(),
702 &PublicKey::from_slice(&recipient_pk).unwrap(),
703 &SecretKey::from_slice(&recipient_sk).unwrap(),
704 )
705 .unwrap();
706
707 assert_eq!(m, message.as_bytes());
708 assert_eq!(m, so_m);
709 }
710 }
711}