kms_aead/providers/
aws_kms_encryption.rs

1use rsb_derive::*;
2
3use crate::errors::*;
4use crate::*;
5use async_trait::async_trait;
6use aws_sdk_kms::primitives::Blob;
7use tracing::*;
8
9use crate::ring_encryption::RingAeadEncryption;
10use rvstruct::ValueStruct;
11use secret_vault_value::SecretValue;
12
13#[derive(Debug, Clone, Eq, PartialEq, Builder)]
14pub struct AwsKmsKeyRef {
15    pub account_id: String,
16    pub key_id: String,
17    pub aws_region: Option<aws_sdk_kms::config::Region>,
18}
19
20impl AwsKmsKeyRef {
21    pub fn to_key_arn(&self) -> String {
22        self.aws_region
23            .as_ref()
24            .map(|region| {
25                format!(
26                    "arn:aws:kms:{}:{}:key/{}",
27                    region, self.account_id, self.key_id
28                )
29            })
30            .unwrap_or_else(|| self.key_id.clone())
31    }
32}
33
34#[derive(Debug, Clone, Builder)]
35pub struct AwsKmsProviderOptions {
36    #[default = "false"]
37    pub use_kms_random_gen: bool,
38}
39
40pub struct AwsKmsProvider {
41    aws_key_ref: AwsKmsKeyRef,
42    client: aws_sdk_kms::Client,
43    options: AwsKmsProviderOptions,
44}
45
46impl AwsKmsProvider {
47    pub async fn new(kms_key_ref: &AwsKmsKeyRef) -> KmsAeadResult<Self> {
48        Self::with_options(kms_key_ref, AwsKmsProviderOptions::new()).await
49    }
50
51    pub async fn with_options(
52        kms_key_ref: &AwsKmsKeyRef,
53        options: AwsKmsProviderOptions,
54    ) -> KmsAeadResult<Self> {
55        debug!(
56            "Initialising AWS KMS envelope encryption for {}",
57            kms_key_ref.to_key_arn()
58        );
59
60        let shared_config = aws_config::load_from_env().await;
61
62        let effective_kms_ref = if kms_key_ref.aws_region.is_none() {
63            kms_key_ref
64                .clone()
65                .opt_aws_region(shared_config.region().cloned())
66        } else {
67            kms_key_ref.clone()
68        };
69
70        let client = aws_sdk_kms::Client::new(&shared_config);
71
72        Ok(Self {
73            aws_key_ref: effective_kms_ref,
74            client,
75            options,
76        })
77    }
78}
79
80#[async_trait]
81impl KmsAeadRingEncryptionProvider for AwsKmsProvider {
82    async fn encrypt_data_encryption_key(
83        &self,
84        encryption_key: &DataEncryptionKey,
85    ) -> KmsAeadResult<EncryptedDataEncryptionKey> {
86        match self
87            .client
88            .encrypt()
89            .set_key_id(Some(self.aws_key_ref.to_key_arn()))
90            .set_plaintext(Some(Blob::new(
91                hex::encode(encryption_key.value().ref_sensitive_value().as_slice()).into_bytes(),
92            )))
93            .send()
94            .await
95        {
96            Ok(encrypt_response) => {
97                if let Some(blob) = encrypt_response.ciphertext_blob {
98                    Ok(EncryptedDataEncryptionKey(blob.into_inner()))
99                } else {
100                    error!(
101                        "Unable to encrypt DEK with AWS KMS {}: Didn't receive any blob.",
102                        self.aws_key_ref.to_key_arn()
103                    );
104                    return Err(KmsAeadError::EncryptionError(KmsAeadEncryptionError::new(
105                        KmsAeadErrorPublicGenericDetails::new("AWS_ERROR".into()),
106                        format!(
107                            "AWS error {:?}. No encrypted blob received.",
108                            self.aws_key_ref.to_key_arn()
109                        ),
110                    )));
111                }
112            }
113            Err(err) => {
114                error!(
115                    "Unable to encrypt DEK with AWS KMS {}: {}.",
116                    self.aws_key_ref.to_key_arn(),
117                    err
118                );
119                return Err(KmsAeadError::EncryptionError(KmsAeadEncryptionError::new(
120                    KmsAeadErrorPublicGenericDetails::new("AWS_ERROR".into()),
121                    format!("AWS error {:?}: {}", self.aws_key_ref.to_key_arn(), err),
122                )));
123            }
124        }
125    }
126
127    async fn decrypt_data_encryption_key(
128        &self,
129        encrypted_key: &EncryptedDataEncryptionKey,
130    ) -> KmsAeadResult<DataEncryptionKey> {
131        let decrypt_response = self
132            .client
133            .decrypt()
134            .ciphertext_blob(Blob::new(encrypted_key.value().as_slice()))
135            .send()
136            .await?;
137
138        if let Some(plaintext) = decrypt_response.plaintext {
139            Ok(DataEncryptionKey::from(
140                secret_vault_value::SecretValue::new(hex::decode(plaintext.into_inner()).unwrap()),
141            ))
142        } else {
143            Err(KmsAeadError::EncryptionError(KmsAeadEncryptionError::new(
144                KmsAeadErrorPublicGenericDetails::new("AWS_ERROR".into()),
145                format!(
146                    "AWS error {:?}: No plaintext received",
147                    self.aws_key_ref.to_key_arn()
148                ),
149            )))
150        }
151    }
152
153    async fn generate_encryption_key(
154        &self,
155        aead_encryption: &RingAeadEncryption,
156    ) -> KmsAeadResult<DataEncryptionKey> {
157        if self.options.use_kms_random_gen {
158            let resp = self
159                .client
160                .generate_random()
161                .number_of_bytes(aead_encryption.algo.key_len() as i32)
162                .send()
163                .await?;
164            let random_bytes_blob = resp.plaintext.ok_or_else(|| {
165                KmsAeadError::EncryptionError(KmsAeadEncryptionError::new(
166                    KmsAeadErrorPublicGenericDetails::new("AWS_ERROR".into()),
167                    format!(
168                        "AWS error {:?}. No secure random bytes received.",
169                        self.aws_key_ref.to_key_arn()
170                    ),
171                ))
172            })?;
173
174            Ok(DataEncryptionKey::from(SecretValue::from(
175                random_bytes_blob.into_inner(),
176            )))
177        } else {
178            aead_encryption.generate_data_encryption_key()
179        }
180    }
181}