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}