Skip to main content

secret_manager/
encryptor.rs

1use async_trait::async_trait;
2use thiserror::Error;
3
4/// Errors returned by [`KeyEncryptor`] implementations.
5#[derive(Debug, Error)]
6pub enum EncryptorError {
7    /// The ciphertext was produced with a key version this encryptor cannot decrypt.
8    #[error("wrong key version: {0}")]
9    WrongKeyVersion(u8),
10    /// The encryption operation failed.
11    #[error("encryption failed: {0}")]
12    EncryptionFailed(String),
13    /// The decryption operation failed.
14    #[error("decryption failed: {0}")]
15    DecryptionFailed(String),
16    /// A nonce is required for decryption but was not present in the payload.
17    #[error("missing nonce")]
18    MissingNonce,
19    /// An AWS KMS API error occurred.
20    #[cfg(feature = "aws-kms")]
21    #[error("KMS error: {0}")]
22    Kms(Box<dyn std::error::Error + Send + Sync + 'static>),
23}
24
25/// An encrypted payload produced by a [`KeyEncryptor`].
26#[derive(Clone)]
27pub struct Encrypted {
28    /// The encrypted key bytes (ciphertext).
29    pub ciphertext: Vec<u8>,
30    /// The nonce/IV used during encryption (`None` for KMS/no-op, which manage their own IV).
31    pub nonce: Option<[u8; 12]>,
32    /// The version of the data-encryption key used (0 = plaintext/no-op).
33    pub key_version: u8,
34}
35
36/// Encrypts and decrypts key material before it is persisted to storage.
37///
38/// Use [`NoOpEncryptor`](crate::no_op_encryptor::NoOpEncryptor) when at-rest encryption is
39/// not required. For local AES-256-GCM-SIV use `LocalEncryptor`. For AWS KMS use `KmsEncryptor`.
40#[async_trait]
41pub trait KeyEncryptor: Send + Sync + 'static {
42    /// Encrypt `plaintext` and return the ciphertext bundle.
43    async fn encrypt(&self, plaintext: &[u8]) -> Result<Encrypted, EncryptorError>;
44    /// Decrypt an [`Encrypted`] bundle back to plaintext.
45    async fn decrypt(&self, encrypted: &Encrypted) -> Result<Vec<u8>, EncryptorError>;
46}