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}