main/keyring/raw_aes_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 Raw AES Keyring
6
7The Raw AES keyring lets you use an AES symmetric key that you provide as a wrapping key that
8protects your data key. You need to generate, store, and protect the key material,
9preferably in a hardware security module (HSM) or key management system. Use a Raw AES keyring
10when you need to provide the wrapping key and encrypt the data keys locally or offline.
11
12This example creates a Raw AES Keyring and then encrypts a custom input EXAMPLE_DATA
13with an encryption context. This example also includes some sanity checks for demonstration:
141. Ciphertext and plaintext data are not the same
152. Decrypted plaintext value matches EXAMPLE_DATA
16These sanity checks are for demonstration in the example only. You do not need these in your code.
17
18The Raw AES keyring encrypts data by using the AES-GCM algorithm and a wrapping key that
19you specify as a byte array. You can specify only one wrapping key in each Raw AES keyring,
20but you can include multiple Raw AES keyrings, alone or with other keyrings, in a multi-keyring.
21
22For more information on how to use Raw AES keyrings, see
23https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-raw-aes-keyring.html
24*/
25
26use aws_esdk::client as esdk_client;
27use aws_esdk::material_providers::client as mpl_client;
28use aws_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;
29use aws_esdk::material_providers::types::AesWrappingAlg;
30use aws_esdk::types::aws_encryption_sdk_config::AwsEncryptionSdkConfig;
31use rand::TryRngCore;
32use std::collections::HashMap;
33
34pub async fn encrypt_and_decrypt_with_keyring(example_data: &str) -> Result<(), crate::BoxError> {
35 // 1. Instantiate the encryption SDK client.
36 // This builds the default client with the RequireEncryptRequireDecrypt commitment policy,
37 // which enforces that this client only encrypts using committing algorithm suites and enforces
38 // that this client will only decrypt encrypted messages that were created with a committing
39 // algorithm suite.
40 let esdk_config = AwsEncryptionSdkConfig::builder().build()?;
41 let esdk_client = esdk_client::Client::from_conf(esdk_config)?;
42
43 // 2. The key namespace and key name are defined by you.
44 // and are used by the Raw AES keyring to determine
45 // whether it should attempt to decrypt an encrypted data key.
46 // For more information, see
47 // https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-raw-aes-keyring.html
48 let key_namespace: &str = "my-key-namespace";
49 let key_name: &str = "my-aes-key-name";
50
51 // 3. Create encryption context.
52 // Remember that your encryption context is NOT SECRET.
53 // For more information, see
54 // https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
55 let encryption_context = HashMap::from([
56 ("encryption".to_string(), "context".to_string()),
57 ("is not".to_string(), "secret".to_string()),
58 ("but adds".to_string(), "useful metadata".to_string()),
59 (
60 "that can help you".to_string(),
61 "be confident that".to_string(),
62 ),
63 (
64 "the data you are handling".to_string(),
65 "is what you think it is".to_string(),
66 ),
67 ]);
68
69 // 4. Generate a 256-bit AES key to use with your keyring.
70 // In practice, you should get this key from a secure key management system such as an HSM.
71 let aes_key_bytes = generate_aes_key_bytes();
72
73 // 5. Create a Raw AES Keyring
74 let mpl_config = MaterialProvidersConfig::builder().build()?;
75 let mpl = mpl_client::Client::from_conf(mpl_config)?;
76
77 let raw_aes_keyring = mpl
78 .create_raw_aes_keyring()
79 .key_name(key_name)
80 .key_namespace(key_namespace)
81 .wrapping_key(aes_key_bytes)
82 .wrapping_alg(AesWrappingAlg::AlgAes256GcmIv12Tag16)
83 .send()
84 .await?;
85
86 // 6. Encrypt the data with the encryption_context
87 let plaintext = example_data.as_bytes();
88
89 let encryption_response = esdk_client
90 .encrypt()
91 .plaintext(plaintext)
92 .keyring(raw_aes_keyring.clone())
93 .encryption_context(encryption_context.clone())
94 .send()
95 .await?;
96
97 let ciphertext = encryption_response
98 .ciphertext
99 .expect("Unable to unwrap ciphertext from encryption response");
100
101 // 7. Demonstrate that the ciphertext and plaintext are different.
102 // (This is an example for demonstration; you do not need to do this in your own code.)
103 assert_ne!(
104 ciphertext,
105 aws_smithy_types::Blob::new(plaintext),
106 "Ciphertext and plaintext data are the same. Invalid encryption"
107 );
108
109 // 8. Decrypt your encrypted data using the same keyring you used on encrypt.
110 let decryption_response = esdk_client
111 .decrypt()
112 .ciphertext(ciphertext)
113 .keyring(raw_aes_keyring)
114 // Provide the encryption context that was supplied to the encrypt method
115 .encryption_context(encryption_context)
116 .send()
117 .await?;
118
119 let decrypted_plaintext = decryption_response
120 .plaintext
121 .expect("Unable to unwrap plaintext from decryption response");
122
123 // 9. Demonstrate that the decrypted plaintext is identical to the original plaintext.
124 // (This is an example for demonstration; you do not need to do this in your own code.)
125 assert_eq!(
126 decrypted_plaintext,
127 aws_smithy_types::Blob::new(plaintext),
128 "Decrypted plaintext should be identical to the original plaintext. Invalid decryption"
129 );
130
131 println!("Raw AES Keyring Example Completed Successfully");
132
133 Ok(())
134}
135
136fn generate_aes_key_bytes() -> Vec<u8> {
137 // This example returns a random AES key.
138 // In practice, you should not generate this key in your code, and should instead
139 // retrieve this key from a secure key management system (e.g. HSM).
140 // This key is created here for example purposes only and should not be used for any other purpose.
141 let mut random_bytes = [0u8; 32];
142 rand::rngs::OsRng.try_fill_bytes(&mut random_bytes).unwrap();
143
144 random_bytes.to_vec()
145}
146
147#[tokio::test(flavor = "multi_thread")]
148pub async fn test_encrypt_and_decrypt_with_keyring() -> Result<(), crate::BoxError2> {
149 // Test function for encrypt and decrypt using the Raw AES Keyring example
150 use crate::example_utils::utils;
151
152 encrypt_and_decrypt_with_keyring(utils::TEST_EXAMPLE_DATA).await?;
153
154 Ok(())
155}