privatebox/
lib.rs

1#![forbid(unsafe_code)]
2#![warn(missing_docs, unused_qualifications)]
3#![cfg_attr(docs_rs, feature(doc_cfg))]
4#![no_std]
5
6//! # PrivateBox
7//!
8//! PrivateBox provides a small and easy to use API to encrypt your data.
9//! It is meant to do one thing, be a simple wrapper and validator around the RustCrypto XChaCha20Poly1305 AEAD encryption algorithm.
10//!
11//! PrivateBox is inspired/based off of [Cocoon](https://github.com/fadeevab/cocoon/blob/master/README.md).
12//! PrivateBox is meant to be a smaller API, more flexible with associated data, and uses XChaCha for random nonces.
13//! ## Generating a key
14//!
15//! The examples just use array generation for the key to keep the code duplication down. However, keys should be random or pseudo-random (aka derived from something like a password).
16//!
17//! Example:
18//!
19//! ```
20//! use rand_core::{OsRng, RngCore};
21//!
22//! let mut key = [0u8; 32];
23//! OsRng.fill_bytes(&mut key);
24//! ```
25//!
26//! ## Detached Encryption/Decryption
27//!
28//! The [`PrivateBox::encrypt_detached`]/[`PrivateBox::decrypt_detached`] methods compute in place to avoid re-allocations.
29//! It returns a prefix (the nonce and tag) that is used for decryption.
30//! This is suitable for a `no_std` build, when you want to avoid re-allocations of data,
31//! and if you want to manage serialization yourself.
32//!
33//! Example:
34//!
35//! ```
36//! # use privatebox::{PrivateBox, PrivateBoxError};
37//! # use rand_core::OsRng;
38//! #
39//! # fn main() -> Result<(), PrivateBoxError> {
40//! let mut privatebox = PrivateBox::new(&[1;32], OsRng); 
41//!
42//! let mut message = *b"secret data";
43//! let assoc_data = *b"plain text";
44//!
45//! let detached_prefix = privatebox.encrypt_detached(&mut message, &assoc_data)?;
46//! assert_ne!(&message, b"secret data");
47//!
48//! privatebox.decrypt_detached(&mut message, &assoc_data, &detached_prefix)?;
49//! assert_eq!(&message, b"secret data");
50//! # Ok(())
51//! # }
52//! ```
53//!
54//! ## PrivateBox Container
55//! 
56//! The [`PrivateBox::encrypt`]/[`PrivateBox::decrypt`] methods handle serialization for you and returns a container.
57//! It enables the use of both attached associated data and detached associated data.
58//! It is much simpler to use than detached encryption/decryption.
59//! It uses the `alloc` feature (enabled by default).
60//! 
61//! Example:
62//! 
63//! ```
64//! # use privatebox::{PrivateBox, PrivateBoxError};
65//! # use rand_core::OsRng;
66//! #
67//! # fn main() -> Result<(), PrivateBoxError> {
68//! let mut privatebox = PrivateBox::new(&[1; 32], OsRng);
69//! 
70//! let header = &[5, 4, 3, 2];
71//! let metadata = &[3, 3, 3];
72//! 
73//! let wrapped = privatebox.encrypt(b"secret data", header, metadata).expect("encrypt");
74//! let (message, authenticated_header) = privatebox.decrypt(&wrapped, metadata).expect("decrypt");
75//! 
76//! assert_eq!(message, b"secret data");
77//! assert_eq!(&authenticated_header, header);
78//! # Ok(())
79//! # }
80//! ```
81//! 
82
83use 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
95/// Max size of message and header byte array
96pub const MAX_DATA_SIZE: usize = 8;
97/// Size of XChaCha nonce
98pub const NONCE_SIZE: usize = 24;
99/// Size of authentication tag
100pub const TAG_SIZE: usize = 16;
101/// Size of encryption key
102pub const KEY_SIZE: usize = 32;
103/// Size of detached prefix
104pub const PREFIX_SIZE: usize = NONCE_SIZE + TAG_SIZE;
105
106/// Error variants provided by the PrivateBox API
107#[derive(Debug)]
108pub enum PrivateBoxError {
109    /// Cryptographic error. Integrity is compromised
110    Cryptography,
111    /// Format is corrupted
112    UnrecognizedFormat,
113    /// Message size is too large to be processed by architecture
114    MessageTooLarge,
115    /// Header size is too large to be processed by architecture
116    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
222/// A wrapper around XChaChaPoly1305 for convenient encryption
223pub struct PrivateBox<T: RngCore> {
224    key: Zeroizing<[u8; KEY_SIZE]>,
225    rng: T,
226}
227/// Generates basic containers that store encrypted data
228///
229/// # Basic Usage
230/// ```
231/// # use privatebox::{PrivateBox, PrivateBoxError};
232/// # use rand_core::OsRng;
233/// #
234/// # fn main() -> Result<(), PrivateBoxError> {
235/// let mut privatebox = PrivateBox::new(b"0123456789abcdef0123456789abcdef", OsRng);
236/// let header = b"stored plain text";
237/// let metadata = b"plain text";
238///
239/// let container = privatebox.encrypt(b"secret data", &*header, &*metadata)?;
240/// assert_ne!(&container, b"secret data");
241///
242/// let (decrypted_message, authenticated_header) = privatebox.decrypt(&container, &*metadata)?;
243/// assert_eq!(decrypted_message, b"secret data");
244/// assert_eq!(authenticated_header, b"stored plain text");
245/// # Ok(())
246/// # }
247/// ```
248///
249/// # Associated Data
250/// Associated data in an AEAD is data that is authenticated but not encrypted.
251/// It is provided during the encryption and decryption stage. It does not
252/// necessarily have to be stored with the ciphertext. Hence [`PrivateBox::encrypt`]
253/// has an authenticated `header` (stored in container) and `metadata` (stored separately).
254/// The metadata thus is provided separately from the container during [`PrivateBox::decrypt`]. When doing
255/// detached encryption/decryption there is just `assoc_data` as storage is handled
256/// by user. For use cases check out this [stackexchange answer](https://security.stackexchange.com/questions/179273/what-is-the-purpose-of-associated-authenticated-data-in-aead#:~:text=As%20a%20very%20general%20rule,can%20be%20detected%20and%20rejected.)
257///
258/// # Nonces
259/// Nonces are arbitrary numbers used in encryption and are one time use per key.
260/// PrivateBox uses XChaChaPoly1305 which is ChaChaPoly1305 with an extended nonce (24 bytes instead of 12).
261/// Therefore it is OK ([libsodium ref](https://doc.libsodium.org/secret-key_cryptography/aead/chacha20-poly1305/xchacha20-poly1305_construction)) to use a random number generator for nonce generation.
262/// The random number generator provided upon the creation of PrivateBox is used to generate nonces.
263/// The generator is not cloned during encryption so each pass produces a different nonce.
264///
265/// # Features
266/// Enabling `alloc` (on by default) lets you access [`PrivateBox::encrypt`] and [`PrivateBox::decrypt`]
267impl<T: RngCore> PrivateBox<T> {
268    /// Creates a new [`PrivateBox`]  with a symmetric key and a random number generator
269    ///
270    /// * `key` - a 32 byte symmetric key
271    /// * `rng` - a random number generator that generates nonces, implements [`RngCore`]
272    ///
273    /// # Examples
274    /// ```
275    /// use privatebox::PrivateBox;
276    /// use rand_core::{RngCore, OsRng};
277    ///
278    /// // Key must have a length of 32 bytes.
279    /// let mut key = [0u8; 32];
280    /// OsRng.fill_bytes(&mut key);
281    ///
282    /// let privatebox = PrivateBox::new(&key, OsRng);
283    /// ```
284    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    /// Encrypts message in place with associated data and returns a detached prefix for the data.
297    ///
298    /// * `message` - data to be encrypted in place
299    /// * `assoc_data` - associated data to be used
300    ///
301    /// The prefix is needed to decrypt the data with [`PrivateBox::decrypt`]
302    /// The prefix is an array of bytes with nonce first, tag second.
303    ///
304    /// This method does not use memory allocation and suitable in the build without [`alloc`]
305    ///
306    /// # Examples
307    /// ```
308    /// # use privatebox::{PrivateBox, PrivateBoxError};
309    /// # use rand_core::OsRng;
310    /// #
311    /// # fn main() -> Result<(), PrivateBoxError> {
312    /// let mut privatebox = PrivateBox::new(&[1;32], OsRng); 
313    ///
314    /// let mut message = *b"secret data";
315    /// let assoc_data = *b"plain text";
316    ///
317    /// let detached_prefix = privatebox.encrypt_detached(&mut message, &assoc_data);
318    /// assert_ne!(&message, b"secret data");
319    /// # Ok(())
320    /// # }
321    /// ```
322    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    /// Decrypts message in place using associated data and prefix returned by the [`PrivateBox::encrypt`] method.
341    ///
342    /// * `message` - data to be encrypted in place
343    /// * `assoc_data` - associated data to be used in decryption
344    ///
345    /// The method doesn't use memory allocation and is suitable in the build without [`alloc`]
346    ///
347    /// # Examples
348    /// ```
349    /// # use privatebox::{PrivateBox, PrivateBoxError};
350    /// # use rand_core::OsRng;
351    /// #
352    /// # fn main() -> Result<(), PrivateBoxError> {
353    /// let mut privatebox = PrivateBox::new(&[1;32], OsRng); 
354    ///
355    /// let mut message = *b"secret data";
356    ///
357    /// let detached_prefix = privatebox.encrypt_detached(&mut message, &[])?;
358    /// assert_ne!(&message, b"secret data");
359    ///
360    /// privatebox.decrypt_detached(&mut message, &[], &detached_prefix)?;
361    /// assert_eq!(&message, b"secret data");
362    /// # Ok(())
363    /// # }
364    /// ```
365    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    /// Encrypts message and outputs a container with all necessary data to decrypt
383    ///
384    /// * `message` - data to be encrypted
385    /// * `header` - data to be authenticated and stored in the container
386    /// * `metadata` - data to be authenticated but not stored
387    ///
388    /// # Examples
389    /// ```
390    /// # use privatebox::{PrivateBox, PrivateBoxError};
391    /// # use rand_core::OsRng;
392    /// #
393    /// # fn main() -> Result<(), PrivateBoxError> {
394    /// let mut privatebox = PrivateBox::new(&[1;32], OsRng); 
395    ///
396    /// let message = *b"secret data";
397    /// let header = *b"attached data";
398    /// let metadata = *b"detached data";
399    ///
400    /// let container = privatebox.encrypt(&message, &header, &metadata)?;
401    /// # Ok(())
402    /// # }
403    /// ```
404    #[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    /// Decrypts a container and outputs the authenticated header and decrypted message
427    ///
428    /// During decryption the header and provided `metadata` is concatenated to produce the
429    /// full associated data. Successful decryption means that the provided metadata was authenticated.
430    ///
431    /// * `container` - the container outputed by [`PrivateBox::encrypt`]
432    /// * `metadata` - authenticated data not stored in the container
433    ///
434    /// # Examples
435    /// ```
436    /// # use privatebox::{PrivateBox, PrivateBoxError};
437    /// # use rand_core::OsRng;
438    /// #
439    /// # fn main() -> Result<(), PrivateBoxError> {
440    /// let mut privatebox = PrivateBox::new(&[1;32], OsRng); 
441    ///
442    /// let message = *b"secret data";
443    /// let header = *b"attached data";
444    /// let metadata = *b"detached data";
445    ///
446    /// let container = privatebox.encrypt(&message, &header, &metadata)?;
447    ///
448    /// // Note only the metadata is required for decryption
449    /// let (decrypted_message, authenticated_header) = privatebox.decrypt(&container, &metadata)?;
450    /// assert_eq!(&decrypted_message, &message);
451    /// assert_eq!(&authenticated_header, &header);
452    /// # Ok(())
453    /// # }
454    /// ```
455    #[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    /// Retrieve the insecure header data from a container
488    ///
489    /// * `container` - container outputted by [`PrivateBox::encrypt`]
490    ///
491    /// The header data is not authenticated, it is insecure.
492    /// It may have been altered so use at your own risk.
493    ///
494    /// Examples
495    /// ```
496    /// # use privatebox::{PrivateBox, PrivateBoxError};
497    /// # use rand_core::OsRng;
498    /// #
499    /// # fn main() -> Result<(), PrivateBoxError> {
500    /// let mut privatebox = PrivateBox::new(&[1;32], OsRng); 
501    /// let header = &[4, 4, 1, 1];
502    ///
503    /// let container = privatebox.encrypt(&*b"data", header, &[])?;
504    /// let insecure_header = privatebox.parse_insecure_header(&container)?;
505    ///
506    /// // In this case header and insecure header are the same (but not guranteed)
507    /// assert_eq!(&insecure_header, header);
508    /// # Ok(())
509    /// # }
510    /// ```
511    #[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        // header size
564        assert_eq!(sizes[..MAX_DATA_SIZE], [0, 0, 0, 0, 0, 0, 0, 50]);
565        // data size
566        assert_eq!(sizes[MAX_DATA_SIZE..], [0, 0, 0, 0, 0, 0, 0, 10])
567    }
568
569    #[test]
570    fn datasizes_deserialize() {
571        // Test a long array
572        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 data_size = 50;
584        // let header = PrivateBoxHeader::new(nonce, data_size);
585
586        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 data_size = core::usize::MAX;
598        // let header = PrivateBoxHeader::new(nonce, data_size);
599
600        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 data_size = 50;
615        // let header = PrivateBoxHeader::new(nonce, data_size);
616
617        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        // Good deserialize
625        assert_eq!(nonce, *deserialized.nonce());
626        assert_eq!(tag, *deserialized.tag());
627
628        // Corrupted deserialize, not correct size
629        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        // nonce | data_size | tag
655        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        // data
664        assert_eq!(
665            &message,
666            &[60, 176, 58, 81, 122, 113, 92, 185, 227, 116, 233]
667        );
668
669        // assoc_data
670        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        // Data sizes attached correctly
724        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        // Data encrypted
729        assert_eq!(container[container.len() - message.len()..], [48, 180, 34, 92]);
730
731        // Header data attached
732        assert_eq!(container[PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE..PrivateBoxPrefix::SIZE + PrivateBoxDataSizes::SIZE + header.len()], [1, 1, 1, 1]);
733
734        // Check tag (header data and metadata combined correctly)
735        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}