1#![forbid(unsafe_code)]
2#![warn(missing_docs, unused_qualifications)]
3#![cfg_attr(docs_rs, feature(doc_cfg))]
4#![no_std]
5
6use rand_core::RngCore;
84use chacha20poly1305::{XChaCha20Poly1305, XNonce, Key, Tag};
85use chacha20poly1305::aead::{NewAead, AeadInPlace};
86use zeroize::Zeroizing;
87use core::convert::{TryFrom, TryInto};
88use core::usize;
89
90#[cfg(feature = "alloc")]
91extern crate alloc;
92#[cfg(feature = "alloc")]
93use alloc::vec::Vec;
94
95pub const MAX_DATA_SIZE: usize = 8;
97pub const NONCE_SIZE: usize = 24;
99pub const TAG_SIZE: usize = 16;
101pub const KEY_SIZE: usize = 32;
103pub const PREFIX_SIZE: usize = NONCE_SIZE + TAG_SIZE;
105
106#[derive(Debug)]
108pub enum PrivateBoxError {
109 Cryptography,
111 UnrecognizedFormat,
113 MessageTooLarge,
115 HeaderTooLarge,
117}
118
119#[derive(Debug)]
120struct PrivateBoxDataSizes {
121 header_size: usize,
122 message_size: usize,
123}
124impl PrivateBoxDataSizes {
125 const SIZE: usize = MAX_DATA_SIZE + MAX_DATA_SIZE;
126
127 fn new (header_size: usize, message_size: usize) -> Self {
128 PrivateBoxDataSizes { header_size, message_size }
129 }
130
131 fn header_size(&self) -> usize {
132 self.header_size
133 }
134
135 fn message_size(&self) -> usize {
136 self.message_size
137 }
138
139 fn serialize(&self) -> [u8; Self::SIZE] {
140 let mut buf = [0u8; Self::SIZE];
141 self.serialize_into(&mut buf);
142 buf
143 }
144
145 fn serialize_into(&self, buf: &mut [u8; Self::SIZE]) {
146 let header = u64::try_from(self.header_size).expect("Header too large").to_be_bytes();
147 let message = u64::try_from(self.message_size).expect("Message too large").to_be_bytes();
148 buf[..MAX_DATA_SIZE].copy_from_slice(&header);
149 buf[MAX_DATA_SIZE..Self::SIZE].copy_from_slice(&message);
150 }
151
152 fn deserialize(start: &[u8]) -> Result<Self, PrivateBoxError> {
153 if start.len() < Self::SIZE {
154 return Err(PrivateBoxError::UnrecognizedFormat);
155 }
156
157 let mut header_size = [0u8; MAX_DATA_SIZE];
158 header_size.copy_from_slice(&start[..MAX_DATA_SIZE]);
159 let header_size = u64::from_be_bytes(header_size)
160 .try_into()
161 .map_err(|_| PrivateBoxError::HeaderTooLarge)?;
162
163 let mut message_size = [0u8; MAX_DATA_SIZE];
164 message_size.copy_from_slice(&start[MAX_DATA_SIZE..Self::SIZE]);
165 let message_size = u64::from_be_bytes(message_size)
166 .try_into()
167 .map_err(|_| PrivateBoxError::MessageTooLarge)?;
168
169 Ok(PrivateBoxDataSizes { header_size, message_size })
170 }
171}
172
173#[derive(Debug)]
174struct PrivateBoxPrefix {
175 nonce: XNonce,
176 tag: Tag,
177}
178impl PrivateBoxPrefix {
179 const SIZE: usize = PREFIX_SIZE;
180
181 fn new (nonce: XNonce, tag: Tag) -> Self {
182 PrivateBoxPrefix { nonce, tag }
183 }
184
185 fn nonce(&self) -> &XNonce {
186 &self.nonce
187 }
188
189 fn tag(&self) -> &Tag {
190 &self.tag
191 }
192
193 fn serialize(&self) -> [u8; Self::SIZE] {
194 let mut buf = [0u8; Self::SIZE];
195 self.serialize_into(&mut buf);
196 buf
197 }
198
199 fn serialize_into(&self, buf: &mut [u8]) {
200 debug_assert!(buf.len() >= Self::SIZE);
201
202 buf[..NONCE_SIZE].copy_from_slice(&self.nonce);
203 buf[NONCE_SIZE..].copy_from_slice(&self.tag);
204 }
205
206 fn deserialize(start: &[u8]) -> Result<Self, PrivateBoxError> {
207 if start.len() < Self::SIZE {
208 return Err(PrivateBoxError::UnrecognizedFormat)
209 }
210
211 let nonce = *XNonce::from_slice(&start[..NONCE_SIZE]);
212
213 let tag = *Tag::from_slice(&start[NONCE_SIZE..PrivateBoxPrefix::SIZE]);
214
215 Ok(PrivateBoxPrefix {
216 nonce,
217 tag
218 })
219 }
220}
221
222pub struct PrivateBox<T: RngCore> {
224 key: Zeroizing<[u8; KEY_SIZE]>,
225 rng: T,
226}
227impl<T: RngCore> PrivateBox<T> {
268 pub fn new(key: &[u8; 32], rng: T) -> Self {
285 let mut k = [0u8; KEY_SIZE];
286 k.copy_from_slice(key);
287
288 let key = Zeroizing::new(k);
289
290 PrivateBox {
291 key,
292 rng
293 }
294 }
295
296 pub fn encrypt_detached(&mut self, data: &mut [u8], assoc_data: &[u8]) -> Result<[u8; PREFIX_SIZE], PrivateBoxError> {
323 let mut nonce = [0_u8; NONCE_SIZE];
324 self.rng.fill_bytes(&mut nonce);
325 let nonce = XNonce::from_slice(&nonce);
326
327 let key = Key::from_slice(self.key.as_ref());
328 let aead = XChaCha20Poly1305::new(key);
329
330 let tag: Tag = aead
331 .encrypt_in_place_detached(nonce, assoc_data, data)
332 .map_err(|_| PrivateBoxError::Cryptography)?;
333
334
335 let prefix = PrivateBoxPrefix::new(*nonce, tag).serialize();
336
337 Ok(prefix)
338 }
339
340 pub fn decrypt_detached(&self, message: &mut [u8], assoc_data: &[u8], detached_prefix: &[u8; PREFIX_SIZE]) -> Result<(), PrivateBoxError> {
366 let detached_prefix = PrivateBoxPrefix::deserialize(detached_prefix)?;
367
368 self.decrypt_detached_parsed(message, assoc_data, &detached_prefix)?;
369 Ok(())
370 }
371
372 fn decrypt_detached_parsed(&self, message: &mut [u8], assoc_data: &[u8], detached_prefix: &PrivateBoxPrefix) -> Result<(), PrivateBoxError> {
373 let key = Key::from_slice(self.key.as_ref());
374 let aead = XChaCha20Poly1305::new(key);
375
376 aead.decrypt_in_place_detached(detached_prefix.nonce(), assoc_data, message, detached_prefix.tag())
377 .map_err(|_| PrivateBoxError::Cryptography)?;
378
379 Ok(())
380 }
381
382 #[cfg(feature = "alloc")]
405 #[cfg_attr(docs_rs, doc(cfg(any(feature = "alloc"))))]
406 pub fn encrypt(&mut self, message: &[u8], header: &[u8], metadata: &[u8]) -> Result<Vec<u8>, PrivateBoxError> {
407 let sizes = PrivateBoxDataSizes::new(header.len(), message.len());
408
409 let mut container = Vec::with_capacity(PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE + sizes.message_size() + sizes.header_size());
410 container.extend_from_slice(&[0; PrivateBoxPrefix::SIZE]);
411 container.extend_from_slice(&sizes.serialize());
412 container.extend_from_slice(header);
413 container.extend_from_slice(message);
414
415 let body = &mut container[PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE + sizes.header_size()..];
416
417 let assoc_data = [header, metadata].concat();
418
419 let detached_prefix = self.encrypt_detached(body, &assoc_data)?;
420
421 container[..PrivateBoxPrefix::SIZE].copy_from_slice(&detached_prefix);
422
423 Ok(container)
424 }
425
426 #[cfg(feature = "alloc")]
456 #[cfg_attr(docs_rs, doc(cfg(any(feature = "alloc"))))]
457 pub fn decrypt(&self, container: &[u8], metadata: &[u8]) -> Result<(Vec<u8>, Vec<u8>), PrivateBoxError> {
458 if container.len() < PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE {
459 return Err(PrivateBoxError::UnrecognizedFormat)
460 }
461
462 let sizes = PrivateBoxDataSizes::deserialize(&container[PrivateBoxPrefix::SIZE..])?;
463 if container.len() < PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE + sizes.message_size() + sizes.header_size() {
464 return Err(PrivateBoxError::UnrecognizedFormat)
465 }
466
467 let prefix = PrivateBoxPrefix::deserialize(&container)?;
468 let header_data = &container[PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE..PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE + sizes.header_size()];
469
470 let mut message = Vec::with_capacity(sizes.message_size());
471
472 message.extend_from_slice(&container[
473 PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE + sizes.header_size()
474 ..
475 PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE + sizes.header_size() + sizes.message_size()
476 ]);
477
478 let assoc_data = [header_data, metadata].concat();
479 self.decrypt_detached_parsed(&mut message, &assoc_data, &prefix)?;
480
481 let mut header = Vec::with_capacity(sizes.message_size());
482 header.extend_from_slice(&header_data);
483
484 Ok((message, header))
485 }
486
487 #[cfg(feature = "alloc")]
512 #[cfg_attr(docs_rs, doc(cfg(any(feature = "alloc"))))]
513 pub fn parse_insecure_header(&self, container: &[u8]) -> Result<Vec<u8>, PrivateBoxError> {
514 if container.len() < PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE {
515 return Err(PrivateBoxError::UnrecognizedFormat)
516 }
517
518 let sizes = PrivateBoxDataSizes::deserialize(&container[PrivateBoxPrefix::SIZE..])?;
519
520 if container.len() < PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE + sizes.header_size() {
521 return Err(PrivateBoxError::UnrecognizedFormat)
522 }
523
524 let header = &container[
525 PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE
526 ..
527 PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE + sizes.header_size()
528 ];
529 Ok(header.to_vec())
530 }
531}
532
533#[cfg(test)]
534mod tests {
535 use super::*;
536
537 use rand::rngs::StdRng;
538 use rand::SeedableRng;
539
540 use crate::tests::alloc::borrow::ToOwned;
541 extern crate std;
542
543 #[test]
544 fn datasizes_new() {
545 let message_size = std::usize::MAX;
546 let header_size = std::usize::MAX;
547
548 let sizes = PrivateBoxDataSizes { message_size, header_size };
549
550 assert_eq!(message_size, sizes.message_size());
551 assert_eq!(header_size, sizes.header_size());
552 }
553
554 #[test]
555 fn datasizes_serialize() {
556 let message_size = 10;
557 let header_size = 50;
558
559 let sizes = PrivateBoxDataSizes::new(header_size, message_size);
560
561 let sizes = sizes.serialize();
562
563 assert_eq!(sizes[..MAX_DATA_SIZE], [0, 0, 0, 0, 0, 0, 0, 50]);
565 assert_eq!(sizes[MAX_DATA_SIZE..], [0, 0, 0, 0, 0, 0, 0, 10])
567 }
568
569 #[test]
570 fn datasizes_deserialize() {
571 let sizes = [0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 10, 5];
573 let deserialized = PrivateBoxDataSizes::deserialize(&sizes).expect("Data sizes");
574 assert_eq!(10, deserialized.message_size());
575 assert_eq!(50, deserialized.header_size());
576
577 PrivateBoxDataSizes::deserialize(&sizes[..sizes.len() - 2]).expect_err("Too short");
578 }
579
580 #[test]
581 fn prefix_new() {
582 let nonce = *XNonce::from_slice(&[2; NONCE_SIZE]);
583 let tag = *Tag::from_slice(&[1u8; TAG_SIZE]);
587
588 let prefix = PrivateBoxPrefix::new(nonce, tag);
589
590 assert_eq!(nonce, *prefix.nonce());
591 assert_eq!(tag, *prefix.tag());
592 }
593
594 #[test]
595 fn prefix_serialize() {
596 let nonce = *XNonce::from_slice(&[2; NONCE_SIZE]);
597 let tag = *Tag::from_slice(&[1u8; TAG_SIZE]);
601
602 let prefix = PrivateBoxPrefix::new(nonce, tag);
603
604 assert_eq!(
605 prefix.serialize()[..],
606 [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
607 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1][..]
608 )
609 }
610
611 #[test]
612 fn prefix_deserialize() {
613 let nonce = *XNonce::from_slice(&[2; NONCE_SIZE]);
614 let tag = *Tag::from_slice(&[1u8; TAG_SIZE]);
618
619 let prefix = PrivateBoxPrefix::new(nonce, tag);
620
621 let prefix_serialized = prefix.serialize();
622 let deserialized = PrivateBoxPrefix::deserialize(&prefix_serialized).expect("Deserialized container's prefix");
623
624 assert_eq!(nonce, *deserialized.nonce());
626 assert_eq!(tag, *deserialized.tag());
627
628 match PrivateBoxPrefix::deserialize(&prefix_serialized[..PrivateBoxPrefix::SIZE - 1]) {
630 Err(err) => match err {
631 PrivateBoxError::UnrecognizedFormat => (),
632 _ => panic!("Invalid error"),
633 },
634 Ok(_) => panic!("Header should not be parsed"),
635 };
636 }
637
638 #[test]
639 fn privatebox_new() {
640 PrivateBox::new(&[1; KEY_SIZE], StdRng::from_seed([1;32]));
641 }
642
643 #[test]
644 fn privatebox_encrypt_detached() {
645 let rng = StdRng::from_seed([1;32]);
646
647 let mut privatebox = PrivateBox::new(&[1; KEY_SIZE], rng);
648
649 let mut message = b"hello world".to_owned();
650 let assoc_data = &[0u8; 4];
651
652 let detached_prefix = privatebox.encrypt_detached(&mut message, assoc_data).unwrap();
653
654 assert_eq!(
656 &detached_prefix[..],
657 &[
658 51, 1, 232, 215, 231, 84, 219, 44, 245, 123, 10, 76, 167, 63, 37, 60, 112, 83, 173, 43, 197, 57, 135, 119,
659 143, 136, 250, 191, 142, 138, 145, 172, 115, 135, 63, 49, 23, 160, 223, 51
660 ][..]
661 );
662
663 assert_eq!(
665 &message,
666 &[60, 176, 58, 81, 122, 113, 92, 185, 227, 116, 233]
667 );
668
669 assert_eq!(
671 &assoc_data[..],
672 &[0u8; 4]
673 )
674 }
675
676 #[test]
677 fn privatebox_decrypt_detached() {
678 let rng = StdRng::from_seed([1;32]);
679 let privatebox = PrivateBox::new(&[1; KEY_SIZE], rng);
680
681 let detached_prefix = [
682 51, 1, 232, 215, 231, 84, 219, 44, 245, 123, 10, 76, 167, 63, 37, 60, 112, 83, 173, 43, 197, 57, 135, 119,
683 143, 136, 250, 191, 142, 138, 145, 172, 115, 135, 63, 49, 23, 160, 223, 51
684 ];
685
686 let mut data = [60, 176, 58, 81, 122, 113, 92, 185, 227, 116, 233];
687
688 let assoc_data = [0, 0, 0, 0];
689
690 privatebox.decrypt_detached(&mut data, &assoc_data, &detached_prefix)
691 .expect("Decrypted data");
692
693 assert_eq!(&data, b"hello world");
694
695 privatebox.decrypt_detached(&mut data, &[0], &detached_prefix)
696 .expect_err("Bad associated data");
697 }
698
699 #[test]
700 fn privatebox_encrypt_decrypt() {
701 let mut privatebox = PrivateBox::new(&[1;32], StdRng::from_seed([1; 32]));
702
703 let mut message = *b"secret data";
704 let assoc_data = *b"plain text";
705
706 let detached_prefix = privatebox.encrypt_detached(&mut message, &assoc_data).expect("encrypt");
707 assert_ne!(&message, b"secret data");
708
709 privatebox.decrypt_detached(&mut message, &assoc_data, &detached_prefix).expect("decrypt");
710 assert_eq!(&message, b"secret data");
711 }
712
713 #[test]
714 fn privatebox_wrap() {
715 let mut privatebox = PrivateBox::new(&[1; 32], StdRng::from_seed([1;32]));
716 let message = b"data".to_owned();
717
718 let header = &[1; 4];
719 let metadata = &[0; 4];
720
721 let container = privatebox.encrypt(b"data", header, metadata).expect("Wrapped container");
722
723 let sizes = PrivateBoxDataSizes::deserialize(&container[PrivateBoxPrefix::SIZE..]).expect("Message size");
725 assert_eq!(message.len(), sizes.message_size());
726 assert_eq!(header.len(), sizes.header_size());
727
728 assert_eq!(container[container.len() - message.len()..], [48, 180, 34, 92]);
730
731 assert_eq!(container[PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE..PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE + header.len()], [1, 1, 1, 1]);
733
734 let prefix = PrivateBoxPrefix::deserialize(&container).expect("Deserialized prefix");
736
737 let mut data = b"data".to_owned();
738 let assoc_data = &[1,1,1,1,0,0,0,0];
739 let mut privatebox = PrivateBox::new(&[1; 32], StdRng::from_seed([1;32]));
740 let detached_prefix = privatebox.encrypt_detached(&mut data, assoc_data).expect("Encrypted data");
741 let detached_prefix = PrivateBoxPrefix::deserialize(&detached_prefix).expect("Detached prefix");
742
743 assert_eq!(prefix.tag(), detached_prefix.tag());
744 }
745
746 #[test]
747 fn privatebox_wrap_unwrap() {
748 let mut privatebox = PrivateBox::new(&[1; 32], StdRng::from_seed([1; 32]));
749 let wrapped = privatebox.encrypt(b"secret data", &[5, 4, 3, 2], &[]).expect("Wrapped container");
750 let (message1, header1) = privatebox.decrypt(&wrapped, &[]).expect("Unwrapped container");
751
752 assert_eq!(message1, b"secret data");
753 assert_eq!(header1, &[5, 4, 3, 2]);
754
755 let container2 = privatebox.encrypt(b"secret data", &[5, 4, 3, 2], &[3, 2, 1]).expect("Wrapped container");
756 let (message2, header2) = privatebox.decrypt(&container2, &[3, 2, 1]).expect("Unwrapped container");
757
758 assert_eq!(
759 message1,
760 message2
761 );
762
763 assert_eq!(
764 header1,
765 header2
766 );
767 }
768
769 #[test]
770 fn privatebox_wrap_unwrap_corrupted() {
771 let mut privatebox = PrivateBox::new(&[1; 32], StdRng::from_seed([1; 32]));
772 let mut wrapped = privatebox.encrypt(b"data", &[], &[]).expect("Wrapped container");
773
774 let last = wrapped.len() - 1;
775 wrapped[last] = wrapped[last] + 1;
776
777 privatebox.decrypt(&wrapped, &[]).expect_err("Unwrapped container");
778 }
779
780 #[test]
781 fn privatebox_unwrap_larger_ok() {
782 let mut privatebox = PrivateBox::new(&[1; 32], StdRng::from_seed([1; 32]));
783 let mut wrapped = privatebox.encrypt(b"data", &[3, 2, 1], &[4, 3, 2]).expect("Wrapped container");
784
785 wrapped.push(0);
786 let (data, header) = privatebox.decrypt(&wrapped, &[4, 3, 2]).expect("Unwrapped container");
787
788 assert_eq!(data, b"data");
789 assert_eq!(header, &[3, 2, 1])
790 }
791
792 #[test]
793 fn privatebox_unwrap_short_bad() {
794 let mut privatebox = PrivateBox::new(&[1; 32], StdRng::from_seed([1; 32]));
795 let mut wrapped = privatebox.encrypt(b"data", &[1u8; 54], &[1u8; 38]).expect("Wrapped container");
796
797 wrapped.pop();
798 privatebox.decrypt(&wrapped, &[1u8; 38]).expect_err("Too short");
799 }
800
801 #[test]
802 fn privatebox_decrypt_wrong_sizes() {
803 let privatebox = PrivateBox::new(&[1; 32], StdRng::from_seed([1; 32]));
804
805 let detached_prefix = [
806 51, 1, 232, 215, 231, 84, 219, 44, 245, 123, 10, 76, 167, 63, 37, 60, 112, 83, 173, 43, 197, 57, 135, 119,
807 143, 136, 250, 191, 142, 138, 145, 172, 115, 135, 63, 49, 23, 160, 223, 51
808 ];
809
810 let mut data = [60, 176, 58, 81, 122, 113, 92, 185, 227, 116, 233];
811
812 let assoc_data = [0, 0, 0, 0];
813
814 privatebox.decrypt_detached(&mut data, &assoc_data, &detached_prefix).expect("Decrypted data data");
815 assert_eq!(&data, b"hello world");
816
817 privatebox
818 .decrypt_detached(&mut data[..4], &assoc_data, &detached_prefix)
819 .expect_err("Corrupted sizes");
820 }
821
822 #[test]
823 fn privatebox_header() {
824 let mut privatebox = PrivateBox::new(&[1; 32], StdRng::from_seed([1; 32]));
825
826 let header = &[1, 2, 3, 4];
827
828 let container = privatebox.encrypt(&*b"data", header, &[]).expect("encrypted data");
829
830 let parse_header = privatebox.parse_insecure_header(&container).expect("header");
831
832 assert_eq!(&parse_header, header);
833 }
834
835 #[test]
836 fn readme_test() {
837 let mut privatebox = PrivateBox::new(&[1; 32], StdRng::from_seed([1u8; 32]));
838 let header = &[5, 4, 3, 2];
839 let metadata = &[3, 3, 3];
840 let wrapped = privatebox.encrypt(b"secret data", header, metadata).expect("encrypt");
841 let (message, authenticated_header) = privatebox.decrypt(&wrapped, metadata).expect("decrypt");
842
843 assert_eq!(message, b"secret data");
844 assert_eq!(&authenticated_header, header);
845 }
846}