kms_aead/providers/
aws_kms_encryption.rs1use 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}