Skip to main content

bitwarden_crypto/hazmat/symmetric_encryption/
mod.rs

1//! # Symmetric key encryption
2//!
3//! Low-level ("hazmat") authenticated symmetric ciphers, exposed behind two traits:
4//! - [`Aead`]: authenticated encryption *with* associated data. Implemented by AES-256-GCM
5//!   ([`Aes256Gcm`]), XAES-256-GCM ([`XAes256Gcm`]), XChaCha20-Poly1305 ([`XChaCha20Poly1305`]),
6//!   and AES-256-CBC-HMAC-SHA256 ([`Aes256CbcHmacSha256Aead`]).
7//!
8//! These are dangerous primitives that operate directly on raw key material. In most cases you
9//! should use the higher-level [`safe`](crate::safe) module (e.g. the password-protected key
10//! envelope or data envelope) instead.
11
12use crate::CryptoError;
13pub(crate) mod aes256_cbc;
14
15#[allow(dead_code)]
16#[derive(Debug, PartialEq, Eq)]
17pub(crate) enum SymmetricEncryptionError {
18    /// The input is malformed — wrong length, invalid padding, or otherwise not a valid
19    /// ciphertext for the cipher.
20    FormatWrong,
21    /// The integrity check (MAC / authentication tag) failed; the ciphertext, associated data,
22    /// nonce/IV, and key do not match.
23    IntegrityCheckFailed,
24}
25
26impl From<SymmetricEncryptionError> for CryptoError {
27    fn from(_: SymmetricEncryptionError) -> Self {
28        CryptoError::KeyDecrypt
29    }
30}
31pub(crate) mod aes256_cbc_hmac_sha256_ae;
32pub(crate) mod aes256_cbc_hmac_sha256_aead;
33pub(crate) mod aes_gcm;
34pub(crate) mod xaes_256_gcm;
35pub(crate) mod xchacha20;
36
37#[allow(unused_imports)]
38pub(crate) use aes_gcm::Aes256Gcm;
39pub(crate) use aes256_cbc::Aes256Cbc;
40pub(crate) use aes256_cbc_hmac_sha256_ae::Aes256CbcHmacSha256;
41#[allow(unused_imports)]
42pub(crate) use aes256_cbc_hmac_sha256_aead::Aes256CbcHmacSha256Aead;
43#[allow(unused_imports)]
44pub(crate) use xaes_256_gcm::XAes256Gcm;
45#[allow(unused_imports)]
46pub(crate) use xchacha20::XChaCha20Poly1305;
47
48/// Authenticated encryption **with** associated data (AEAD).
49///
50/// In addition to encrypting and authenticating the plaintext, a cipher implementing this trait
51/// authenticates (but does not encrypt) caller-supplied associated data. The exact same associated
52/// data must be supplied to [`decrypt`](Aead::decrypt) for authentication to succeed.
53#[allow(dead_code)]
54pub(crate) trait Aead {
55    /// Key material used by the cipher.
56    type Key;
57    /// Authenticated ciphertext (the encrypted bytes). The nonce is tracked separately, by the
58    /// caller.
59    type Ciphertext;
60    /// The per-message nonce. A fresh nonce must be supplied for every encryption under a given
61    /// key.
62    type Nonce;
63
64    /// Encrypts `plaintext` under `key` with `nonce`, authenticating `associated_data` along with
65    /// the ciphertext.
66    ///
67    /// The same `nonce` must be supplied to [`decrypt`](Aead::decrypt). A fresh nonce must be used
68    /// for every message encrypted under a given key.
69    fn encrypt(
70        key: &Self::Key,
71        nonce: &Self::Nonce,
72        plaintext: &[u8],
73        associated_data: &[u8],
74    ) -> Self::Ciphertext;
75
76    /// Authenticates and decrypts `ciphertext` under `key` with `nonce`, verifying
77    /// `associated_data`.
78    ///
79    /// Returns [`CryptoError::KeyDecrypt`] if authentication fails (including a mismatch of
80    /// `associated_data` or `nonce`) or the ciphertext is malformed.
81    fn decrypt(
82        key: &Self::Key,
83        nonce: &Self::Nonce,
84        ciphertext: &Self::Ciphertext,
85        associated_data: &[u8],
86    ) -> Result<Vec<u8>, CryptoError>;
87}