main/keyring/
aws_kms_keyring_example.rs

1// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4/*
5This example sets up the AWS KMS Keyring
6
7The AWS KMS keyring uses symmetric encryption KMS keys to generate, encrypt and
8decrypt data keys. This example creates a KMS Keyring and then encrypts a custom input EXAMPLE_DATA
9with an encryption context. This example also includes some sanity checks for demonstration:
101. Ciphertext and plaintext data are not the same
112. Decrypted plaintext value matches EXAMPLE_DATA
12These sanity checks are for demonstration in the example only. You do not need these in your code.
13
14AWS KMS keyrings can be used independently or in a multi-keyring with other keyrings
15of the same or a different type.
16
17For more information on how to use KMS keyrings, see
18https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-kms-keyring.html
19
20For more information on KMS Key identifiers, see
21https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id
22*/
23
24use aws_esdk::client as esdk_client;
25use aws_esdk::material_providers::client as mpl_client;
26use aws_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;
27use aws_esdk::types::aws_encryption_sdk_config::AwsEncryptionSdkConfig;
28use std::collections::HashMap;
29
30pub async fn encrypt_and_decrypt_with_keyring(
31    example_data: &str,
32    kms_key_id: &str,
33) -> Result<(), crate::BoxError> {
34    // 1. Instantiate the encryption SDK client.
35    // This builds the default client with the RequireEncryptRequireDecrypt commitment policy,
36    // which enforces that this client only encrypts using committing algorithm suites and enforces
37    // that this client will only decrypt encrypted messages that were created with a committing
38    // algorithm suite.
39    let esdk_config = AwsEncryptionSdkConfig::builder().build()?;
40    let esdk_client = esdk_client::Client::from_conf(esdk_config)?;
41
42    // 2. Create a KMS client.
43    let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
44    let kms_client = aws_sdk_kms::Client::new(&sdk_config);
45
46    // 3. Create encryption context.
47    // Remember that your encryption context is NOT SECRET.
48    // For more information, see
49    // https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
50    let encryption_context = HashMap::from([
51        ("encryption".to_string(), "context".to_string()),
52        ("is not".to_string(), "secret".to_string()),
53        ("but adds".to_string(), "useful metadata".to_string()),
54        (
55            "that can help you".to_string(),
56            "be confident that".to_string(),
57        ),
58        (
59            "the data you are handling".to_string(),
60            "is what you think it is".to_string(),
61        ),
62    ]);
63
64    // 4. Create a KMS keyring
65    let mpl_config = MaterialProvidersConfig::builder().build()?;
66    let mpl = mpl_client::Client::from_conf(mpl_config)?;
67
68    let kms_keyring = mpl
69        .create_aws_kms_keyring()
70        .kms_key_id(kms_key_id)
71        .kms_client(kms_client)
72        .send()
73        .await?;
74
75    // 5. Encrypt the data with the encryption_context
76    let plaintext = example_data.as_bytes();
77
78    let encryption_response = esdk_client
79        .encrypt()
80        .plaintext(plaintext)
81        .keyring(kms_keyring.clone())
82        .encryption_context(encryption_context.clone())
83        .send()
84        .await?;
85
86    let ciphertext = encryption_response
87        .ciphertext
88        .expect("Unable to unwrap ciphertext from encryption response");
89
90    // 6. Demonstrate that the ciphertext and plaintext are different.
91    // (This is an example for demonstration; you do not need to do this in your own code.)
92    assert_ne!(
93        ciphertext,
94        aws_smithy_types::Blob::new(plaintext),
95        "Ciphertext and plaintext data are the same. Invalid encryption"
96    );
97
98    // 7. Decrypt your encrypted data using the same keyring you used on encrypt.
99    let decryption_response = esdk_client
100        .decrypt()
101        .ciphertext(ciphertext)
102        .keyring(kms_keyring)
103        // Provide the encryption context that was supplied to the encrypt method
104        .encryption_context(encryption_context)
105        .send()
106        .await?;
107
108    let decrypted_plaintext = decryption_response
109        .plaintext
110        .expect("Unable to unwrap plaintext from decryption response");
111
112    // 8. Demonstrate that the decrypted plaintext is identical to the original plaintext.
113    // (This is an example for demonstration; you do not need to do this in your own code.)
114    assert_eq!(
115        decrypted_plaintext,
116        aws_smithy_types::Blob::new(plaintext),
117        "Decrypted plaintext should be identical to the original plaintext. Invalid decryption"
118    );
119
120    println!("KMS Keyring Example Completed Successfully");
121
122    Ok(())
123}
124
125#[tokio::test(flavor = "multi_thread")]
126pub async fn test_encrypt_and_decrypt_with_keyring() -> Result<(), crate::BoxError2> {
127    // Test function for encrypt and decrypt using the AWS KMS Keyring example
128    use crate::example_utils::utils;
129
130    encrypt_and_decrypt_with_keyring(utils::TEST_EXAMPLE_DATA, utils::TEST_DEFAULT_KMS_KEY_ID)
131        .await?;
132
133    Ok(())
134}
135
136#[tokio::test(flavor = "multi_thread")]
137pub async fn test_encrypt_and_decrypt_with_keyring_async() -> Result<(), crate::BoxError2> {
138    // Test function for encrypt and decrypt using the AWS KMS Keyring example (async)
139    use crate::example_utils::utils;
140
141    let handle = tokio::spawn(async move {
142        encrypt_and_decrypt_with_keyring(utils::TEST_EXAMPLE_DATA, utils::TEST_DEFAULT_KMS_KEY_ID)
143            .await
144    });
145
146    assert!(handle.await.unwrap().is_ok());
147    Ok(())
148}