fog_crypto/lockbox.rs
1//! Encrypted data.
2//!
3//! This submodule provides "lockboxes", which are byte sequences holding encrypted information.
4//! There are 4 different types of lockboxes:
5//! - [`IdentityLockbox`]: Stores an [`IdentityKey`](crate::identity::IdentityKey)
6//! - [`StreamLockbox`]: Stores a [`StreamKey`](crate::stream::StreamKey)
7//! - [`LockLockbox`]: Stores a [`LockKey`](crate::lock::LockKey)
8//! - [`DataLockbox`]: Stores an arbitrary byte sequence
9//!
10//! Each lockbox is encoded in a similar way. The lockbox type should be known when attempting to
11//! decode it, though if necessary it is also possible to determine the type through decoding (see
12//! [`determine_lockbox_type`]).
13//!
14//! A lockbox is created with a specific [`LockId`] or [`StreamKey`](crate::stream::StreamKey) as
15//! the intended recipient. A `DataLockbox` can be created by calling the encrypt function on a
16//! `StreamKey` or `LockId`, while the others can be created by calling the appropriate "export"
17//! function on the key to be exported.
18//!
19//! For decoding, each lockbox has a corresponding reference type, which will parse a byte slice
20//! and return a reference on success. These can be turned into their corresponding owned variants
21//! if needed, or can be used directly for decryption. These reference types are:
22//!
23//! - [`IdentityLockboxRef`]
24//! - [`StreamLockboxRef`]
25//! - [`LockLockboxRef`]
26//! - [`DataLockboxRef`]
27//!
28//! # Algorithms
29//!
30//! The current (and only) algorithm is XChaCha20 with a Poly1305 AEAD construction. For
31//! `StreamKey` recipients, the secret XChaCha20 key is used for encryption. For `LockId`
32//! recipients, an ephemeral X25519 keypair is generated and DH key agreement is used to generate
33//! the key.
34//!
35//! # Lockbox Types
36//!
37//! The different types of lockboxes each have 2 subtypes: one for `LockId`-recipient lockboxes,
38//! and one for `StreamKey`-recipient lockboxes. The encoded type byte is thus:
39//!
40//! | Type | Recipient | Byte Value |
41//! | -- | -- | -- |
42//! | `IdentityLockbox` | `LockId` | 0 |
43//! | `IdentityLockbox` | `StreamId` | 1 |
44//! | `StreamLockbox` | `LockId` | 2 |
45//! | `StreamLockbox` | `StreamId` | 3 |
46//! | `LockLockbox` | `LockId` | 4 |
47//! | `LockLockbox` | `StreamId` | 5 |
48//! | `DataLockbox` | `LockId` | 6 |
49//! | `DataLockbox` | `StreamId` | 7 |
50//!
51//! Alternately, the Type byte can be considered to have two bitfields: bit 0 encodes the
52//! recipient, and bits 2 & 1 encode the main lockbox type.
53//!
54//! # Format
55//!
56//! The first lockbox format is for `LockId`-recipient lockboxes. It consists of the version
57//! byte, a byte set to the lockbox type, the encoded `LockId`, an ephemeral X25519 public key
58//! (without a version byte), a 24-byte nonce, the ciphertext, and the 16-byte Poly1305
59//! authentication tag.
60//!
61//! The second lockbox format is for `StreamKey`-recipient lockboxes. It consists of the version
62//! byte, a byte set to the lockbox type, the encoded `StreamId`, a 24-byte nonce, the ciphertext,
63//! and the 16-byte Poly1305 authentication tag.
64//!
65//! ```text
66//! +----------+----------+==========+==========+==========+==============+=====+
67//! | Version | Type | SignKey | EphKey | Nonce | Ciphertext | Tag |
68//! +----------+----------+==========+==========+==========+==============+=====+
69//!
70//! +----------+----------+==========+==========+==============+=====+
71//! | Version | Type | StreamId | Nonce | Ciphertext | Tag |
72//! +----------+----------+==========+==========+==============+=====+
73//!
74//! - Version indicates what version of symmetric-key encryption was used for this lockbox.
75//! - Type indicates the lockbox type and recipient type. If bit 0 is cleared, the first format
76//! (with SignKey & EphKey) is used. If bit 1 is set, the second format (with StreamId) is used.
77//! - SignKey is a LockId. This is a version byte followed by the encoded public key.
78//! - EphKey is a raw public key, of the same version as SignKey.
79//! - StreamId is an identifier for the StreamKey that created the lockbox.
80//! - Nonce is a random byte sequence matching the nonce length specified by the symmetric
81//! encryption version used.
82//! - Ciphertext is the internal data, encrypted with the chosen algorithm.
83//! - Tag is the authentication tag produced using the chosen algorithm.
84//! ```
85//!
86//! In the AEAD construction, the additional data consists of every byte prior to the nonce.
87//!
88
89use crate::{
90 lock::{lock_eph_size, lock_id_size, LockId},
91 stream::{stream_id_size, StreamId, MAX_STREAM_VERSION, MIN_STREAM_VERSION},
92 CryptoError,
93};
94
95use std::{convert::TryFrom, fmt};
96
97pub(crate) const V1_LOCKBOX_NONCE_SIZE: usize = 24;
98pub(crate) const V1_LOCKBOX_TAG_SIZE: usize = 16;
99
100const LOCKBOX_OFFSET_VERSION: usize = 0;
101const LOCKBOX_OFFSET_TYPE: usize = 1;
102const LOCKBOX_OFFSET_ID_VERSION: usize = 2;
103
104/// Encodes the various types of lockboxes that may be decoded.
105///
106/// Each lockbox type can have a [`StreamKey`](crate::stream::StreamKey) recipient, in which case
107/// the held boolean should be set to true.
108pub enum LockboxType {
109 Identity(bool),
110 Stream(bool),
111 Lock(bool),
112 Data(bool),
113}
114
115impl LockboxType {
116 /// Convert the lockbox type into its encoded byte value.
117 pub fn as_u8(&self) -> u8 {
118 use LockboxType::*;
119 let (v, t) = match self {
120 Identity(t) => (0, *t),
121 Stream(t) => (2, *t),
122 Lock(t) => (4, *t),
123 Data(t) => (6, *t),
124 };
125 if t {
126 v | 0x1
127 } else {
128 v
129 }
130 }
131
132 /// Attempt to decode a lockbox type byte.
133 pub fn from_u8(v: u8) -> Result<Self, CryptoError> {
134 use LockboxType::*;
135 let t = (v & 0x1) != 0;
136 match v & 0xFE {
137 0 => Ok(Identity(t)),
138 2 => Ok(Stream(t)),
139 4 => Ok(Lock(t)),
140 6 => Ok(Data(t)),
141 _ => Err(CryptoError::BadFormat("Lockbox type field wasn't valid")),
142 }
143 }
144
145 /// Check if the lockbox type has a stream recipient.
146 pub fn is_for_stream(&self) -> bool {
147 use LockboxType::*;
148 match self {
149 Identity(t) => *t,
150 Stream(t) => *t,
151 Lock(t) => *t,
152 Data(t) => *t,
153 }
154 }
155}
156
157/// Determine what type of lockbox is in the encoded sequence. This only checks the first two
158/// bytes, and doesn't guarantee the whole `raw` byte slice contains a valid encoded lockbox.
159pub fn determine_lockbox_type(raw: &[u8]) -> Result<LockboxType, CryptoError> {
160 let &boxtype = raw.get(LOCKBOX_OFFSET_TYPE).ok_or(CryptoError::BadLength {
161 step: "get lockbox type",
162 expected: 2,
163 actual: raw.len(),
164 })?;
165 LockboxType::from_u8(boxtype)
166}
167
168/// Get expected size of a Lockbox's nonce for a given version. Version *must* be validated before
169/// calling this.
170pub(crate) fn lockbox_nonce_size(_version: u8) -> usize {
171 V1_LOCKBOX_NONCE_SIZE
172}
173
174/// Get expected size of a Lockbox's AEAD tag for a given version. Version *must* be validated
175/// before calling this.
176pub(crate) fn lockbox_tag_size(_version: u8) -> usize {
177 V1_LOCKBOX_TAG_SIZE
178}
179
180/// An encrypted [`LockKey`](crate::lock::LockKey).
181///
182/// This must be decrypted by the matching recipient, which will return the `LockKey` on success.
183/// It can either be decrypted on its own, returning a temporary `LockKey`, or through a Vault,
184/// which will store the `LockKey`.
185///
186/// When decoding, a reference to the data is first created: [`LockLockboxRef`], which can then be
187/// converted with `to_owned` to create this struct.
188///
189/// See: [`StreamKey::decrypt_lock_key`](crate::stream::StreamKey::decrypt_lock_key),
190/// [`LockKey::decrypt_lock_key`](crate::lock::LockKey::decrypt_lock_key), and
191/// [`Vault::decrypt_lock_key`](crate::Vault::decrypt_lock_key).
192///
193/// # Example
194///
195/// Using a `StreamKey` for decryption:
196///
197/// ```
198/// # use fog_crypto::lock::*;
199/// # use fog_crypto::lockbox::*;
200/// # use fog_crypto::stream::*;
201/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
202/// # // Setup
203/// # let key = StreamKey::new();
204/// # let to_send = LockKey::new();
205/// #
206/// # // Encrypt
207/// # let lockbox = to_send.export_for_stream(&key).unwrap();
208/// # let enc = Vec::from(lockbox.as_bytes());
209/// #
210/// // We have `enc`, a byte vector containing a lockbox
211/// let dec_lockbox: LockLockbox = LockLockboxRef::from_bytes(&enc[..])?.to_owned();
212/// let recipient: LockboxRecipient = dec_lockbox.recipient();
213/// // ...
214/// // Retrieve the key by looking up recipient
215/// // ...
216/// let dec_key: LockKey = key.decrypt_lock_key(&dec_lockbox)?;
217/// # Ok(())
218/// # }
219/// ```
220#[derive(Clone, PartialEq, Eq, Hash)]
221pub struct LockLockbox(Lockbox);
222
223impl fmt::Debug for LockLockbox {
224 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225 let parts = self.as_parts();
226 f.debug_struct("LockLockbox")
227 .field("version", &self.version())
228 .field("recipient", &self.recipient())
229 .field("cipertext_len", &parts.ciphertext.len())
230 .finish()
231 }
232}
233
234impl std::ops::Deref for LockLockbox {
235 type Target = LockLockboxRef;
236 #[inline]
237 fn deref(&self) -> &Self::Target {
238 LockLockboxRef::new_ref(&self.0)
239 }
240}
241
242impl std::borrow::Borrow<LockLockboxRef> for LockLockbox {
243 fn borrow(&self) -> &LockLockboxRef {
244 LockLockboxRef::new_ref(&self.0)
245 }
246}
247
248/// An reference to an encrypted [`LockKey`](crate::lock::LockKey).
249///
250/// This must be decrypted by the matching recipient, which will return the `LockKey` on success.
251/// It can either be decrypted on its own, returning a temporary `LockKey`, or through a Vault,
252/// which will store the `LockKey`.
253///
254/// This is only a reference to an encrypted payload. The owned version is [`LockLockbox`].
255///
256/// See: [`StreamKey::decrypt_lock_key`](crate::stream::StreamKey::decrypt_lock_key),
257/// [`LockKey::decrypt_lock_key`](crate::lock::LockKey::decrypt_lock_key), and
258/// [`Vault::decrypt_lock_key`](crate::Vault::decrypt_lock_key).
259///
260/// # Example
261///
262/// Using a `StreamKey` for decryption:
263///
264/// ```
265/// # use fog_crypto::lock::*;
266/// # use fog_crypto::lockbox::*;
267/// # use fog_crypto::stream::*;
268/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
269/// # // Setup
270/// # let key = StreamKey::new();
271/// # let to_send = LockKey::new();
272/// #
273/// # // Encrypt
274/// # let lockbox = to_send.export_for_stream(&key).unwrap();
275/// # let enc = Vec::from(lockbox.as_bytes());
276/// #
277/// // We have `enc`, a byte vector containing a lockbox
278/// let dec_lockbox: &LockLockboxRef = LockLockboxRef::from_bytes(&enc[..])?;
279/// let recipient: LockboxRecipient = dec_lockbox.recipient();
280/// // ...
281/// // Retrieve the key by looking up recipient
282/// // ...
283/// let dec_key: LockKey = key.decrypt_lock_key(&dec_lockbox)?;
284/// # Ok(())
285/// # }
286/// ```
287#[derive(PartialEq, Eq, Hash)]
288pub struct LockLockboxRef(LockboxRef);
289
290impl LockLockboxRef {
291 /// Create a new &LockboxRef from a byte slice. This should only be called by code that has
292 /// already verified the byte slice.
293 fn new_ref(lockbox_ref: &LockboxRef) -> &Self {
294 // Justification:
295 // LockLockboxRef is a newtype for a LockboxRef. See LockboxRef's `new_ref` for
296 // more justification, as it does the same thing.
297 unsafe { &*(lockbox_ref as *const LockboxRef as *const LockLockboxRef) }
298 }
299
300 /// Decompose the lockbox into its component parts.
301 pub fn as_parts(&self) -> LockboxParts {
302 self.0.as_parts()
303 }
304
305 /// Get the stream encryption version.
306 pub fn version(&self) -> u8 {
307 self.0.version()
308 }
309
310 /// Get the target recipient who can decrypt this.
311 pub fn recipient(&self) -> LockboxRecipient {
312 self.0.recipient()
313 }
314
315 /// The raw bytestream, suitable for serialization.
316 pub fn as_bytes(&self) -> &[u8] {
317 self.0.as_bytes()
318 }
319
320 pub fn from_bytes(buf: &[u8]) -> Result<&Self, CryptoError> {
321 let (lockbox, boxtype) = LockboxRef::decode(buf)?;
322 if let LockboxType::Lock(_) = boxtype {
323 Ok(Self::new_ref(lockbox))
324 } else {
325 Err(CryptoError::BadFormat("Didn't find a data lockbox"))
326 }
327 }
328}
329
330impl ToOwned for LockLockboxRef {
331 type Owned = LockLockbox;
332 #[inline]
333 fn to_owned(&self) -> Self::Owned {
334 LockLockbox(Lockbox {
335 inner: Vec::from(&self.0.inner),
336 })
337 }
338}
339
340impl fmt::Debug for LockLockboxRef {
341 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
342 let parts = self.as_parts();
343 f.debug_struct("LockLockboxRef")
344 .field("version", &self.version())
345 .field("recipient", &self.recipient())
346 .field("cipertext_len", &parts.ciphertext.len())
347 .finish()
348 }
349}
350
351/// An encrypted [`IdentityKey`](crate::identity::IdentityKey).
352///
353/// This must be decrypted by the matching recipient, which will return the `IdentityKey` on
354/// success. It can either be decrypted on its own, returning a temporary `IdentityKey`, or
355/// through a Vault, which will store the `IdentityKey`.
356///
357/// When decoding, a reference to the data is first created: [`IdentityLockboxRef`], which can then
358/// be converted with `to_owned` to create this struct.
359///
360/// See: [`StreamKey::decrypt_identity_key`](crate::stream::StreamKey::decrypt_identity_key),
361/// [`LockKey::decrypt_identity_key`](crate::lock::LockKey::decrypt_identity_key), and
362/// [`Vault::decrypt_identity_key`](crate::Vault::decrypt_identity_key).
363///
364/// # Example
365///
366/// Using a `StreamKey` for decryption:
367///
368/// ```
369/// # use fog_crypto::identity::*;
370/// # use fog_crypto::lockbox::*;
371/// # use fog_crypto::stream::*;
372/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
373/// # // Setup
374/// # let key = StreamKey::new();
375/// # let to_send = IdentityKey::new();
376/// #
377/// # // Encrypt
378/// # let lockbox = to_send.export_for_stream(&key).unwrap();
379/// # let enc = Vec::from(lockbox.as_bytes());
380/// #
381/// // We have `enc`, a byte vector containing a lockbox
382/// let dec_lockbox: IdentityLockbox = IdentityLockboxRef::from_bytes(&enc[..])?.to_owned();
383/// let recipient: LockboxRecipient = dec_lockbox.recipient();
384/// // ...
385/// // Retrieve the key by looking up recipient
386/// // ...
387/// let dec_key: IdentityKey = key.decrypt_identity_key(&dec_lockbox)?;
388/// # Ok(())
389/// # }
390/// ```
391#[derive(Clone, PartialEq, Eq, Hash)]
392pub struct IdentityLockbox(Lockbox);
393
394impl fmt::Debug for IdentityLockbox {
395 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
396 let parts = self.as_parts();
397 f.debug_struct("IdentityLockbox")
398 .field("version", &self.version())
399 .field("recipient", &self.recipient())
400 .field("cipertext_len", &parts.ciphertext.len())
401 .finish()
402 }
403}
404
405impl std::ops::Deref for IdentityLockbox {
406 type Target = IdentityLockboxRef;
407 #[inline]
408 fn deref(&self) -> &Self::Target {
409 IdentityLockboxRef::new_ref(&self.0)
410 }
411}
412
413impl std::borrow::Borrow<IdentityLockboxRef> for IdentityLockbox {
414 fn borrow(&self) -> &IdentityLockboxRef {
415 IdentityLockboxRef::new_ref(&self.0)
416 }
417}
418
419/// An encrypted [`IdentityKey`](crate::identity::IdentityKey).
420///
421/// This must be decrypted by the matching recipient, which will return the `IdentityKey` on
422/// success. It can either be decrypted on its own, returning a temporary `IdentityKey`, or
423/// through a Vault, which will store the `IdentityKey`.
424///
425/// This is only a reference to an encrypted payload. The owned version is [`IdentityLockbox`].
426///
427/// See: [`StreamKey::decrypt_identity_key`](crate::stream::StreamKey::decrypt_identity_key),
428/// [`LockKey::decrypt_identity_key`](crate::lock::LockKey::decrypt_identity_key), and
429/// [`Vault::decrypt_identity_key`](crate::Vault::decrypt_identity_key).
430///
431/// # Example
432///
433/// Using a `StreamKey` for decryption:
434///
435/// ```
436/// # use fog_crypto::identity::*;
437/// # use fog_crypto::lockbox::*;
438/// # use fog_crypto::stream::*;
439/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
440/// # // Setup
441/// # let key = StreamKey::new();
442/// # let to_send = IdentityKey::new();
443/// #
444/// # // Encrypt
445/// # let lockbox = to_send.export_for_stream(&key).unwrap();
446/// # let enc = Vec::from(lockbox.as_bytes());
447/// #
448/// // We have `enc`, a byte vector containing a lockbox
449/// let dec_lockbox: &IdentityLockboxRef = IdentityLockboxRef::from_bytes(&enc[..])?;
450/// let recipient: LockboxRecipient = dec_lockbox.recipient();
451/// // ...
452/// // Retrieve the key by looking up recipient
453/// // ...
454/// let dec_key: IdentityKey = key.decrypt_identity_key(&dec_lockbox)?;
455/// # Ok(())
456/// # }
457/// ```
458#[derive(PartialEq, Eq, Hash)]
459pub struct IdentityLockboxRef(LockboxRef);
460
461impl IdentityLockboxRef {
462 /// Create a new &LockboxRef from a byte slice. This should only be called by code that has
463 /// already verified the byte slice.
464 fn new_ref(lockbox_ref: &LockboxRef) -> &Self {
465 // Justification:
466 // IdentityLockboxRef is a newtype for a LockboxRef. See LockboxRef's `new_ref` for
467 // more justification, as it does the same thing.
468 unsafe { &*(lockbox_ref as *const LockboxRef as *const IdentityLockboxRef) }
469 }
470
471 /// Decompose the lockbox into its component parts.
472 pub fn as_parts(&self) -> LockboxParts {
473 self.0.as_parts()
474 }
475
476 /// Get the stream encryption version.
477 pub fn version(&self) -> u8 {
478 self.0.version()
479 }
480
481 /// Get the target recipient who can decrypt this.
482 pub fn recipient(&self) -> LockboxRecipient {
483 self.0.recipient()
484 }
485
486 /// The raw bytestream, suitable for serialization.
487 pub fn as_bytes(&self) -> &[u8] {
488 self.0.as_bytes()
489 }
490
491 pub fn from_bytes(buf: &[u8]) -> Result<&Self, CryptoError> {
492 let (lockbox, boxtype) = LockboxRef::decode(buf)?;
493 if let LockboxType::Identity(_) = boxtype {
494 Ok(Self::new_ref(lockbox))
495 } else {
496 Err(CryptoError::BadFormat("Didn't find a data lockbox"))
497 }
498 }
499}
500
501impl ToOwned for IdentityLockboxRef {
502 type Owned = IdentityLockbox;
503 #[inline]
504 fn to_owned(&self) -> Self::Owned {
505 IdentityLockbox(Lockbox {
506 inner: Vec::from(&self.0.inner),
507 })
508 }
509}
510
511impl fmt::Debug for IdentityLockboxRef {
512 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
513 let parts = self.as_parts();
514 f.debug_struct("IdentityLockboxRef")
515 .field("version", &self.version())
516 .field("recipient", &self.recipient())
517 .field("cipertext_len", &parts.ciphertext.len())
518 .finish()
519 }
520}
521
522/// An encrypted [`StreamKey`](crate::stream::StreamKey).
523///
524/// This must be decrypted by the matching recipient, which will return the `StreamKey` on
525/// success. It can either be decrypted on its own, returning a temporary `StreamKey`, or
526/// through a Vault, which will store the `StreamKey`.
527///
528/// When decoding, a reference to the data is first created: [`StreamLockboxRef`], which can then
529/// be converted with `to_owned` to create this struct.
530///
531/// See: [`StreamKey::decrypt_stream_key`](crate::stream::StreamKey::decrypt_stream_key),
532/// [`LockKey::decrypt_stream_key`](crate::lock::LockKey::decrypt_stream_key), and
533/// [`Vault::decrypt_stream_key`](crate::Vault::decrypt_stream_key).
534///
535/// # Example
536///
537/// Using a `StreamKey` for decryption (different from the one contained in the lockbox!):
538///
539/// ```
540/// # use fog_crypto::lockbox::*;
541/// # use fog_crypto::stream::*;
542/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
543/// # // Setup
544/// # let key = StreamKey::new();
545/// # let to_send = StreamKey::new();
546/// #
547/// # // Encrypt
548/// # let lockbox = to_send.export_for_stream(&key).unwrap();
549/// # let enc = Vec::from(lockbox.as_bytes());
550/// #
551/// // We have `enc`, a byte vector containing a lockbox
552/// let dec_lockbox: StreamLockbox = StreamLockboxRef::from_bytes(&enc[..])?.to_owned();
553/// let recipient: LockboxRecipient = dec_lockbox.recipient();
554/// // ...
555/// // Retrieve the key by looking up recipient
556/// // ...
557/// let dec_key: StreamKey = key.decrypt_stream_key(&dec_lockbox)?;
558/// # Ok(())
559/// # }
560/// ```
561#[derive(Clone, PartialEq, Eq, Hash)]
562pub struct StreamLockbox(Lockbox);
563
564impl fmt::Debug for StreamLockbox {
565 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
566 let parts = self.as_parts();
567 f.debug_struct("StreamLockbox")
568 .field("version", &self.version())
569 .field("recipient", &self.recipient())
570 .field("cipertext_len", &parts.ciphertext.len())
571 .finish()
572 }
573}
574
575impl std::ops::Deref for StreamLockbox {
576 type Target = StreamLockboxRef;
577 #[inline]
578 fn deref(&self) -> &Self::Target {
579 StreamLockboxRef::new_ref(&self.0)
580 }
581}
582
583impl std::borrow::Borrow<StreamLockboxRef> for StreamLockbox {
584 fn borrow(&self) -> &StreamLockboxRef {
585 StreamLockboxRef::new_ref(&self.0)
586 }
587}
588
589/// An encrypted [`StreamKey`](crate::stream::StreamKey).
590///
591/// This must be decrypted by the matching recipient, which will return the `StreamKey` on
592/// success. It can either be decrypted on its own, returning a temporary `StreamKey`, or
593/// through a Vault, which will store the `StreamKey`.
594///
595/// This is only a reference to an encrypted payload. The owned version is [`StreamLockbox`].
596///
597/// See: [`StreamKey::decrypt_stream_key`](crate::stream::StreamKey::decrypt_stream_key),
598/// [`LockKey::decrypt_stream_key`](crate::lock::LockKey::decrypt_stream_key), and
599/// [`Vault::decrypt_stream_key`](crate::Vault::decrypt_stream_key).
600///
601/// # Example
602///
603/// Using a `StreamKey` for decryption (different from the one contained in the lockbox!):
604///
605/// ```
606/// # use fog_crypto::lockbox::*;
607/// # use fog_crypto::stream::*;
608/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
609/// # // Setup
610/// # let key = StreamKey::new();
611/// # let to_send = StreamKey::new();
612/// #
613/// # // Encrypt
614/// # let lockbox = to_send.export_for_stream(&key).unwrap();
615/// # let enc = Vec::from(lockbox.as_bytes());
616/// #
617/// // We have `enc`, a byte vector containing a lockbox
618/// let dec_lockbox: &StreamLockboxRef = StreamLockboxRef::from_bytes(&enc[..])?;
619/// let recipient: LockboxRecipient = dec_lockbox.recipient();
620/// // ...
621/// // Retrieve the key by looking up recipient
622/// // ...
623/// let dec_key: StreamKey = key.decrypt_stream_key(&dec_lockbox)?;
624/// # Ok(())
625/// # }
626/// ```
627#[derive(PartialEq, Eq, Hash)]
628pub struct StreamLockboxRef(LockboxRef);
629
630impl StreamLockboxRef {
631 /// Create a new &LockboxRef from a byte slice. This should only be called by code that has
632 /// already verified the byte slice.
633 fn new_ref(lockbox_ref: &LockboxRef) -> &Self {
634 // Justification:
635 // StreamLockboxRef is a newtype for a LockboxRef. See LockboxRef's `new_ref` for
636 // more justification, as it does the same thing.
637 unsafe { &*(lockbox_ref as *const LockboxRef as *const StreamLockboxRef) }
638 }
639
640 /// Decompose the lockbox into its component parts.
641 pub fn as_parts(&self) -> LockboxParts {
642 self.0.as_parts()
643 }
644
645 /// Get the stream encryption version.
646 pub fn version(&self) -> u8 {
647 self.0.version()
648 }
649
650 /// Get the target recipient who can decrypt this.
651 pub fn recipient(&self) -> LockboxRecipient {
652 self.0.recipient()
653 }
654
655 /// The raw bytestream, suitable for serialization.
656 pub fn as_bytes(&self) -> &[u8] {
657 self.0.as_bytes()
658 }
659
660 pub fn from_bytes(buf: &[u8]) -> Result<&Self, CryptoError> {
661 let (lockbox, boxtype) = LockboxRef::decode(buf)?;
662 if let LockboxType::Stream(_) = boxtype {
663 Ok(Self::new_ref(lockbox))
664 } else {
665 Err(CryptoError::BadFormat("Didn't find a data lockbox"))
666 }
667 }
668}
669
670impl ToOwned for StreamLockboxRef {
671 type Owned = StreamLockbox;
672 #[inline]
673 fn to_owned(&self) -> Self::Owned {
674 StreamLockbox(Lockbox {
675 inner: Vec::from(&self.0.inner),
676 })
677 }
678}
679
680impl fmt::Debug for StreamLockboxRef {
681 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
682 let parts = self.as_parts();
683 f.debug_struct("StreamLockboxRef")
684 .field("version", &self.version())
685 .field("recipient", &self.recipient())
686 .field("cipertext_len", &parts.ciphertext.len())
687 .finish()
688 }
689}
690
691/// General encrypted data.
692///
693/// This must be decrypted by the matching recipient, which will return a `Vec<u8>` on success.
694/// It can either be decrypted on its own or through a Vault. In both cases, the data is returned
695/// without being stored anywhere.
696///
697/// When decoding, a reference to the data is first created: [`DataLockboxRef`], which can then be
698/// converted with `to_owned` to create this struct.
699///
700/// See: [`StreamKey::decrypt_data`](crate::stream::StreamKey::decrypt_data),
701/// [`LockKey::decrypt_data`](crate::lock::LockKey::decrypt_data), and
702/// [`Vault::decrypt_data`](crate::Vault::decrypt_data).
703///
704/// # Example
705///
706/// Using a `StreamKey` for decryption:
707///
708/// ```
709/// # use fog_crypto::lockbox::*;
710/// # use fog_crypto::stream::*;
711/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
712/// # // Setup
713/// # let key = StreamKey::new();
714/// # let to_send = b"I am data to be encrypted, and you don't need to see me.";
715/// #
716/// # // Encrypt
717/// # let lockbox = key.encrypt_data(&to_send[..]);
718/// # let enc = Vec::from(lockbox.as_bytes());
719/// #
720/// // We have `enc`, a byte vector containing a lockbox
721/// let dec_lockbox: DataLockbox = DataLockboxRef::from_bytes(&enc[..])?.to_owned();
722/// let recipient: LockboxRecipient = dec_lockbox.recipient();
723/// // ...
724/// // Retrieve the key by looking up recipient
725/// // ...
726/// let plaintext: Vec<u8> = key.decrypt_data(&dec_lockbox)?;
727/// # Ok(())
728/// # }
729/// ```
730#[derive(Clone, PartialEq, Eq, Hash)]
731pub struct DataLockbox(Lockbox);
732
733impl fmt::Debug for DataLockbox {
734 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
735 let parts = self.as_parts();
736 f.debug_struct("DataLockbox")
737 .field("version", &self.version())
738 .field("recipient", &self.recipient())
739 .field("cipertext_len", &parts.ciphertext.len())
740 .finish()
741 }
742}
743
744impl std::ops::Deref for DataLockbox {
745 type Target = DataLockboxRef;
746 #[inline]
747 fn deref(&self) -> &Self::Target {
748 DataLockboxRef::new_ref(&self.0)
749 }
750}
751
752impl std::borrow::Borrow<DataLockboxRef> for DataLockbox {
753 fn borrow(&self) -> &DataLockboxRef {
754 DataLockboxRef::new_ref(&self.0)
755 }
756}
757
758/// General encrypted data.
759///
760/// This must be decrypted by the matching recipient, which will return a `Vec<u8>` on success.
761/// It can either be decrypted on its own or through a Vault. In both cases, the data is returned
762/// without being stored anywhere.
763///
764/// This is only a reference to an encrypted payload. The owned version is [`DataLockbox`].
765///
766/// See: [`StreamKey::decrypt_data`](crate::stream::StreamKey::decrypt_data),
767/// [`LockKey::decrypt_data`](crate::lock::LockKey::decrypt_data), and
768/// [`Vault::decrypt_data`](crate::Vault::decrypt_data).
769///
770/// # Example
771///
772/// Using a `StreamKey` for decryption:
773///
774/// ```
775/// # use fog_crypto::lockbox::*;
776/// # use fog_crypto::stream::*;
777/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
778/// # // Setup
779/// # let key = StreamKey::new();
780/// # let to_send = b"I am data to be encrypted, and you don't need to see me.";
781/// #
782/// # // Encrypt
783/// # let lockbox = key.encrypt_data(&to_send[..]);
784/// # let enc = Vec::from(lockbox.as_bytes());
785/// #
786/// // We have `enc`, a byte vector containing a lockbox
787/// let dec_lockbox: &DataLockboxRef = DataLockboxRef::from_bytes(&enc[..])?;
788/// let recipient: LockboxRecipient = dec_lockbox.recipient();
789/// // ...
790/// // Retrieve the key by looking up recipient
791/// // ...
792/// let plaintext: Vec<u8> = key.decrypt_data(&dec_lockbox)?;
793/// # Ok(())
794/// # }
795/// ```
796#[derive(PartialEq, Eq, Hash)]
797pub struct DataLockboxRef(LockboxRef);
798
799impl DataLockboxRef {
800 /// Create a new &LockboxRef from a byte slice. This should only be called by code that has
801 /// already verified the byte slice.
802 fn new_ref(lockbox_ref: &LockboxRef) -> &Self {
803 // Justification:
804 // DataLockboxRef is a newtype for a LockboxRef. See LockboxRef's `new_ref` for
805 // more justification, as it does the same thing.
806 unsafe { &*(lockbox_ref as *const LockboxRef as *const DataLockboxRef) }
807 }
808
809 /// Decompose the lockbox into its component parts.
810 pub fn as_parts(&self) -> LockboxParts {
811 self.0.as_parts()
812 }
813
814 /// Get the stream encryption version.
815 pub fn version(&self) -> u8 {
816 self.0.version()
817 }
818
819 /// Get the target recipient who can decrypt this.
820 pub fn recipient(&self) -> LockboxRecipient {
821 self.0.recipient()
822 }
823
824 /// The raw bytestream, suitable for serialization.
825 pub fn as_bytes(&self) -> &[u8] {
826 self.0.as_bytes()
827 }
828
829 pub fn from_bytes(buf: &[u8]) -> Result<&Self, CryptoError> {
830 let (lockbox, boxtype) = LockboxRef::decode(buf)?;
831 if let LockboxType::Data(_) = boxtype {
832 Ok(Self::new_ref(lockbox))
833 } else {
834 Err(CryptoError::BadFormat("Didn't find a data lockbox"))
835 }
836 }
837}
838
839impl ToOwned for DataLockboxRef {
840 type Owned = DataLockbox;
841 #[inline]
842 fn to_owned(&self) -> Self::Owned {
843 DataLockbox(Lockbox {
844 inner: Vec::from(&self.0.inner),
845 })
846 }
847}
848
849impl fmt::Debug for DataLockboxRef {
850 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
851 let parts = self.as_parts();
852 f.debug_struct("DataLockboxRef")
853 .field("version", &self.version())
854 .field("recipient", &self.recipient())
855 .field("cipertext_len", &parts.ciphertext.len())
856 .finish()
857 }
858}
859
860/// A lockbox byte stream, sliced into its component parts
861pub struct LockboxParts<'a> {
862 /// The ephemeral public key
863 pub eph_pub: Option<&'a [u8]>,
864 /// The entire "additional data" portion - every byte prior to the nonce.
865 pub additional: &'a [u8],
866 /// The random nonce.
867 pub nonce: &'a [u8],
868 /// The encrypted data, including the AEAD tag at the end.
869 pub ciphertext: &'a [u8],
870}
871
872#[derive(Clone, PartialEq, Eq, Hash)]
873struct Lockbox {
874 inner: Vec<u8>,
875}
876
877impl fmt::Debug for Lockbox {
878 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
879 let parts = self.as_parts();
880 f.debug_struct("Lockbox")
881 .field("version", &self.version())
882 .field("recipient", &self.recipient())
883 .field("cipertext_len", &parts.ciphertext.len())
884 .finish()
885 }
886}
887
888impl std::ops::Deref for Lockbox {
889 type Target = LockboxRef;
890 #[inline]
891 fn deref(&self) -> &Self::Target {
892 let inner: &[u8] = self.inner.as_ref();
893 LockboxRef::new_ref(inner)
894 }
895}
896
897impl std::borrow::Borrow<LockboxRef> for Lockbox {
898 fn borrow(&self) -> &LockboxRef {
899 let inner: &[u8] = self.inner.as_ref();
900 LockboxRef::new_ref(inner)
901 }
902}
903
904#[derive(PartialEq, Eq, Hash)]
905struct LockboxRef {
906 inner: [u8],
907}
908
909impl LockboxRef {
910 /// Create a new &LockboxRef from a byte slice. This should only be called by code that has
911 /// already verified the byte slice.
912 fn new_ref(buf: &[u8]) -> &Self {
913 // Justification:
914 // LockboxRef is literally a newtype for a [u8], so &[u8] and &LockboxRef refer to the
915 // same thing. This is a hack to get the type system to let us turn one into the other, and
916 // it's the same hack that `serde_bytes` uses for this functionality. Likewise, the
917 // standard library does something similar for working with `OsStr`, `str`, and `[T]`. So
918 // at least we're in good company.
919 unsafe { &*(buf as *const [u8] as *const LockboxRef) }
920 }
921
922 fn as_parts(&self) -> LockboxParts {
923 let version = self.version();
924 let nonce_len = lockbox_nonce_size(version);
925 let boxtype = LockboxType::from_u8(self.inner[LOCKBOX_OFFSET_TYPE]).unwrap();
926 if boxtype.is_for_stream() {
927 let id_len = stream_id_size(version);
928 let additional_len = 2 + id_len; // 1 for lockbox version, 1 for lockbox type
929 let (additional, inner) = self.inner.split_at(additional_len);
930 let (nonce, ciphertext) = inner.split_at(nonce_len);
931 LockboxParts {
932 eph_pub: None,
933 additional,
934 nonce,
935 ciphertext,
936 }
937 } else {
938 let id_version = self.inner[LOCKBOX_OFFSET_ID_VERSION]; // Can differ from lockbox version
939 let id_len = lock_id_size(id_version);
940 let eph_len = lock_eph_size(id_version);
941 let additional_len = 2 + id_len + eph_len; // 1 for lockbox version, 1 for lockbox type
942 let (additional, inner) = self.inner.split_at(additional_len);
943 let eph_pub = additional.get((2 + id_len)..).unwrap();
944 let (nonce, ciphertext) = inner.split_at(nonce_len);
945 LockboxParts {
946 eph_pub: Some(eph_pub),
947 additional,
948 nonce,
949 ciphertext,
950 }
951 }
952 }
953
954 /// Get the version of the Lockbox.
955 fn version(&self) -> u8 {
956 self.inner[LOCKBOX_OFFSET_VERSION]
957 }
958
959 /// Get the target recipient who should be able to decrypt the lockbox.
960 fn recipient(&self) -> LockboxRecipient {
961 let boxtype = LockboxType::from_u8(self.inner[1]).unwrap();
962 let id_version = self.inner[2];
963 if boxtype.is_for_stream() {
964 let id_len = stream_id_size(id_version);
965 let range = LOCKBOX_OFFSET_ID_VERSION..(LOCKBOX_OFFSET_ID_VERSION + id_len);
966 LockboxRecipient::StreamId(StreamId::try_from(&self.inner[range]).unwrap())
967 } else {
968 let id_len = lock_id_size(id_version);
969 let range = LOCKBOX_OFFSET_ID_VERSION..(LOCKBOX_OFFSET_ID_VERSION + id_len);
970 LockboxRecipient::LockId(LockId::try_from(&self.inner[range]).unwrap())
971 }
972 }
973
974 /// Provide the encoded lockbox as a byte slice.
975 fn as_bytes(&self) -> &[u8] {
976 &self.inner
977 }
978
979 /// Attempt to decode a lockbox & produce both the resulting lockbox and the lockbox type byte.
980 fn decode(raw: &[u8]) -> Result<(&Self, LockboxType), CryptoError> {
981 let (&version, parse) = raw.split_first().ok_or(CryptoError::BadLength {
982 step: "get lockbox version",
983 expected: 1,
984 actual: 0,
985 })?;
986 if version < MIN_STREAM_VERSION || version > MAX_STREAM_VERSION {
987 return Err(CryptoError::UnsupportedVersion(version));
988 }
989 let (&boxtype, parse) = parse.split_first().ok_or(CryptoError::BadLength {
990 step: "get lockbox type",
991 expected: 1,
992 actual: 0,
993 })?;
994 let boxtype = LockboxType::from_u8(boxtype)?;
995 if boxtype.is_for_stream() {
996 // Check the length. Must be at least long enough to hold the StreamId, Nonce, and
997 // Tag. It is acceptable (if a bit silly) for the actual ciphertext to be of length
998 // 0.
999 let id_len = stream_id_size(version);
1000 let nonce_len = lockbox_nonce_size(version);
1001 let tag_len = lockbox_tag_size(version);
1002 if parse.len() < (id_len + nonce_len + tag_len) {
1003 return Err(CryptoError::BadLength {
1004 step: "get lockbox component lengths",
1005 expected: id_len + nonce_len + tag_len,
1006 actual: parse.len(),
1007 });
1008 }
1009 // Extract the StreamId
1010 let (raw_id, _) = parse.split_at(id_len);
1011 let id = StreamId::try_from(raw_id)?; // Verify that the ID is a valid one
1012 // Compare the StreamId & version byte. We can't use stream keys that differ from
1013 // the lockbox version because they're supposed to literally be the same algorithm!
1014 if id.version() != version {
1015 return Err(CryptoError::BadFormat(
1016 "Lockbox version didn't match Stream Id version",
1017 ));
1018 }
1019 Ok((Self::new_ref(raw), boxtype))
1020 } else {
1021 let id_version = *parse.first().ok_or(CryptoError::BadLength {
1022 step: "get LockId version for lockbox",
1023 expected: 1,
1024 actual: 0,
1025 })?;
1026 let id_len = lock_id_size(id_version);
1027 let eph_len = lock_eph_size(id_version);
1028 let nonce_len = lockbox_nonce_size(version);
1029 let tag_len = lockbox_tag_size(version);
1030 if parse.len() < (id_len + eph_len + nonce_len + tag_len) {
1031 return Err(CryptoError::BadLength {
1032 step: "get lockbox component lengths",
1033 expected: id_len + eph_len + nonce_len + tag_len,
1034 actual: parse.len(),
1035 });
1036 }
1037 // Extract the LockId
1038 let (raw_id, _) = parse.split_at(id_len);
1039 LockId::try_from(raw_id)?; // Just verify that the ID is a valid one
1040 Ok((Self::new_ref(raw), boxtype))
1041 }
1042 }
1043}
1044
1045impl fmt::Debug for LockboxRef {
1046 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1047 let parts = self.as_parts();
1048 f.debug_struct("Lockbox")
1049 .field("version", &self.version())
1050 .field("recipient", &self.recipient())
1051 .field("cipertext_len", &parts.ciphertext.len())
1052 .finish()
1053 }
1054}
1055
1056impl ToOwned for LockboxRef {
1057 type Owned = Lockbox;
1058 #[inline]
1059 fn to_owned(&self) -> Self::Owned {
1060 Lockbox {
1061 inner: Vec::from(&self.inner),
1062 }
1063 }
1064}
1065
1066/// Directly take parts to construct a `LockLockbox`. Should only be used by implementors of the
1067/// `encrypt` functions.
1068///
1069/// This is *not* checked for correctness. Strongly consider having unit tests that check the
1070/// round-trip encrypt/decrypt for each lockbox type to catch misuse of this.
1071pub fn lock_lockbox_from_parts(inner: Vec<u8>) -> LockLockbox {
1072 LockLockbox(Lockbox { inner })
1073}
1074
1075/// Directly take parts to construct a `IdentityLockbox`. Should only be used by implementors of the
1076/// `encrypt` functions.
1077///
1078/// This is *not* checked for correctness. Strongly consider having unit tests that check the
1079/// round-trip encrypt/decrypt for each lockbox type to catch misuse of this.
1080pub fn identity_lockbox_from_parts(inner: Vec<u8>) -> IdentityLockbox {
1081 IdentityLockbox(Lockbox { inner })
1082}
1083
1084/// Directly take parts to construct a `StreamLockbox`. Should only be used by implementors of the
1085/// `encrypt` functions.
1086///
1087/// This is *not* checked for correctness. Strongly consider having unit tests that check the
1088/// round-trip encrypt/decrypt for each lockbox type to catch misuse of this.
1089pub fn stream_lockbox_from_parts(inner: Vec<u8>) -> StreamLockbox {
1090 StreamLockbox(Lockbox { inner })
1091}
1092
1093/// Directly take parts to construct a `DataLockbox`. Should only be used by implementors of the
1094/// `encrypt` functions.
1095///
1096/// This is *not* checked for correctness. Strongly consider having unit tests that check the
1097/// round-trip encrypt/decrypt for each lockbox type to catch misuse of this.
1098pub fn data_lockbox_from_parts(inner: Vec<u8>) -> DataLockbox {
1099 DataLockbox(Lockbox { inner })
1100}
1101
1102/// Lockboxes can be meant for one of two types of recipients: a [`LockId`] (public key), or a
1103/// [`StreamId`] (symmetric key). The corresponding [`LockKey`](crate::lock::LockKey) or
1104/// [`StreamKey`](crate::stream::StreamKey) is needed for decryption of the lockbox.
1105#[derive(Clone, Debug, PartialEq, Eq)]
1106pub enum LockboxRecipient {
1107 LockId(LockId),
1108 StreamId(StreamId),
1109}