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}