main/keyring/aws_kms_hierarchical/
aws_kms_hierarchical_keyring_example.rs1use super::create_branch_key_id::create_branch_key_id;
41use super::example_branch_key_id_supplier::ExampleBranchKeyIdSupplier;
42use aws_esdk::client as esdk_client;
43use aws_esdk::key_store::client as keystore_client;
44use aws_esdk::key_store::types::key_store_config::KeyStoreConfig;
45use aws_esdk::key_store::types::KmsConfiguration;
46use aws_esdk::material_providers::client as mpl_client;
47use aws_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;
48use aws_esdk::types::aws_encryption_sdk_config::AwsEncryptionSdkConfig;
49use aws_esdk::types::error::Error::AwsCryptographicMaterialProvidersError;
50use std::collections::HashMap;
51
52pub async fn encrypt_and_decrypt_with_keyring(
53 example_data: &str,
54 key_store_table_name: &str,
55 logical_key_store_name: &str,
56 key_store_kms_key_id: &str,
57) -> Result<(), crate::BoxError> {
58 let esdk_config = AwsEncryptionSdkConfig::builder().build()?;
64 let esdk_client = esdk_client::Client::from_conf(esdk_config)?;
65
66 let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
68 let kms_client = aws_sdk_kms::Client::new(&sdk_config);
69 let ddb_client = aws_sdk_dynamodb::Client::new(&sdk_config);
70
71 let key_store_config = KeyStoreConfig::builder()
75 .kms_client(kms_client)
76 .ddb_client(ddb_client)
77 .ddb_table_name(key_store_table_name)
78 .logical_key_store_name(logical_key_store_name)
79 .kms_configuration(KmsConfiguration::KmsKeyArn(
80 key_store_kms_key_id.to_string(),
81 ))
82 .build()?;
83
84 let key_store = keystore_client::Client::from_conf(key_store_config)?;
85
86 let branch_key_id_a: String = create_branch_key_id(
88 key_store_table_name,
89 logical_key_store_name,
90 key_store_kms_key_id,
91 )
92 .await?;
93 let branch_key_id_b: String = create_branch_key_id(
94 key_store_table_name,
95 logical_key_store_name,
96 key_store_kms_key_id,
97 )
98 .await?;
99
100 let branch_key_id_supplier =
102 ExampleBranchKeyIdSupplier::new(&branch_key_id_a, &branch_key_id_b);
103
104 let mpl_config = MaterialProvidersConfig::builder().build()?;
106 let mpl = mpl_client::Client::from_conf(mpl_config)?;
107
108 let hierarchical_keyring = mpl
109 .create_aws_kms_hierarchical_keyring()
110 .key_store(key_store.clone())
111 .branch_key_id_supplier(branch_key_id_supplier)
112 .ttl_seconds(600)
113 .send()
114 .await?;
115
116 let encryption_context_a = HashMap::from([
125 ("tenant".to_string(), "TenantA".to_string()),
126 ("encryption".to_string(), "context".to_string()),
127 ("is not".to_string(), "secret".to_string()),
128 ("but adds".to_string(), "useful metadata".to_string()),
129 (
130 "that can help you".to_string(),
131 "be confident that".to_string(),
132 ),
133 (
134 "the data you are handling".to_string(),
135 "is what you think it is".to_string(),
136 ),
137 ]);
138
139 let encryption_context_b = HashMap::from([
141 ("tenant".to_string(), "TenantB".to_string()),
142 ("encryption".to_string(), "context".to_string()),
143 ("is not".to_string(), "secret".to_string()),
144 ("but adds".to_string(), "useful metadata".to_string()),
145 (
146 "that can help you".to_string(),
147 "be confident that".to_string(),
148 ),
149 (
150 "the data you are handling".to_string(),
151 "is what you think it is".to_string(),
152 ),
153 ]);
154
155 let plaintext = example_data.as_bytes();
157
158 let encryption_response_a = esdk_client
159 .encrypt()
160 .plaintext(plaintext)
161 .keyring(hierarchical_keyring.clone())
162 .encryption_context(encryption_context_a.clone())
163 .send()
164 .await?;
165
166 let ciphertext_a = encryption_response_a
167 .ciphertext
168 .expect("Unable to unwrap ciphertext from encryption response");
169
170 let encryption_response_b = esdk_client
171 .encrypt()
172 .plaintext(plaintext)
173 .keyring(hierarchical_keyring.clone())
174 .encryption_context(encryption_context_b.clone())
175 .send()
176 .await?;
177
178 let ciphertext_b = encryption_response_b
179 .ciphertext
180 .expect("Unable to unwrap ciphertext from encryption response");
181
182 assert_ne!(
185 ciphertext_a,
186 aws_smithy_types::Blob::new(plaintext),
187 "Ciphertext and plaintext data are the same. Invalid encryption"
188 );
189
190 assert_ne!(
191 ciphertext_b,
192 aws_smithy_types::Blob::new(plaintext),
193 "Ciphertext and plaintext data are the same. Invalid encryption"
194 );
195
196 let hierarchical_keyring_a = mpl
199 .create_aws_kms_hierarchical_keyring()
200 .key_store(key_store.clone())
201 .branch_key_id(branch_key_id_a)
202 .ttl_seconds(600)
203 .send()
204 .await?;
205
206 let hierarchical_keyring_b = mpl
207 .create_aws_kms_hierarchical_keyring()
208 .key_store(key_store)
209 .branch_key_id(branch_key_id_b)
210 .ttl_seconds(600)
211 .send()
212 .await?;
213
214 let decryption_response_mismatch_1 = esdk_client
221 .decrypt()
222 .ciphertext(ciphertext_a.clone())
223 .keyring(hierarchical_keyring_b.clone())
224 .encryption_context(encryption_context_a.clone())
226 .send()
227 .await;
228
229 match decryption_response_mismatch_1 {
230 Ok(_) => panic!(
231 "Decrypt with wrong tenant's hierarchical keyring MUST \
232 raise AwsCryptographicMaterialProvidersError"
233 ),
234 Err(AwsCryptographicMaterialProvidersError { error: _e }) => (),
235 _ => panic!("Unexpected error type"),
236 }
237
238 let decryption_response_mismatch_2 = esdk_client
242 .decrypt()
243 .ciphertext(ciphertext_b.clone())
244 .keyring(hierarchical_keyring_a.clone())
245 .encryption_context(encryption_context_b.clone())
247 .send()
248 .await;
249
250 match decryption_response_mismatch_2 {
251 Ok(_) => panic!(
252 "Decrypt with wrong tenant's hierarchical keyring MUST \
253 raise AwsCryptographicMaterialProvidersError"
254 ),
255 Err(AwsCryptographicMaterialProvidersError { error: _e }) => (),
256 _ => panic!("Unexpected error type"),
257 }
258
259 let decryption_response_a = esdk_client
262 .decrypt()
263 .ciphertext(ciphertext_a)
264 .keyring(hierarchical_keyring_a)
265 .encryption_context(encryption_context_a)
267 .send()
268 .await?;
269
270 let decrypted_plaintext_a = decryption_response_a
271 .plaintext
272 .expect("Unable to unwrap plaintext from decryption response");
273
274 assert_eq!(
277 decrypted_plaintext_a,
278 aws_smithy_types::Blob::new(plaintext),
279 "Decrypted plaintext should be identical to the original plaintext. Invalid decryption"
280 );
281
282 let decryption_response_b = esdk_client
284 .decrypt()
285 .ciphertext(ciphertext_b)
286 .keyring(hierarchical_keyring_b)
287 .encryption_context(encryption_context_b)
289 .send()
290 .await?;
291
292 let decrypted_plaintext_b = decryption_response_b
293 .plaintext
294 .expect("Unable to unwrap plaintext from decryption response");
295
296 assert_eq!(
299 decrypted_plaintext_b,
300 aws_smithy_types::Blob::new(plaintext),
301 "Decrypted plaintext should be identical to the original plaintext. Invalid decryption"
302 );
303
304 println!("Hierarchical Keyring Example Completed Successfully");
305
306 Ok(())
307}
308
309#[tokio::test(flavor = "multi_thread")]
310pub async fn test_encrypt_and_decrypt_with_keyring() -> Result<(), crate::BoxError2> {
311 use crate::example_utils::utils;
313
314 encrypt_and_decrypt_with_keyring(
315 utils::TEST_EXAMPLE_DATA,
316 utils::TEST_KEY_STORE_NAME,
317 utils::TEST_LOGICAL_KEY_STORE_NAME,
318 utils::TEST_KEY_STORE_KMS_KEY_ID,
319 )
320 .await?;
321
322 Ok(())
323}