main/
set_commitment_policy_example.rs

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