main/cryptographic_materials_manager/restrict_algorithm_suite/
signing_only_example.rs

1// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4/*
5 Demonstrate an encrypt/decrypt cycle using a Custom Cryptographic Materials Manager (CMM).
6 `SigningSuiteOnlyCMM.cs` demonstrates creating a custom CMM to reject Non-Signing Algorithms.
7*/
8
9use super::signing_suite_only_cmm::SigningSuiteOnlyCMM;
10use aws_esdk::client as esdk_client;
11use aws_esdk::material_providers::client as mpl_client;
12use aws_esdk::material_providers::types::cryptographic_materials_manager::CryptographicMaterialsManagerRef;
13use aws_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;
14use aws_esdk::material_providers::types::EsdkAlgorithmSuiteId;
15use aws_esdk::types::aws_encryption_sdk_config::AwsEncryptionSdkConfig;
16use aws_esdk::types::error::Error::AwsCryptographicMaterialProvidersError;
17use std::collections::HashMap;
18
19pub async fn encrypt_and_decrypt_with_cmm(
20    example_data: &str,
21    kms_key_id: &str,
22) -> Result<(), crate::BoxError> {
23    // 1. Instantiate the encryption SDK client.
24    // This builds the default client with the RequireEncryptRequireDecrypt commitment policy,
25    // which enforces that this client only encrypts using committing algorithm suites and enforces
26    // that this client will only decrypt encrypted messages that were created with a committing
27    // algorithm suite.
28    let esdk_config = AwsEncryptionSdkConfig::builder().build()?;
29    let esdk_client = esdk_client::Client::from_conf(esdk_config)?;
30
31    // 2. Create a KMS client.
32    let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
33    let kms_client = aws_sdk_kms::Client::new(&sdk_config);
34
35    // 3. Create encryption context.
36    // Remember that your encryption context is NOT SECRET.
37    // For more information, see
38    // https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
39    let encryption_context = HashMap::from([
40        ("encryption".to_string(), "context".to_string()),
41        ("is not".to_string(), "secret".to_string()),
42        ("but adds".to_string(), "useful metadata".to_string()),
43        (
44            "that can help you".to_string(),
45            "be confident that".to_string(),
46        ),
47        (
48            "the data you are handling".to_string(),
49            "is what you think it is".to_string(),
50        ),
51    ]);
52
53    // 4. Create a custom SigningSuiteOnlyCMM
54    let mpl_config = MaterialProvidersConfig::builder().build()?;
55    let mpl = mpl_client::Client::from_conf(mpl_config)?;
56
57    let kms_keyring = mpl
58        .create_aws_kms_keyring()
59        .kms_key_id(kms_key_id)
60        .kms_client(kms_client)
61        .send()
62        .await?;
63
64    let signing_suite_only_cmm = SigningSuiteOnlyCMM::new(kms_keyring);
65
66    let signing_suite_only_cmm_ref: CryptographicMaterialsManagerRef =
67        CryptographicMaterialsManagerRef {
68            inner: ::std::sync::Arc::new(std::sync::Mutex::new(signing_suite_only_cmm)),
69        };
70
71    // 5. Encrypt the data with the encryption_context
72    let plaintext = example_data.as_bytes();
73
74    let encryption_response = esdk_client
75        .encrypt()
76        .plaintext(plaintext)
77        .materials_manager(signing_suite_only_cmm_ref.clone())
78        .encryption_context(encryption_context.clone())
79        .algorithm_suite_id(EsdkAlgorithmSuiteId::AlgAes256GcmHkdfSha512CommitKeyEcdsaP384)
80        .send()
81        .await?;
82
83    let ciphertext = encryption_response
84        .ciphertext
85        .expect("Unable to unwrap ciphertext from encryption response");
86
87    // 6. Demonstrate that the ciphertext and plaintext are different.
88    // (This is an example for demonstration; you do not need to do this in your own code.)
89    assert_ne!(
90        ciphertext,
91        aws_smithy_types::Blob::new(plaintext),
92        "Ciphertext and plaintext data are the same. Invalid encryption"
93    );
94
95    // 7. Decrypt your encrypted data using the same keyring you used on encrypt.
96    let decryption_response = esdk_client
97        .decrypt()
98        .ciphertext(ciphertext)
99        .materials_manager(signing_suite_only_cmm_ref.clone())
100        // Provide the encryption context that was supplied to the encrypt method
101        .encryption_context(encryption_context.clone())
102        .send()
103        .await?;
104
105    let decrypted_plaintext = decryption_response
106        .plaintext
107        .expect("Unable to unwrap plaintext from decryption response");
108
109    // 8. Demonstrate that the decrypted plaintext is identical to the original plaintext.
110    // (This is an example for demonstration; you do not need to do this in your own code.)
111    assert_eq!(
112        decrypted_plaintext,
113        aws_smithy_types::Blob::new(plaintext),
114        "Decrypted plaintext should be identical to the original plaintext. Invalid decryption"
115    );
116
117    // 9. Demonstrate that a Non Signing Algorithm Suite will be rejected
118    // by the CMM.
119    let encryption_response_non_signing = esdk_client
120        .encrypt()
121        .plaintext(plaintext)
122        .materials_manager(signing_suite_only_cmm_ref)
123        .encryption_context(encryption_context.clone())
124        .algorithm_suite_id(EsdkAlgorithmSuiteId::AlgAes256GcmHkdfSha512CommitKey)
125        .send()
126        .await;
127
128    match encryption_response_non_signing {
129        Ok(_) => panic!(
130            "Encrypt using non signing algorithm suite MUST \
131                            raise AwsCryptographicMaterialProvidersError"
132        ),
133        Err(AwsCryptographicMaterialProvidersError { error: _e }) => (),
134        _ => panic!("Unexpected error type"),
135    }
136
137    println!("SigningSuiteOnlyCMM Example Completed Successfully");
138
139    Ok(())
140}
141
142#[tokio::test(flavor = "multi_thread")]
143pub async fn test_encrypt_and_decrypt_with_cmm() -> Result<(), crate::BoxError2> {
144    // Test function for encrypt and decrypt using the SigningSuiteOnlyCMM example
145    use crate::example_utils::utils;
146
147    encrypt_and_decrypt_with_cmm(utils::TEST_EXAMPLE_DATA, utils::TEST_DEFAULT_KMS_KEY_ID).await?;
148
149    Ok(())
150}