fog_crypto/
lock.rs

1//! Public-Key encryption.
2//!
3//! This module lets you create a [`LockKey`] (a private key), which comes with a corresponding
4//! [`LockId`] (the public key). The `LockId` can be used to encrypt data and export keys, while
5//! the `LockKey` can decrypt those keys and data.
6//!
7//! All `LockKey` structs are backed by some struct that implements the [`LockInterface`] trait;
8//! this can be an in-memory private key, an interface to an OS-managed keystore, an interface to a
9//! hardware security module, or something else.
10//!
11//! # Example
12//!
13//! ```
14//! # use std::convert::TryFrom;
15//! # use fog_crypto::lock::*;
16//! # use fog_crypto::lockbox::*;
17//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
18//!
19//! // Make a new temporary key
20//! let key = LockKey::new();
21//! let id = key.id().clone();
22//!
23//! println!("LockId(Base58): {}", key.id());
24//!
25//! // Encrypt some data with the public ID, then turn it into a byte vector
26//! let data = b"I am sensitive information, about to be encrypted";
27//! let lockbox = id.encrypt_data(data.as_ref());
28//! let mut encoded = Vec::new();
29//! encoded.extend_from_slice(lockbox.as_bytes());
30//!
31//! // Decrypt that data with the private key
32//! let dec_lockbox = DataLockboxRef::from_bytes(encoded.as_ref())?;
33//! let dec_data = key.decrypt_data(&dec_lockbox)?;
34//! # Ok(())
35//! # }
36//! ```
37//!
38//! # Algorithms
39//!
40//! The current (and only) algorithm for public-key encryption is X25519 for calculation of the
41//! shared secret. The private key is handled by a [`LockKey`], while the public key is available
42//! as a [`LockId`].
43//!
44//! An ephemeral key pair is generated for each new lockbox, and the shared secret is calculated
45//! on encryption with the ephemeral private key and the `LockId` through Diffie-Hellman key
46//! exchange. On decryption, the ephemeral public key is recovered from the lockbox and is
47//! combined with the recipient's `LockKey`.
48//!
49//! In all cases, the 32-byte shared secret is directly used as the symmetric key in
50//! XChaCha20Poly1305.
51//!
52//! # Format
53//!
54//! A [`LockId`] is encoded as a version byte followed by the contained public key, whose length
55//! may be dependant on the version. For X25519, it is 32 bytes (plus the version byte).
56//!
57//! A [`LockKey`] is encoded as a version byte followed by the contained private key, whose length
58//! may be dependant on the version. For X25519, it is 32 bytes (plus the version byte).  This
59//! encoding is only ever used for the payload of a [`LockLockbox`].
60//!
61//! For details on the lockbox formatting, see the [submodule documentation](crate::lockbox).
62//!
63
64use crate::{
65    identity::{BareIdKey, IdentityKey},
66    lockbox::*,
67    stream::{stream_key_encrypt, BareStreamKey, StreamKey},
68    CryptoError, CryptoSrc,
69};
70
71use chacha20poly1305::KeyInit;
72use rand_core::{CryptoRng, RngCore};
73
74use zeroize::Zeroize;
75
76use std::{convert::TryFrom, fmt, sync::Arc};
77
78/// Default public-key encryption algorithm version.
79pub const DEFAULT_LOCK_VERSION: u8 = 1;
80
81/// Minimum accepted public-key encryption algorithm version.
82pub const MIN_LOCK_VERSION: u8 = 1;
83
84/// Maximum accepted public-key encryption algorithm version.
85pub const MAX_LOCK_VERSION: u8 = 1;
86
87const V1_LOCK_ID_SIZE: usize = 32; // Size of public key
88const V1_LOCK_KEY_SIZE: usize = 32; // Size of static secret key
89
90pub(crate) fn lock_id_size(_version: u8) -> usize {
91    1 + V1_LOCK_ID_SIZE
92}
93
94pub(crate) fn lock_eph_size(_version: u8) -> usize {
95    V1_LOCK_ID_SIZE
96}
97
98/// A key that allows decrypting data meant for a particular [`LockId`].
99///
100/// This acts as a wrapper for a specific cryptographic private decryption key,
101///
102/// # Example
103/// ```
104/// # use std::convert::TryFrom;
105/// # use fog_crypto::lock::*;
106/// # use fog_crypto::lockbox::*;
107/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
108///
109/// // Make a new temporary key
110/// let key = LockKey::new();
111/// let id = key.id().clone();
112/// println!("LockId(Base58): {}", key.id());
113///
114/// // ...
115/// // Wait for encrypted data to show up
116/// // ...
117/// # let data = b"I am sensitive information, about to be encrypted";
118/// # let lockbox = id.encrypt_data(data.as_ref());
119/// # let mut received = Vec::new();
120/// # received.extend_from_slice(lockbox.as_bytes());
121///
122/// // Decrypt Some received data
123/// let lockbox = DataLockboxRef::from_bytes(received.as_ref())?;
124/// let data = key.decrypt_data(&lockbox)?;
125/// # Ok(())
126/// # }
127/// ```
128#[derive(Clone)]
129pub struct LockKey {
130    interface: Arc<dyn LockInterface>,
131}
132
133#[cfg(feature = "getrandom")]
134impl Default for LockKey {
135    fn default() -> Self {
136        Self::new()
137    }
138}
139
140impl LockKey {
141
142    /// Create a new `LockKey` to hold a `LockInterface` implementation. Can be used by implementors of
143    /// a vault when making new `LockKey` instances.
144    pub fn from_interface(interface: Arc<dyn LockInterface>) -> Self {
145        Self { interface }
146    }
147
148    /// Generate a temporary `LockKey` that exists only in program memory.
149    pub fn new() -> LockKey {
150        let interface = Arc::new(BareLockKey::new());
151        Self::from_interface(interface)
152    }
153
154    /// Generate a temporary `LockKey` that exists only in program memory, using
155    /// the provided cryptographic RNG.
156    pub fn with_rng<R>(csprng: &mut R) -> LockKey
157    where
158        R: CryptoRng + RngCore,
159    {
160        let interface = Arc::new(BareLockKey::with_rng(csprng));
161        Self::from_interface(interface)
162    }
163
164    /// Generate a temporary `LockKey` that exists only in program memory. Uses the specified
165    /// version instead of the default, and fails if the version is unsupported.
166    pub fn with_rng_and_version<R>(csprng: &mut R, version: u8) -> Result<LockKey, CryptoError>
167    where
168        R: CryptoRng + RngCore,
169    {
170        let interface = Arc::new(BareLockKey::with_rng_and_version(csprng, version)?);
171        Ok(Self::from_interface(interface))
172    }
173
174    /// Version of Diffie-Hellman key exchange algorithm used by this key.
175    pub fn version(&self) -> u8 {
176        self.interface.id().version()
177    }
178
179    /// The public identifier for this key.
180    pub fn id(&self) -> &LockId {
181        self.interface.id()
182    }
183
184    /// Attempt to decrypt a `LockLockboxRef` with this key. On success, the returned `LockKey` is
185    /// temporary and not associated with any Vault.
186    pub fn decrypt_lock_key(&self, lockbox: &LockLockboxRef) -> Result<LockKey, CryptoError> {
187        self.interface.decrypt_lock_key(lockbox)
188    }
189
190    /// Attempt to decrypt a `IdentityLockboxRef` with this key. On success, the returned
191    /// `IdentityKey` is temporary and not associated with any Vault.
192    pub fn decrypt_identity_key(
193        &self,
194        lockbox: &IdentityLockboxRef,
195    ) -> Result<IdentityKey, CryptoError> {
196        self.interface.decrypt_identity_key(lockbox)
197    }
198
199    /// Attempt to decrypt a `StreamLockboxRef` with this key. On success, the returned
200    /// `StreamKey` is temporary and not associated with any Vault.
201    pub fn decrypt_stream_key(&self, lockbox: &StreamLockboxRef) -> Result<StreamKey, CryptoError> {
202        self.interface.decrypt_stream_key(lockbox)
203    }
204
205    /// Attempt to decrypt a `DataLockboxRef` with this key.
206    pub fn decrypt_data(&self, lockbox: &DataLockboxRef) -> Result<Vec<u8>, CryptoError> {
207        self.interface.decrypt_data(lockbox)
208    }
209
210    /// Export the signing key in a `LockLockbox`, with `receive_lock` as the recipient. If
211    /// the key cannot be exported, this should return None.
212    pub fn export_for_lock(
213        &self,
214        lock: &LockId,
215    ) -> Option<LockLockbox> {
216        self.interface.self_export_lock(&mut rand_core::OsRng, lock)
217    }
218
219    /// Export the signing key in an `LockLockbox`, with `receive_lock` as the recipient. If
220    /// the key cannot be exported, this should return None.
221    pub fn export_for_lock_with_rng<R: CryptoRng + RngCore>(
222        &self,
223        csprng: &mut R,
224        lock: &LockId,
225    ) -> Option<LockLockbox> {
226        self.interface.self_export_lock(csprng, lock)
227    }
228
229    #[cfg(feature = "getrandom")]
230    /// Export the private key in a `LockLockbox`, with `receive_stream` as the recipient. If
231    /// the key cannot be exported, this should return None. Additionally, if the underlying
232    /// implementation does not allow moving the raw key into memory (i.e. it cannot call
233    /// [`StreamInterface::encrypt`](crate::stream::StreamInterface::encrypt) or
234    /// [`lock_id_encrypt`](lock_id_encrypt)) then None can also be returned.
235    pub fn export_for_stream(
236        &self,
237        stream: &StreamKey,
238    ) -> Option<LockLockbox> {
239        self.interface.self_export_stream(&mut rand_core::OsRng, stream)
240    }
241
242    /// Export the private key in a `LockLockbox`, with `receive_stream` as the recipient. If
243    /// the key cannot be exported, this should return None. Additionally, if the underlying
244    /// implementation does not allow moving the raw key into memory (i.e. it cannot call
245    /// [`StreamInterface::encrypt`](crate::stream::StreamInterface::encrypt) or
246    /// [`lock_id_encrypt`](lock_id_encrypt)) then None can also be returned.
247    pub fn export_for_stream_with_rng<R: CryptoRng + RngCore>(
248        &self,
249        csprng: &mut R,
250        stream: &StreamKey,
251    ) -> Option<LockLockbox> {
252        self.interface.self_export_stream(csprng, stream)
253    }
254}
255
256impl fmt::Debug for LockKey {
257    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258        f.debug_struct("LockKey")
259            .field("version", &self.version())
260            .field("lock_id", &self.id().raw_public_key())
261            .finish()
262    }
263}
264
265impl fmt::Display for LockKey {
266    /// Display just the LockId (never the underlying key).
267    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
268        fmt::Display::fmt(self.id(), f)
269    }
270}
271
272impl<T: LockInterface + 'static> From<T> for LockKey {
273    fn from(value: T) -> Self {
274        Self::from_interface(Arc::new(value))
275    }
276}
277
278/// A decryption interface, implemented by anything that can hold a private cryptographic
279/// decryption key.
280///
281/// An implementor must handle all supported Diffie-Hellman algorithms and symmetric-key encryption
282/// algorithms.
283pub trait LockInterface {
284    /// Get the corresponding `LockId` for the private key.
285    fn id(&self) -> &LockId;
286
287    /// Decrypt an exported `LockKey`.
288    fn decrypt_lock_key(&self, lockbox: &LockLockboxRef) -> Result<LockKey, CryptoError>;
289
290    /// Decrypt an exported `IdentityKey`.
291    fn decrypt_identity_key(
292        &self,
293        lockbox: &IdentityLockboxRef,
294    ) -> Result<IdentityKey, CryptoError>;
295
296    /// Decrypt an exported `StreamKey`.
297    fn decrypt_stream_key(&self, lockbox: &StreamLockboxRef) -> Result<StreamKey, CryptoError>;
298
299    /// Decrypt encrypted data.
300    fn decrypt_data(&self, lockbox: &DataLockboxRef) -> Result<Vec<u8>, CryptoError>;
301
302    /// Export the decryption key in a `LockLockbox`, with `receive_lock` as the recipient. If the
303    /// key cannot be exported, this should return None.
304    fn self_export_lock(
305        &self,
306        csprng: &mut dyn CryptoSrc,
307        receive_lock: &LockId,
308    ) -> Option<LockLockbox>;
309
310    /// Export the decryption key in a `LockLockbox`, with `receive_stream` as the recipient. If the
311    /// key cannot be exported, this should return None.
312    fn self_export_stream(
313        &self,
314        csprng: &mut dyn CryptoSrc,
315        receive_stream: &StreamKey,
316    ) -> Option<LockLockbox>;
317}
318
319/// An identifier for a corresponding [`LockKey`] that can be used to encrypt data for that key.
320///
321/// This contains a cryptographic public encryption key.
322///
323/// # Example
324/// ```
325/// # use fog_crypto::lock::*;
326/// # use fog_crypto::lockbox::*;
327/// # let key = LockKey::new();
328/// # let id = key.id().clone();
329///
330/// // We've been given a LockId that we're sending encrypted data to.
331/// println!("LockId(Base58): {}", key.id());
332///
333/// // Encrypt some data for that LockId
334/// let data = b"I am sensitive information, about to be encrypted";
335/// let lockbox = id.encrypt_data(data.as_ref());
336///
337/// // The lockbox can be encoded onto a vec or used as raw bytes.
338/// let mut to_send = Vec::new();
339/// to_send.extend_from_slice(lockbox.as_bytes());
340/// ```
341#[derive(Clone, PartialEq, Eq, Hash)]
342pub struct LockId {
343    inner: x25519_dalek::PublicKey,
344}
345
346impl LockId {
347
348    #[cfg(feature = "getrandom")]
349    /// Encrypt a byte slice into a `DataLockbox`.
350    pub fn encrypt_data(&self, content: &[u8]) -> DataLockbox {
351        self.encrypt_data_with_rng(&mut rand_core::OsRng, content)
352    }
353
354    /// Encrypt a byte slice into a `DataLockbox`. Requires a cryptographic RNG to generate the
355    /// needed nonce.
356    pub fn encrypt_data_with_rng<R>(&self, csprng: &mut R, content: &[u8]) -> DataLockbox
357    where
358        R: CryptoRng + RngCore,
359    {
360        data_lockbox_from_parts(lock_id_encrypt(
361            self,
362            csprng,
363            LockboxType::Data(false),
364            content,
365        ))
366    }
367
368    /// Get the cryptographic algorithm version used for this ID.
369    pub fn version(&self) -> u8 {
370        1u8
371    }
372
373    /// Get the raw public encryption key contained within.
374    pub fn raw_public_key(&self) -> &[u8] {
375        self.inner.as_bytes()
376    }
377
378    /// Convert into a byte vector. For extending an existing byte vector, see
379    /// [`encode_vec`](Self::encode_vec).
380    pub fn as_vec(&self) -> Vec<u8> {
381        let mut v = Vec::new();
382        self.encode_vec(&mut v);
383        v
384    }
385
386    /// Attempt to parse a base58-encoded `LockId`.
387    pub fn from_base58(s: &str) -> Result<Self, CryptoError> {
388        let raw = bs58::decode(s)
389            .into_vec()
390            .or(Err(CryptoError::BadFormat("Not valid Base58")))?;
391        Self::try_from(&raw[..])
392    }
393
394    /// Convert into a base58-encoded `LockId`.
395    pub fn to_base58(&self) -> String {
396        bs58::encode(&(self.as_vec())).into_string()
397    }
398
399    /// Encode onto an existing byte vector. Writes out the version followed by the public signing
400    /// key. It does not include any length information in the encoding.
401    pub fn encode_vec(&self, buf: &mut Vec<u8>) {
402        buf.reserve(self.size());
403        buf.push(self.version());
404        buf.extend_from_slice(self.inner.as_bytes());
405    }
406
407    /// Get the length of this Identity once encoded as bytes.
408    pub fn size(&self) -> usize {
409        1 + V1_LOCK_ID_SIZE
410    }
411}
412
413impl TryFrom<&[u8]> for LockId {
414    type Error = CryptoError;
415
416    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
417        let (&version, data) = value.split_first().ok_or(CryptoError::BadLength {
418            step: "get LockId version",
419            expected: 1,
420            actual: 0,
421        })?;
422        if version != 1u8 {
423            return Err(CryptoError::UnsupportedVersion(version));
424        }
425        if data.len() != V1_LOCK_ID_SIZE {
426            return Err(CryptoError::BadLength {
427                step: "get LockId public key",
428                expected: V1_LOCK_ID_SIZE,
429                actual: data.len(),
430            });
431        }
432        let inner: [u8; V1_LOCK_ID_SIZE] =
433            TryFrom::try_from(data).map_err(|_| CryptoError::BadLength {
434                step: "get LockId public key",
435                expected: V1_LOCK_ID_SIZE,
436                actual: data.len(),
437            })?;
438        Ok(Self {
439            inner: x25519_dalek::PublicKey::from(inner),
440        })
441    }
442}
443
444impl fmt::Debug for LockId {
445    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
446        f.debug_struct("Identity")
447            .field("version", &self.version())
448            .field("public_key", &self.raw_public_key())
449            .finish()
450    }
451}
452
453impl fmt::Display for LockId {
454    /// Display as a base58-encoded string.
455    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
456        write!(f, "{}", self.to_base58())
457    }
458}
459
460impl fmt::LowerHex for LockId {
461    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
462        for byte in self.as_vec().iter() {
463            write!(f, "{:x}", byte)?;
464        }
465        Ok(())
466    }
467}
468
469impl fmt::UpperHex for LockId {
470    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
471        for byte in self.as_vec().iter() {
472            write!(f, "{:X}", byte)?;
473        }
474        Ok(())
475    }
476}
477
478/// Encrypt data with a `LockId`, returning a raw byte vector. Implementors of
479/// [`SignInterface`][SignInterface], [`StreamInterface`][StreamInterface], [`LockInterface`] can
480/// use this when exporting keys.
481///
482/// It's not inside the regular `LockId` methods because those are meant for users, which should
483/// not use this function and instead rely on the various `export...` and `encrypt_data` functions.
484///
485/// [StreamInterface]: crate::stream::StreamInterface
486/// [SignInterface]: crate::identity::SignInterface
487pub fn lock_id_encrypt(
488    id: &LockId,
489    csprng: &mut dyn CryptoSrc,
490    lock_type: LockboxType,
491    content: &[u8],
492) -> Vec<u8> {
493    assert!(
494        !lock_type.is_for_stream(),
495        "Tried to encrypt a non-lock-recipient lockbox with a LockId"
496    );
497    use chacha20poly1305::{ AeadInPlace, XChaCha20Poly1305, XNonce };
498
499    // Generate the ephemeral key and the nonce
500    let mut nonce = [0u8; crate::lockbox::V1_LOCKBOX_NONCE_SIZE];
501    csprng.fill_bytes(nonce.as_mut());
502    let eph = x25519_dalek::EphemeralSecret::random_from_rng(csprng);
503    let eph_pub = x25519_dalek::PublicKey::from(&eph);
504
505    // Get the data lengths and allocate the vec
506    let version = id.version();
507    let tag_len = lockbox_tag_size(version);
508    let nonce_len = lockbox_nonce_size(version);
509    let header_len = 2 + id.size() + eph_pub.as_bytes().len();
510    let len = header_len + nonce_len + content.len() + tag_len;
511    let mut lockbox = Vec::with_capacity(len);
512
513    // Lockbox header & data
514    lockbox.push(version);
515    lockbox.push(lock_type.as_u8());
516    id.encode_vec(&mut lockbox);
517    lockbox.extend_from_slice(eph_pub.as_bytes());
518    lockbox.extend_from_slice(&nonce);
519    lockbox.extend_from_slice(content);
520
521    // Set up the symmetric-key cipher
522    let (additional, nonce_and_content) = lockbox.split_at_mut(header_len);
523    let (_, content) = nonce_and_content.split_at_mut(nonce_len);
524    let secret = eph.diffie_hellman(&id.inner);
525    let aead = XChaCha20Poly1305::new_from_slice(secret.as_bytes()).unwrap();
526    let nonce = XNonce::from(nonce);
527
528    // We unwrap here because the only failure condition on encryption is if the content is really
529    // big. Specifically, for XChaCha20Poly1305, 256 GiB big. This library cannot handle that for
530    // many other reasons, so it's a-ok if we panic here.
531    let tag = aead
532        .encrypt_in_place_detached(&nonce, additional, content)
533        .expect("More data than the cipher can accept was put in");
534    lockbox.extend_from_slice(&tag);
535    lockbox
536}
537
538/// A self-contained implementor of `LockInterface`. It's expected this will be used unless the
539/// decryption key is being managed by the OS or a hardware module.
540pub struct BareLockKey {
541    id: LockId,
542    key: x25519_dalek::StaticSecret,
543}
544
545#[cfg(feature = "getrandom")]
546impl Default for BareLockKey {
547    fn default() -> Self {
548        Self::new()
549    }
550}
551
552impl BareLockKey {
553
554    #[cfg(feature = "getrandom")]
555    /// Generate a random new key.
556    pub fn new() -> Self {
557        let key = x25519_dalek::StaticSecret::random();
558        let id = LockId {
559            inner: (&key).into()
560        };
561        Self { key, id }
562    }
563
564    /// Generate a new key given a cryptographic random number generator.
565    pub fn with_rng<R>(csprng: &mut R) -> Self
566    where
567        R: CryptoRng + RngCore,
568    {
569        Self::with_rng_and_version(csprng, DEFAULT_LOCK_VERSION).unwrap()
570    }
571
572    /// Generate a new key with a specific version, given a cryptographic random number generator.
573    /// Fails if the version isn't supported.
574    pub fn with_rng_and_version<R>(csprng: &mut R, version: u8) -> Result<Self, CryptoError>
575    where
576        R: CryptoRng + RngCore,
577    {
578        if (version < MIN_LOCK_VERSION) || (version > MAX_LOCK_VERSION) {
579            return Err(CryptoError::UnsupportedVersion(version));
580        }
581
582        let key = x25519_dalek::StaticSecret::random_from_rng(csprng);
583        let id = LockId {
584            inner: x25519_dalek::PublicKey::from(&key),
585        };
586
587        Ok(Self { key, id })
588    }
589
590    /// Encode directly to a byte vector. The resulting vector should be zeroized or overwritten
591    /// before being dropped.
592    pub fn encode_vec(&self, buf: &mut Vec<u8>) {
593        buf.reserve(1 + V1_LOCK_KEY_SIZE);
594        buf.push(1u8);
595        // We have to copy the key out and then extend it because x25519_dalek doesn't have a
596        // "as_bytes"-style function. Make sure to zeroize this after it's been used.
597        let mut raw_key = self.key.to_bytes();
598        buf.extend_from_slice(&raw_key);
599        raw_key.zeroize();
600    }
601
602    /// Decrypt a lockbox's individual parts. This is only used by the `LockInterface`
603    /// implementation.
604    fn decrypt_parts(
605        &self,
606        recipient: &LockboxRecipient,
607        parts: LockboxParts,
608    ) -> Result<Vec<u8>, CryptoError> {
609        // Verify this is the right key for this lockbox. It costs us little to do this, and saves
610        // us from potential logic errors
611        if let LockboxRecipient::LockId(id) = recipient {
612            if id != &self.id {
613                return Err(CryptoError::ObjectMismatch(
614                    "LockKey being used on a lockbox meant for a different LockId",
615                ));
616            }
617        } else {
618            return Err(CryptoError::ObjectMismatch(
619                "Attempted to use a LockKey to decrypt a lockbox with a StreamId recipient",
620            ));
621        }
622
623        // Attempt to read the ephemeral key and compute the secret
624        let eph_pub = parts.eph_pub.unwrap();
625        if eph_pub.len() != V1_LOCK_ID_SIZE {
626            return Err(CryptoError::BadLength {
627                step: "get Lockbox ephemeral public key",
628                expected: V1_LOCK_ID_SIZE,
629                actual: eph_pub.len(),
630            });
631        }
632        let eph_pub: [u8; 32] = TryFrom::try_from(eph_pub).map_err(|_| CryptoError::BadLength {
633            step: "get Lockbox ephemeral public key",
634            expected: V1_LOCK_ID_SIZE,
635            actual: eph_pub.len(),
636        })?;
637        let eph_pub = x25519_dalek::PublicKey::from(eph_pub);
638        let secret = self.key.diffie_hellman(&eph_pub);
639
640        // Feed the lockbox's parts into the decryption algorithm
641        use chacha20poly1305::aead::Aead;
642        use chacha20poly1305::*;
643        let aead = XChaCha20Poly1305::new(Key::from_slice(secret.as_bytes()));
644        let nonce = XNonce::from_slice(parts.nonce);
645        let payload = aead::Payload {
646            msg: parts.ciphertext,
647            aad: parts.additional,
648        };
649        aead.decrypt(nonce, payload)
650            .map_err(|_| CryptoError::DecryptFailed)
651    }
652}
653
654impl TryFrom<&[u8]> for BareLockKey {
655    type Error = CryptoError;
656
657    /// Try to decode a raw byte sequence into a private
658    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
659        let (version, raw_key) = value.split_first().ok_or(CryptoError::BadLength {
660            step: "get LockKey version",
661            expected: 1,
662            actual: 0,
663        })?;
664        let version = *version;
665        if version < MIN_LOCK_VERSION {
666            return Err(CryptoError::OldVersion(version));
667        }
668        if version > MAX_LOCK_VERSION {
669            return Err(CryptoError::UnsupportedVersion(version));
670        }
671
672        // Copy the private key, wrap in StaticSecret, and clear out the temporary value.
673        // We have to do this because x25519_dalek doesn't support try_from and provides no other
674        // means to copy in from a byte slice.
675        if raw_key.len() != V1_LOCK_KEY_SIZE {
676            return Err(CryptoError::BadLength {
677                step: "get LockKey key bytes",
678                expected: V1_LOCK_KEY_SIZE,
679                actual: raw_key.len(),
680            });
681        }
682        let mut raw_key: [u8; V1_LOCK_KEY_SIZE] =
683            TryFrom::try_from(raw_key).map_err(|_| CryptoError::BadLength {
684                step: "get LockKey key bytes",
685                expected: V1_LOCK_KEY_SIZE,
686                actual: raw_key.len(),
687            })?;
688        let key = x25519_dalek::StaticSecret::from(raw_key);
689        raw_key.zeroize();
690
691        let public = x25519_dalek::PublicKey::from(&key);
692
693        Ok(Self {
694            key,
695            id: LockId { inner: public },
696        })
697    }
698}
699
700impl LockInterface for BareLockKey {
701    fn id(&self) -> &LockId {
702        &self.id
703    }
704
705    fn decrypt_lock_key(&self, lockbox: &LockLockboxRef) -> Result<LockKey, CryptoError> {
706        let recipient = lockbox.recipient();
707        let parts = lockbox.as_parts();
708        let mut key = self.decrypt_parts(&recipient, parts)?;
709        let result = BareLockKey::try_from(key.as_ref());
710        key.zeroize();
711        Ok(LockKey::from_interface(Arc::new(result?)))
712    }
713
714    fn decrypt_identity_key(
715        &self,
716        lockbox: &IdentityLockboxRef,
717    ) -> Result<IdentityKey, CryptoError> {
718        let recipient = lockbox.recipient();
719        let parts = lockbox.as_parts();
720        let mut key = self.decrypt_parts(&recipient, parts)?;
721        let result = BareIdKey::try_from(key.as_ref());
722        key.zeroize();
723        Ok(IdentityKey::from_interface(Arc::new(result?)))
724    }
725
726    fn decrypt_stream_key(&self, lockbox: &StreamLockboxRef) -> Result<StreamKey, CryptoError> {
727        let recipient = lockbox.recipient();
728        let parts = lockbox.as_parts();
729        let mut key = self.decrypt_parts(&recipient, parts)?;
730        let result = BareStreamKey::try_from(key.as_ref());
731        key.zeroize();
732        Ok(StreamKey::from_interface(Arc::new(result?)))
733    }
734
735    fn decrypt_data(&self, lockbox: &DataLockboxRef) -> Result<Vec<u8>, CryptoError> {
736        let recipient = lockbox.recipient();
737        let parts = lockbox.as_parts();
738        self.decrypt_parts(&recipient, parts)
739    }
740
741    fn self_export_lock(
742        &self,
743        csprng: &mut dyn CryptoSrc,
744        receive_lock: &LockId,
745    ) -> Option<LockLockbox> {
746        let mut raw_secret = Vec::new(); // Make 100% certain this is zeroized at the end!
747        self.encode_vec(&mut raw_secret);
748        let lockbox_vec =
749            lock_id_encrypt(receive_lock, csprng, LockboxType::Lock(false), &raw_secret);
750        raw_secret.zeroize();
751        debug_assert!(raw_secret.iter().all(|&x| x == 0)); // You didn't remove the zeroize call, right?
752        Some(lock_lockbox_from_parts(lockbox_vec))
753    }
754
755    fn self_export_stream(
756        &self,
757        csprng: &mut dyn CryptoSrc,
758        receive_stream: &StreamKey,
759    ) -> Option<LockLockbox> {
760        let mut raw_secret = Vec::new(); // Make 100% certain this is zeroized at the end!
761        self.encode_vec(&mut raw_secret);
762        let lockbox_vec =
763            stream_key_encrypt(receive_stream, csprng, LockboxType::Lock(true), &raw_secret);
764        raw_secret.zeroize();
765        debug_assert!(raw_secret.iter().all(|&x| x == 0)); // You didn't remove the zeroize call, right?
766        Some(lock_lockbox_from_parts(lockbox_vec))
767    }
768}
769
770#[cfg(test)]
771mod tests {
772    use super::*;
773
774    #[test]
775    fn basics() {
776        let mut csprng = rand::rngs::OsRng;
777        let key = LockKey::with_rng(&mut csprng);
778        assert_eq!(key.version(), DEFAULT_LOCK_VERSION);
779        let key = LockKey::with_rng_and_version(&mut csprng, DEFAULT_LOCK_VERSION).unwrap();
780        assert_eq!(key.version(), DEFAULT_LOCK_VERSION);
781        let result = LockKey::with_rng_and_version(&mut csprng, 99u8);
782        if let Err(CryptoError::UnsupportedVersion(99u8)) = result {
783        } else {
784            panic!("Didn't get expected error on with_rng_and_version");
785        }
786    }
787
788    #[test]
789    fn display() {
790        let mut csprng = rand::rngs::OsRng;
791        let key = LockKey::with_rng(&mut csprng);
792        let disp_key = format!("{}", &key);
793        let disp_id = format!("{}", key.id());
794        let base58 = key.id().to_base58();
795        assert_eq!(disp_key, disp_id);
796        assert_eq!(disp_key, base58);
797        assert!(disp_key.len() > 1);
798    }
799
800    #[test]
801    fn base58() {
802        let mut csprng = rand::rngs::OsRng;
803        let key = LockKey::with_rng(&mut csprng);
804        let mut base58 = key.id().to_base58();
805        assert!(base58.len() > 1);
806        let id = LockId::from_base58(&base58).unwrap();
807        assert_eq!(&id, key.id());
808        base58.push('a');
809        base58.push('a');
810        assert!(LockId::from_base58(&base58).is_err());
811        base58.pop();
812        base58.pop();
813        base58.pop();
814        assert!(LockId::from_base58(&base58).is_err());
815    }
816
817    #[test]
818    fn encode() {
819        let mut csprng = rand::rngs::OsRng;
820        let key = LockKey::with_rng(&mut csprng);
821        let id = key.id();
822        let mut id_vec = Vec::new();
823        id.encode_vec(&mut id_vec);
824        assert_eq!(id_vec.len(), id.size());
825        let id = LockId::try_from(&id_vec[..]).unwrap();
826        assert_eq!(&id, key.id());
827    }
828
829    fn corrupt_version<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
830    where
831        F1: Fn(&[u8]) -> bool,
832        F2: Fn(&[u8]) -> bool,
833    {
834        // Version byte corruption
835        let version = enc[0];
836        enc[0] = 0;
837        assert!(!check_decode(&enc[..]));
838        enc[0] = 2;
839        assert!(!check_decode(&enc[..]));
840        enc[0] = version;
841        assert!(check_decrypt(&enc[..]));
842    }
843
844    fn corrupt_type<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
845    where
846        F1: Fn(&[u8]) -> bool,
847        F2: Fn(&[u8]) -> bool,
848    {
849        // Type byte corruption
850        enc[1] |= 0x80;
851        assert!(!check_decode(&enc[..]));
852        enc[1] &= 0x07;
853        assert!(check_decrypt(&enc[..]));
854        enc[1] = (enc[1] + 1) & 0x7; // First increment should still decode, but have bad recipient
855        assert!(check_decode(&enc[..]));
856        assert!(!check_decrypt(&enc[..]));
857        for _ in 0..6 {
858            // Remaining increments should put it outside of expected lockbox type
859            enc[1] = (enc[1] + 1) & 0x7;
860            assert!(!check_decode(&enc[..]));
861        }
862        enc[1] = (enc[1] + 1) & 0x7;
863        assert!(check_decrypt(&enc[..]));
864    }
865
866    fn corrupt_id<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
867    where
868        F1: Fn(&[u8]) -> bool,
869        F2: Fn(&[u8]) -> bool,
870    {
871        // Identity corruption - 2 is ID version, 3 is first byte of ID
872        enc[2] = 0;
873        assert!(!check_decode(&enc[..]));
874        enc[2] = 2;
875        assert!(!check_decode(&enc[..]));
876        enc[2] = DEFAULT_LOCK_VERSION;
877        assert!(check_decrypt(&enc[..]));
878        enc[3] ^= 0xFF;
879        assert!(!check_decrypt(&enc[..]));
880        enc[3] ^= 0xFF;
881        assert!(check_decrypt(&enc[..]));
882    }
883
884    fn corrupt_ephemeral<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
885    where
886        F1: Fn(&[u8]) -> bool,
887        F2: Fn(&[u8]) -> bool,
888    {
889        // Ephemeral Key corruption - 35 is first byte of ephemeral public key
890        enc[35] ^= 0xFF;
891        assert!(check_decode(&enc[..]));
892        assert!(!check_decrypt(&enc[..]));
893        enc[35] ^= 0xFF;
894        assert!(check_decrypt(&enc[..]));
895    }
896
897    fn corrupt_nonce<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
898    where
899        F1: Fn(&[u8]) -> bool,
900        F2: Fn(&[u8]) -> bool,
901    {
902        // Nonce corruption - 67 is first byte of the nonce
903        enc[67] ^= 0xFF;
904        assert!(check_decode(&enc[..]));
905        assert!(!check_decrypt(&enc[..]));
906        enc[67] ^= 0xFF;
907        assert!(check_decrypt(&enc[..]));
908    }
909
910    fn corrupt_ciphertext<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
911    where
912        F1: Fn(&[u8]) -> bool,
913        F2: Fn(&[u8]) -> bool,
914    {
915        // Ciphertext corruption - 91 is first byte of ciphertext
916        enc[91] ^= 0xFF;
917        assert!(check_decode(&enc[..]));
918        assert!(!check_decrypt(&enc[..]));
919        enc[91] ^= 0xFF;
920        assert!(check_decrypt(&enc[..]));
921    }
922
923    fn corrupt_tag<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
924    where
925        F1: Fn(&[u8]) -> bool,
926        F2: Fn(&[u8]) -> bool,
927    {
928        // Tag corruption - corrupt the last byte
929        let tag_end = enc.last_mut().unwrap();
930        *tag_end ^= 0xFF;
931        assert!(check_decode(&enc[..]));
932        assert!(!check_decrypt(&enc[..]));
933        let tag_end = enc.last_mut().unwrap();
934        *tag_end ^= 0xFF;
935        assert!(check_decrypt(&enc[..]));
936    }
937
938    fn corrupt_length_extend<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
939    where
940        F1: Fn(&[u8]) -> bool,
941        F2: Fn(&[u8]) -> bool,
942    {
943        // Length extension
944        enc.push(0);
945        assert!(check_decode(&enc[..]));
946        assert!(!check_decrypt(&enc[..]));
947        enc.pop();
948        assert!(check_decrypt(&enc[..]));
949    }
950
951    fn corrupt_truncation<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
952    where
953        F1: Fn(&[u8]) -> bool,
954        F2: Fn(&[u8]) -> bool,
955    {
956        // Early truncation
957        enc.pop();
958        assert!(check_decode(&enc[..]));
959        assert!(!check_decrypt(&enc[..]));
960    }
961
962    fn corrupt_each_byte<F1, F2>(mut enc: Vec<u8>, _check_decode: F1, check_decrypt: F2)
963    where
964        F1: Fn(&[u8]) -> bool,
965        F2: Fn(&[u8]) -> bool,
966    {
967        for i in 0..enc.len() {
968            enc[i] ^= 0xFF;
969            assert!(!check_decrypt(&enc[..]));
970            enc[i] ^= 0xFF;
971        }
972    }
973
974    fn corrupt_inner_version<F: Fn(&[u8]) -> bool>(mut content: Vec<u8>, check_sequence: F) {
975        // Corrupt the version byte
976        content[0] = 0u8;
977        assert!(!check_sequence(&content[..]));
978        // Corrupt the version byte differently
979        content[0] = 99u8;
980        assert!(!check_sequence(&content[..]));
981    }
982
983    fn corrupt_inner_length_extend<F: Fn(&[u8]) -> bool>(mut content: Vec<u8>, check_sequence: F) {
984        content.push(0u8);
985        assert!(!check_sequence(&content[..]));
986    }
987
988    fn corrupt_inner_truncate<F: Fn(&[u8]) -> bool>(mut content: Vec<u8>, check_sequence: F) {
989        content.pop();
990        assert!(!check_sequence(&content[..]));
991    }
992
993    fn setup_data() -> (Vec<u8>, impl Fn(&[u8]) -> bool, impl Fn(&[u8]) -> bool) {
994        // Setup
995        let key = LockKey::new();
996        let message = b"I am a test message, going undercover";
997
998        // Encrypt
999        let lockbox = key.id().encrypt_data(message);
1000        let recipient = LockboxRecipient::LockId(key.id().clone());
1001        assert_eq!(recipient, lockbox.recipient());
1002        let enc = Vec::from(lockbox.as_bytes());
1003        (
1004            enc,
1005            |enc| DataLockboxRef::from_bytes(enc).is_ok(),
1006            move |enc| {
1007                let dec_lockbox = if let Ok(d) = DataLockboxRef::from_bytes(enc) {
1008                    d
1009                } else {
1010                    return false;
1011                };
1012                if LockboxRecipient::LockId(key.id().clone()) != dec_lockbox.recipient() {
1013                    return false;
1014                }
1015                if let Ok(dec) = key.decrypt_data(dec_lockbox) {
1016                    dec == message
1017                } else {
1018                    false
1019                }
1020            },
1021        )
1022    }
1023
1024    #[test]
1025    fn data_clean_decrypt() {
1026        let (enc, _check_decode, check_decrypt) = setup_data();
1027        assert!(check_decrypt(&enc[..]));
1028    }
1029
1030    #[test]
1031    fn data_corrupt_version() {
1032        let (enc, check_decode, check_decrypt) = setup_data();
1033        corrupt_version(enc, check_decode, check_decrypt);
1034    }
1035
1036    #[test]
1037    fn data_corrupt_type() {
1038        let (enc, check_decode, check_decrypt) = setup_data();
1039        corrupt_type(enc, check_decode, check_decrypt);
1040    }
1041
1042    #[test]
1043    fn data_corrupt_id() {
1044        let (enc, check_decode, check_decrypt) = setup_data();
1045        corrupt_id(enc, check_decode, check_decrypt);
1046    }
1047
1048    #[test]
1049    fn data_corrupt_ephemeral() {
1050        let (enc, check_decode, check_decrypt) = setup_data();
1051        corrupt_ephemeral(enc, check_decode, check_decrypt);
1052    }
1053
1054    #[test]
1055    fn data_corrupt_nonce() {
1056        let (enc, check_decode, check_decrypt) = setup_data();
1057        corrupt_nonce(enc, check_decode, check_decrypt);
1058    }
1059
1060    #[test]
1061    fn data_corrupt_ciphertext() {
1062        let (enc, check_decode, check_decrypt) = setup_data();
1063        corrupt_ciphertext(enc, check_decode, check_decrypt);
1064    }
1065
1066    #[test]
1067    fn data_corrupt_tag() {
1068        let (enc, check_decode, check_decrypt) = setup_data();
1069        corrupt_tag(enc, check_decode, check_decrypt);
1070    }
1071
1072    #[test]
1073    fn data_corrupt_length_extend() {
1074        let (enc, check_decode, check_decrypt) = setup_data();
1075        corrupt_length_extend(enc, check_decode, check_decrypt);
1076    }
1077
1078    #[test]
1079    fn data_corrupt_truncation() {
1080        let (enc, check_decode, check_decrypt) = setup_data();
1081        corrupt_truncation(enc, check_decode, check_decrypt);
1082    }
1083
1084    #[test]
1085    fn data_corrupt_each_byte() {
1086        let (enc, check_decode, check_decrypt) = setup_data();
1087        corrupt_each_byte(enc, check_decode, check_decrypt);
1088    }
1089
1090    fn setup_id() -> (Vec<u8>, impl Fn(&[u8]) -> bool, impl Fn(&[u8]) -> bool) {
1091        // Setup
1092        let key = LockKey::new();
1093        let to_send = IdentityKey::new();
1094
1095        // Encrypt
1096        let lockbox = to_send.export_for_lock(key.id()).unwrap();
1097        let recipient = LockboxRecipient::LockId(key.id().clone());
1098        assert_eq!(recipient, lockbox.recipient());
1099        let enc = Vec::from(lockbox.as_bytes());
1100        (
1101            enc,
1102            |enc| IdentityLockboxRef::from_bytes(enc).is_ok(),
1103            move |enc| {
1104                let dec_lockbox = if let Ok(d) = IdentityLockboxRef::from_bytes(enc) {
1105                    d
1106                } else {
1107                    return false;
1108                };
1109                if LockboxRecipient::LockId(key.id().clone()) != dec_lockbox.recipient() {
1110                    return false;
1111                }
1112                if let Ok(dec) = key.decrypt_identity_key(dec_lockbox) {
1113                    dec.id() == to_send.id()
1114                } else {
1115                    false
1116                }
1117            },
1118        )
1119    }
1120
1121    #[test]
1122    fn id_clean_decrypt() {
1123        let (enc, _check_decode, check_decrypt) = setup_id();
1124        assert!(check_decrypt(&enc[..]));
1125    }
1126
1127    #[test]
1128    fn id_corrupt_version() {
1129        let (enc, check_decode, check_decrypt) = setup_id();
1130        corrupt_version(enc, check_decode, check_decrypt);
1131    }
1132
1133    #[test]
1134    fn id_corrupt_type() {
1135        let (enc, check_decode, check_decrypt) = setup_id();
1136        corrupt_type(enc, check_decode, check_decrypt);
1137    }
1138
1139    #[test]
1140    fn id_corrupt_id() {
1141        let (enc, check_decode, check_decrypt) = setup_id();
1142        corrupt_id(enc, check_decode, check_decrypt);
1143    }
1144
1145    #[test]
1146    fn id_corrupt_ephemeral() {
1147        let (enc, check_decode, check_decrypt) = setup_id();
1148        corrupt_ephemeral(enc, check_decode, check_decrypt);
1149    }
1150
1151    #[test]
1152    fn id_corrupt_nonce() {
1153        let (enc, check_decode, check_decrypt) = setup_id();
1154        corrupt_nonce(enc, check_decode, check_decrypt);
1155    }
1156
1157    #[test]
1158    fn id_corrupt_ciphertext() {
1159        let (enc, check_decode, check_decrypt) = setup_id();
1160        corrupt_ciphertext(enc, check_decode, check_decrypt);
1161    }
1162
1163    #[test]
1164    fn id_corrupt_tag() {
1165        let (enc, check_decode, check_decrypt) = setup_id();
1166        corrupt_tag(enc, check_decode, check_decrypt);
1167    }
1168
1169    #[test]
1170    fn id_corrupt_length_extend() {
1171        let (enc, check_decode, check_decrypt) = setup_id();
1172        corrupt_length_extend(enc, check_decode, check_decrypt);
1173    }
1174
1175    #[test]
1176    fn id_corrupt_truncation() {
1177        let (enc, check_decode, check_decrypt) = setup_id();
1178        corrupt_truncation(enc, check_decode, check_decrypt);
1179    }
1180
1181    #[test]
1182    fn id_corrupt_each_byte() {
1183        let (enc, check_decode, check_decrypt) = setup_id();
1184        corrupt_each_byte(enc, check_decode, check_decrypt);
1185    }
1186
1187    fn setup_id_raw() -> (Vec<u8>, impl Fn(&[u8]) -> bool) {
1188        use crate::identity::SignInterface;
1189        // Setup
1190        let mut csprng = rand::rngs::OsRng;
1191        let key = LockKey::with_rng(&mut csprng);
1192        let to_send = crate::BareIdKey::with_rng(&mut csprng);
1193
1194        // Encrypt
1195        let mut content = Vec::new();
1196        to_send.encode_vec(&mut content);
1197
1198        (content, move |content| {
1199            let mut csprng = rand::rngs::OsRng;
1200            let lockbox = identity_lockbox_from_parts(crate::lock::lock_id_encrypt(
1201                key.id(),
1202                &mut csprng,
1203                crate::lockbox::LockboxType::Identity(false),
1204                content,
1205            ));
1206            let enc = Vec::from(lockbox.as_bytes());
1207            let lockbox = if let Ok(l) = IdentityLockboxRef::from_bytes(&enc[..]) {
1208                l
1209            } else {
1210                return false;
1211            };
1212            if let Ok(dec) = key.decrypt_identity_key(lockbox) {
1213                dec.id() == to_send.id()
1214            } else {
1215                false
1216            }
1217        })
1218    }
1219
1220    #[test]
1221    fn id_inner_ok() {
1222        let (content, check_sequence) = setup_id_raw();
1223        assert!(check_sequence(&content[..]));
1224    }
1225
1226    #[test]
1227    fn id_corrupt_inner_version() {
1228        let (content, check_sequence) = setup_id_raw();
1229        corrupt_inner_version(content, check_sequence);
1230    }
1231
1232    #[test]
1233    fn id_corrupt_inner_length_extend() {
1234        let (content, check_sequence) = setup_id_raw();
1235        corrupt_inner_length_extend(content, check_sequence);
1236    }
1237
1238    #[test]
1239    fn id_corrupt_inner_truncate() {
1240        let (content, check_sequence) = setup_id_raw();
1241        corrupt_inner_truncate(content, check_sequence);
1242    }
1243
1244    fn setup_lock_stream() -> (Vec<u8>, impl Fn(&[u8]) -> bool, impl Fn(&[u8]) -> bool) {
1245        // Setup
1246        let key = LockKey::new();
1247        let to_send = StreamKey::new();
1248
1249        // Encrypt
1250        let lockbox = to_send.export_for_lock(key.id()).unwrap();
1251        let recipient = LockboxRecipient::LockId(key.id().clone());
1252        assert_eq!(recipient, lockbox.recipient());
1253        let enc = Vec::from(lockbox.as_bytes());
1254        (
1255            enc,
1256            |enc| StreamLockboxRef::from_bytes(enc).is_ok(),
1257            move |enc| {
1258                let dec_lockbox = if let Ok(d) = StreamLockboxRef::from_bytes(enc) {
1259                    d
1260                } else {
1261                    return false;
1262                };
1263                if LockboxRecipient::LockId(key.id().clone()) != dec_lockbox.recipient() {
1264                    return false;
1265                }
1266                if let Ok(dec) = key.decrypt_stream_key(dec_lockbox) {
1267                    dec.id() == to_send.id()
1268                } else {
1269                    false
1270                }
1271            },
1272        )
1273    }
1274
1275    #[test]
1276    fn stream_clean_decrypt() {
1277        let (enc, _check_decode, check_decrypt) = setup_lock_stream();
1278        assert!(check_decrypt(&enc[..]));
1279    }
1280
1281    #[test]
1282    fn stream_corrupt_version() {
1283        let (enc, check_decode, check_decrypt) = setup_lock_stream();
1284        corrupt_version(enc, check_decode, check_decrypt);
1285    }
1286
1287    #[test]
1288    fn stream_corrupt_type() {
1289        let (enc, check_decode, check_decrypt) = setup_lock_stream();
1290        corrupt_type(enc, check_decode, check_decrypt);
1291    }
1292
1293    #[test]
1294    fn stream_corrupt_id() {
1295        let (enc, check_decode, check_decrypt) = setup_lock_stream();
1296        corrupt_id(enc, check_decode, check_decrypt);
1297    }
1298
1299    #[test]
1300    fn stream_corrupt_ephemeral() {
1301        let (enc, check_decode, check_decrypt) = setup_lock_stream();
1302        corrupt_ephemeral(enc, check_decode, check_decrypt);
1303    }
1304
1305    #[test]
1306    fn stream_corrupt_nonce() {
1307        let (enc, check_decode, check_decrypt) = setup_lock_stream();
1308        corrupt_nonce(enc, check_decode, check_decrypt);
1309    }
1310
1311    #[test]
1312    fn stream_corrupt_ciphertext() {
1313        let (enc, check_decode, check_decrypt) = setup_lock_stream();
1314        corrupt_ciphertext(enc, check_decode, check_decrypt);
1315    }
1316
1317    #[test]
1318    fn stream_corrupt_tag() {
1319        let (enc, check_decode, check_decrypt) = setup_lock_stream();
1320        corrupt_tag(enc, check_decode, check_decrypt);
1321    }
1322
1323    #[test]
1324    fn stream_corrupt_length_extend() {
1325        let (enc, check_decode, check_decrypt) = setup_lock_stream();
1326        corrupt_length_extend(enc, check_decode, check_decrypt);
1327    }
1328
1329    #[test]
1330    fn stream_corrupt_truncation() {
1331        let (enc, check_decode, check_decrypt) = setup_lock_stream();
1332        corrupt_truncation(enc, check_decode, check_decrypt);
1333    }
1334
1335    #[test]
1336    fn stream_corrupt_each_byte() {
1337        let (enc, check_decode, check_decrypt) = setup_lock_stream();
1338        corrupt_each_byte(enc, check_decode, check_decrypt);
1339    }
1340
1341    fn setup_lock_stream_raw() -> (Vec<u8>, impl Fn(&[u8]) -> bool) {
1342        use crate::stream::StreamInterface;
1343        // Setup
1344        let mut csprng = rand::rngs::OsRng;
1345        let key = LockKey::with_rng(&mut csprng);
1346        let to_send = crate::BareStreamKey::with_rng(&mut csprng);
1347
1348        // Encrypt
1349        let mut content = Vec::new();
1350        to_send.encode_vec(&mut content);
1351
1352        (content, move |content| {
1353            let mut csprng = rand::rngs::OsRng;
1354            let lockbox = stream_lockbox_from_parts(crate::lock::lock_id_encrypt(
1355                key.id(),
1356                &mut csprng,
1357                crate::lockbox::LockboxType::Stream(false),
1358                content,
1359            ));
1360            let enc = Vec::from(lockbox.as_bytes());
1361            let lockbox = if let Ok(l) = StreamLockboxRef::from_bytes(&enc[..]) {
1362                l
1363            } else {
1364                return false;
1365            };
1366            if let Ok(dec) = key.decrypt_stream_key(lockbox) {
1367                dec.id() == to_send.id()
1368            } else {
1369                false
1370            }
1371        })
1372    }
1373
1374    #[test]
1375    fn stream_inner_ok() {
1376        let (content, check_sequence) = setup_lock_stream_raw();
1377        assert!(check_sequence(&content[..]));
1378    }
1379
1380    #[test]
1381    fn stream_corrupt_inner_version() {
1382        let (content, check_sequence) = setup_lock_stream_raw();
1383        corrupt_inner_version(content, check_sequence);
1384    }
1385
1386    #[test]
1387    fn stream_corrupt_inner_length_extend() {
1388        let (content, check_sequence) = setup_lock_stream_raw();
1389        corrupt_inner_length_extend(content, check_sequence);
1390    }
1391
1392    #[test]
1393    fn stream_corrupt_inner_truncate() {
1394        let (content, check_sequence) = setup_lock_stream_raw();
1395        corrupt_inner_truncate(content, check_sequence);
1396    }
1397
1398    fn setup_lock() -> (Vec<u8>, impl Fn(&[u8]) -> bool, impl Fn(&[u8]) -> bool) {
1399        // Setup
1400        let key = LockKey::new();
1401        let to_send = LockKey::new();
1402
1403        // Encrypt
1404        let lockbox = to_send.export_for_lock(key.id()).unwrap();
1405        let recipient = LockboxRecipient::LockId(key.id().clone());
1406        assert_eq!(recipient, lockbox.recipient());
1407        let enc = Vec::from(lockbox.as_bytes());
1408        (
1409            enc,
1410            |enc| LockLockboxRef::from_bytes(enc).is_ok(),
1411            move |enc| {
1412                let dec_lockbox = if let Ok(d) = LockLockboxRef::from_bytes(enc) {
1413                    d
1414                } else {
1415                    return false;
1416                };
1417                if LockboxRecipient::LockId(key.id().clone()) != dec_lockbox.recipient() {
1418                    return false;
1419                }
1420                if let Ok(dec) = key.decrypt_lock_key(dec_lockbox) {
1421                    dec.id() == to_send.id()
1422                } else {
1423                    false
1424                }
1425            },
1426        )
1427    }
1428
1429    #[test]
1430    fn lock_clean_decrypt() {
1431        let (enc, _check_decode, check_decrypt) = setup_lock();
1432        assert!(check_decrypt(&enc[..]));
1433    }
1434
1435    #[test]
1436    fn lock_corrupt_version() {
1437        let (enc, check_decode, check_decrypt) = setup_lock();
1438        corrupt_version(enc, check_decode, check_decrypt);
1439    }
1440
1441    #[test]
1442    fn lock_corrupt_type() {
1443        let (enc, check_decode, check_decrypt) = setup_lock();
1444        corrupt_type(enc, check_decode, check_decrypt);
1445    }
1446
1447    #[test]
1448    fn lock_corrupt_id() {
1449        let (enc, check_decode, check_decrypt) = setup_lock();
1450        corrupt_id(enc, check_decode, check_decrypt);
1451    }
1452
1453    #[test]
1454    fn lock_corrupt_ephemeral() {
1455        let (enc, check_decode, check_decrypt) = setup_lock();
1456        corrupt_ephemeral(enc, check_decode, check_decrypt);
1457    }
1458
1459    #[test]
1460    fn lock_corrupt_nonce() {
1461        let (enc, check_decode, check_decrypt) = setup_lock();
1462        corrupt_nonce(enc, check_decode, check_decrypt);
1463    }
1464
1465    #[test]
1466    fn lock_corrupt_ciphertext() {
1467        let (enc, check_decode, check_decrypt) = setup_lock();
1468        corrupt_ciphertext(enc, check_decode, check_decrypt);
1469    }
1470
1471    #[test]
1472    fn lock_corrupt_tag() {
1473        let (enc, check_decode, check_decrypt) = setup_lock();
1474        corrupt_tag(enc, check_decode, check_decrypt);
1475    }
1476
1477    #[test]
1478    fn lock_corrupt_length_extend() {
1479        let (enc, check_decode, check_decrypt) = setup_lock();
1480        corrupt_length_extend(enc, check_decode, check_decrypt);
1481    }
1482
1483    #[test]
1484    fn lock_corrupt_truncation() {
1485        let (enc, check_decode, check_decrypt) = setup_lock();
1486        corrupt_truncation(enc, check_decode, check_decrypt);
1487    }
1488
1489    #[test]
1490    fn lock_corrupt_each_byte() {
1491        let (enc, check_decode, check_decrypt) = setup_lock();
1492        corrupt_each_byte(enc, check_decode, check_decrypt);
1493    }
1494
1495    fn setup_lock_raw() -> (Vec<u8>, impl Fn(&[u8]) -> bool) {
1496        // Setup
1497        let mut csprng = rand::rngs::OsRng;
1498        let key = LockKey::with_rng(&mut csprng);
1499        let to_send = crate::BareLockKey::with_rng(&mut csprng);
1500
1501        // Encrypt
1502        let mut content = Vec::new();
1503        to_send.encode_vec(&mut content);
1504
1505        (content, move |content| {
1506            let mut csprng = rand::rngs::OsRng;
1507            let lockbox = lock_lockbox_from_parts(crate::lock::lock_id_encrypt(
1508                key.id(),
1509                &mut csprng,
1510                crate::lockbox::LockboxType::Lock(false),
1511                content,
1512            ));
1513            let enc = Vec::from(lockbox.as_bytes());
1514            let lockbox = if let Ok(l) = LockLockboxRef::from_bytes(&enc[..]) {
1515                l
1516            } else {
1517                return false;
1518            };
1519            if let Ok(dec) = key.decrypt_lock_key(lockbox) {
1520                dec.id() == to_send.id()
1521            } else {
1522                false
1523            }
1524        })
1525    }
1526
1527    #[test]
1528    fn lock_inner_ok() {
1529        let (content, check_sequence) = setup_lock_raw();
1530        assert!(check_sequence(&content[..]));
1531    }
1532
1533    #[test]
1534    fn lock_corrupt_inner_version() {
1535        let (content, check_sequence) = setup_lock_raw();
1536        corrupt_inner_version(content, check_sequence);
1537    }
1538
1539    #[test]
1540    fn lock_corrupt_inner_length_extend() {
1541        let (content, check_sequence) = setup_lock_raw();
1542        corrupt_inner_length_extend(content, check_sequence);
1543    }
1544
1545    #[test]
1546    fn lock_corrupt_inner_truncate() {
1547        let (content, check_sequence) = setup_lock_raw();
1548        corrupt_inner_truncate(content, check_sequence);
1549    }
1550}