Skip to content

Commit 99ac9fa

Browse files
committed
m
1 parent a216ef8 commit 99ac9fa

File tree

6 files changed

+712
-686
lines changed

6 files changed

+712
-686
lines changed

DynamoDbEncryption/runtimes/rust/src/bin/example/keyring/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pub mod branch_key_id_supplier;
22
pub mod hierarchical_keyring;
33
pub mod kms_rsa_keyring;
44
// pub mod mrk_discovery_multi_keyring;
5-
// pub mod multi_keyring;
6-
// pub mod multi_mrk_keyring;
7-
// pub mod raw_aes_keyring;
5+
pub mod multi_keyring;
6+
pub mod multi_mrk_keyring;
7+
pub mod raw_aes_keyring;
88
pub mod raw_rsa_keyring;

DynamoDbEncryption/runtimes/rust/src/bin/example/keyring/multi_keyring.rs

+246-228
Large diffs are not rendered by default.

DynamoDbEncryption/runtimes/rust/src/bin/example/keyring/multi_mrk_keyring.rs

+287-285
Large diffs are not rendered by default.

DynamoDbEncryption/runtimes/rust/src/bin/example/keyring/raw_aes_keyring.rs

+170-164
Original file line numberDiff line numberDiff line change
@@ -6,174 +6,180 @@ use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::types::DynamoDbTable
66
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_structuredEncryption::types::CryptoAction;
77
use aws_db_esdk::aws_cryptography_materialProviders::client as mpl_client;
88
use aws_db_esdk::aws_cryptography_materialProviders::types::material_providers_config::MaterialProvidersConfig;
9-
use aws_db_esdk::aws_cryptography_materialProviders::types::PaddingScheme;
9+
use aws_db_esdk::aws_cryptography_materialProviders::types::AesWrappingAlg;
1010
use aws_db_esdk::intercept::DbEsdkInterceptor;
1111
use aws_db_esdk::DynamoDbTablesEncryptionConfig;
1212
use aws_sdk_dynamodb::types::AttributeValue;
1313
use std::collections::HashMap;
14-
use std::fs::File;
15-
use std::io::Read;
16-
use std::io::Write;
17-
use std::path::Path;
1814

1915
/*
20-
This example sets up DynamoDb Encryption for the AWS SDK client
21-
using the raw AES Keyring. This keyring takes in an AES key
22-
and uses that key to protect the data keys that encrypt and
23-
decrypt DynamoDb table items.
24-
25-
This example takes in an `aesKeyBytes` parameter. This parameter
26-
should be a ByteBuffer representing a 256-bit AES key. If this example
27-
is run through the class' main method, it will create a new key.
28-
In practice, users of this library should not randomly generate a key,
29-
and should instead retrieve an existing key from a secure key
30-
management system (e.g. an HSM).
31-
32-
This example encrypts a test item using the provided AES key and puts the
33-
encrypted item to the provided DynamoDb table. Then, it gets the
34-
item from the table and decrypts it.
35-
36-
Running this example requires access to the DDB Table whose name
37-
is provided in CLI arguments.
38-
This table must be configured with the following
39-
primary key configuration:
40-
- Partition key is named "partition_key" with type (S)
41-
- Sort key is named "sort_key" with type (S)
42-
*/
43-
44-
pub async fn RawAesKeyringGetItemPutItem()
45-
{
46-
/*
47-
var ddbTableName = TestUtils.TEST_DDB_TABLE_NAME;
48-
var aesKeyBytes = GenerateAesKeyBytes();
49-
50-
// 1. Create the keyring.
51-
// The DynamoDb encryption client uses this to encrypt and decrypt items.
52-
var keyringInput = new CreateRawAesKeyringInput
53-
{
54-
KeyName = "my-aes-key-name",
55-
KeyNamespace = "my-key-namespace",
56-
WrappingKey = aesKeyBytes,
57-
WrappingAlg = AesWrappingAlg.ALG_AES256_GCM_IV12_TAG16
58-
};
59-
var matProv = new MaterialProviders(new MaterialProvidersConfig());
60-
IKeyring rawAesKeyring = matProv.CreateRawAesKeyring(keyringInput);
61-
62-
// 2. Configure which attributes are encrypted and/or signed when writing new items.
63-
// For each attribute that may exist on the items we plan to write to our DynamoDbTable,
64-
// we must explicitly configure how they should be treated during item encryption:
65-
// - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
66-
// - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
67-
// - DO_NOTHING: The attribute is not encrypted and not included in the signature
68-
var attributeActionsOnEncrypt = new Dictionary<String, CryptoAction>
69-
{
70-
["partition_key"] = CryptoAction.SIGN_ONLY, // Our partition attribute must be SIGN_ONLY
71-
["sort_key"] = CryptoAction.SIGN_ONLY, // Our sort attribute must be SIGN_ONLY
72-
["sensitive_data"] = CryptoAction.ENCRYPT_AND_SIGN
73-
};
74-
75-
// 3. Configure which attributes we expect to be included in the signature
76-
// when reading items. There are two options for configuring this:
77-
//
78-
// - (Recommended) Configure `allowedUnsignedAttributesPrefix`:
79-
// When defining your DynamoDb schema and deciding on attribute names,
80-
// choose a distinguishing prefix (such as ":") for all attributes that
81-
// you do not want to include in the signature.
82-
// This has two main benefits:
83-
// - It is easier to reason about the security and authenticity of data within your item
84-
// when all unauthenticated data is easily distinguishable by their attribute name.
85-
// - If you need to add new unauthenticated attributes in the future,
86-
// you can easily make the corresponding update to your `attributeActionsOnEncrypt`
87-
// and immediately start writing to that new attribute, without
88-
// any other configuration update needed.
89-
// Once you configure this field, it is not safe to update it.
90-
//
91-
// - Configure `allowedUnsignedAttributes`: You may also explicitly list
92-
// a set of attributes that should be considered unauthenticated when encountered
93-
// on read. Be careful if you use this configuration. Do not remove an attribute
94-
// name from this configuration, even if you are no longer writing with that attribute,
95-
// as old items may still include this attribute, and our configuration needs to know
96-
// to continue to exclude this attribute from the signature scope.
97-
// If you add new attribute names to this field, you must first deploy the update to this
98-
// field to all readers in your host fleet before deploying the update to start writing
99-
// with that new attribute.
100-
//
101-
// For this example, we currently authenticate all attributes. To make it easier to
102-
// add unauthenticated attributes in the future, we define a prefix ":" for such attributes.
103-
const String unsignAttrPrefix = ":";
104-
105-
// 4. Create the DynamoDb Encryption configuration for the table we will be writing to.
106-
var tableConfigs = new Dictionary<String, DynamoDbTableEncryptionConfig>
107-
{
108-
[ddbTableName] = new DynamoDbTableEncryptionConfig
109-
{
110-
LogicalTableName = ddbTableName,
111-
PartitionKeyName = "partition_key",
112-
SortKeyName = "sort_key",
113-
AttributeActionsOnEncrypt = attributeActionsOnEncrypt,
114-
Keyring = rawAesKeyring,
115-
AllowedUnsignedAttributePrefix = unsignAttrPrefix
116-
}
117-
};
118-
119-
// 5. Create a new AWS SDK DynamoDb client using the Config above
120-
var ddb = new Client.DynamoDbClient(
121-
new DynamoDbTablesEncryptionConfig { TableEncryptionConfigs = tableConfigs });
122-
123-
// 7. Put an item into our table using the above client.
124-
// Before the item gets sent to DynamoDb, it will be encrypted
125-
// client-side, according to our configuration.
126-
var item = new Dictionary<String, AttributeValue>
127-
{
128-
["partition_key"] = new AttributeValue("rawAesKeyringItem"),
129-
["sort_key"] = new AttributeValue { N = "0" },
130-
["sensitive_data"] = new AttributeValue("encrypt and sign me!")
131-
};
132-
133-
var putRequest = new PutItemRequest
134-
{
135-
TableName = ddbTableName,
136-
Item = item
137-
};
138-
139-
var putResponse = await ddb.PutItemAsync(putRequest);
140-
141-
// Demonstrate that PutItem succeeded
142-
Debug.Assert(putResponse.HttpStatusCode == HttpStatusCode.OK);
143-
144-
// 8. Get the item back from our table using the same client.
145-
// The client will decrypt the item client-side, and return
146-
// back the original item.
147-
var keyToGet = new Dictionary<String, AttributeValue>
148-
{
149-
["partition_key"] = new AttributeValue("rawAesKeyringItem"),
150-
["sort_key"] = new AttributeValue { N = "0" }
151-
};
152-
153-
var getRequest = new GetItemRequest
154-
{
155-
Key = keyToGet,
156-
TableName = ddbTableName
157-
};
158-
159-
var getResponse = await ddb.GetItemAsync(getRequest);
160-
161-
// Demonstrate that GetItem succeeded and returned the decrypted item
162-
Debug.Assert(getResponse.HttpStatusCode == HttpStatusCode.OK);
163-
var returnedItem = getResponse.Item;
164-
Debug.Assert(returnedItem["sensitive_data"].S.Equals("encrypt and sign me!"));
16+
This example sets up DynamoDb Encryption for the AWS SDK client
17+
using the raw AES Keyring. This keyring takes in an AES key
18+
and uses that key to protect the data keys that encrypt and
19+
decrypt DynamoDb table items.
20+
21+
This example takes in an `aesKeyBytes` parameter. This parameter
22+
should be a ByteBuffer representing a 256-bit AES key. If this example
23+
is run through the class' main method, it will create a new key.
24+
In practice, users of this library should not randomly generate a key,
25+
and should instead retrieve an existing key from a secure key
26+
management system (e.g. an HSM).
27+
28+
This example encrypts a test item using the provided AES key and puts the
29+
encrypted item to the provided DynamoDb table. Then, it gets the
30+
item from the table and decrypts it.
31+
32+
Running this example requires access to the DDB Table whose name
33+
is provided in CLI arguments.
34+
This table must be configured with the following
35+
primary key configuration:
36+
- Partition key is named "partition_key" with type (S)
37+
- Sort key is named "sort_key" with type (S)
16538
*/
166-
println!("raw_aes_keyring successful.");
167-
}
168-
/*
169-
public static MemoryStream GenerateAesKeyBytes()
170-
{
171-
// This example uses AES's KeyGenerator to generate the key bytes.
172-
// In practice, you should not generate this key in your code, and should instead
173-
// retrieve this key from a secure key management system (e.g. HSM).
174-
// This key is created here for example purposes only and should not be used for any other purpose.
175-
var aes = Aes.Create();
176-
aes.GenerateKey();
177-
return new MemoryStream(aes.Key);
178-
}
179-
*/
39+
40+
pub async fn put_item_get_item() {
41+
let ddb_table_name = test_utils::TEST_DDB_TABLE_NAME;
42+
let aes_key_bytes = generate_aes_key_bytes();
43+
44+
// 1. Create the keyring.
45+
// The DynamoDb encryption client uses this to encrypt and decrypt items.
46+
let mpl_config = MaterialProvidersConfig::builder().build().unwrap();
47+
let mpl = mpl_client::Client::from_conf(mpl_config).unwrap();
48+
let raw_aes_keyring = mpl
49+
.create_raw_aes_keyring()
50+
.key_name("my-aes-key-name")
51+
.key_namespace("my-key-namespace")
52+
.wrapping_key(aws_smithy_types::Blob::new(aes_key_bytes))
53+
.wrapping_alg(AesWrappingAlg::AlgAes256GcmIv12Tag16)
54+
.send()
55+
.await
56+
.unwrap();
57+
58+
// 2. Configure which attributes are encrypted and/or signed when writing new items.
59+
// For each attribute that may exist on the items we plan to write to our DynamoDbTable,
60+
// we must explicitly configure how they should be treated during item encryption:
61+
// - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
62+
// - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
63+
// - DO_NOTHING: The attribute is not encrypted and not included in the signature
64+
let attribute_actions_on_encrypt = HashMap::from([
65+
("partition_key".to_string(), CryptoAction::SignOnly), // Our partition attribute must be SIGN_ONLY
66+
("sort_key".to_string(), CryptoAction::SignOnly), // Our sort attribute must be SIGN_ONLY
67+
("sensitive_data".to_string(), CryptoAction::EncryptAndSign),
68+
]);
69+
70+
// 3. Configure which attributes we expect to be included in the signature
71+
// when reading items. There are two options for configuring this:
72+
//
73+
// - (Recommended) Configure `allowedUnsignedAttributesPrefix`:
74+
// When defining your DynamoDb schema and deciding on attribute names,
75+
// choose a distinguishing prefix (such as ":") for all attributes that
76+
// you do not want to include in the signature.
77+
// This has two main benefits:
78+
// - It is easier to reason about the security and authenticity of data within your item
79+
// when all unauthenticated data is easily distinguishable by their attribute name.
80+
// - If you need to add new unauthenticated attributes in the future,
81+
// you can easily make the corresponding update to your `attributeActionsOnEncrypt`
82+
// and immediately start writing to that new attribute, without
83+
// any other configuration update needed.
84+
// Once you configure this field, it is not safe to update it.
85+
//
86+
// - Configure `allowedUnsignedAttributes`: You may also explicitly list
87+
// a set of attributes that should be considered unauthenticated when encountered
88+
// on read. Be careful if you use this configuration. Do not remove an attribute
89+
// name from this configuration, even if you are no longer writing with that attribute,
90+
// as old items may still include this attribute, and our configuration needs to know
91+
// to continue to exclude this attribute from the signature scope.
92+
// If you add new attribute names to this field, you must first deploy the update to this
93+
// field to all readers in your host fleet before deploying the update to start writing
94+
// with that new attribute.
95+
//
96+
// For this example, we currently authenticate all attributes. To make it easier to
97+
// add unauthenticated attributes in the future, we define a prefix ":" for such attributes.
98+
const UNSIGNED_ATTR_PREFIX: &str = ":";
99+
100+
// 4. Create the DynamoDb Encryption configuration for the table we will be writing to.
101+
let table_config = DynamoDbTableEncryptionConfig::builder()
102+
.logical_table_name(ddb_table_name)
103+
.partition_key_name("partition_key")
104+
.sort_key_name("sort_key")
105+
.attribute_actions_on_encrypt(attribute_actions_on_encrypt)
106+
.keyring(raw_aes_keyring)
107+
.allowed_unsigned_attribute_prefix(UNSIGNED_ATTR_PREFIX)
108+
.build()
109+
.unwrap();
110+
111+
let table_configs = DynamoDbTablesEncryptionConfig::builder()
112+
.table_encryption_configs(HashMap::from([(ddb_table_name.to_string(), table_config)]))
113+
.build()
114+
.unwrap();
115+
116+
// 5. Create a new AWS SDK DynamoDb client using the Config above
117+
let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
118+
let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config)
119+
.interceptor(DbEsdkInterceptor::new(table_configs))
120+
.build();
121+
let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);
122+
123+
// 6. Put an item into our table using the above client.
124+
// Before the item gets sent to DynamoDb, it will be encrypted
125+
// client-side, according to our configuration.
126+
let item = HashMap::from([
127+
(
128+
"partition_key".to_string(),
129+
AttributeValue::S("rawAesKeyringItem".to_string()),
130+
),
131+
("sort_key".to_string(), AttributeValue::N("0".to_string())),
132+
(
133+
"sensitive_data".to_string(),
134+
AttributeValue::S("encrypt and sign me!".to_string()),
135+
),
136+
]);
137+
138+
let _resp = ddb
139+
.put_item()
140+
.table_name(ddb_table_name)
141+
.set_item(Some(item.clone()))
142+
.send()
143+
.await
144+
.unwrap();
145+
146+
// 7. Get the item back from our table using the same client.
147+
// The client will decrypt the item client-side, and return
148+
// back the original item.
149+
let key_to_get = HashMap::from([
150+
(
151+
"partition_key".to_string(),
152+
AttributeValue::S("rawAesKeyringItem".to_string()),
153+
),
154+
("sort_key".to_string(), AttributeValue::N("0".to_string())),
155+
]);
156+
157+
let resp = ddb
158+
.get_item()
159+
.table_name(ddb_table_name)
160+
.set_key(Some(key_to_get))
161+
// In this example we configure a strongly consistent read
162+
// because we perform a read immediately after a write (for demonstrative purposes).
163+
// By default, reads are only eventually consistent.
164+
// Read our docs to determine which read consistency to use for your application:
165+
// https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html
166+
.consistent_read(true)
167+
.send()
168+
.await
169+
.unwrap();
170+
171+
assert_eq!(resp.item, Some(item));
172+
173+
println!("raw_aes_keyring successful.");
174+
}
175+
176+
fn generate_aes_key_bytes() -> Vec<u8> {
177+
// This example returns a static key.
178+
// In practice, you should not generate this key in your code, and should instead
179+
// retrieve this key from a secure key management system (e.g. HSM).
180+
// This key is created here for example purposes only and should not be used for any other purpose.
181+
vec![
182+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
183+
25, 26, 27, 28, 29, 30, 31, 32,
184+
]
185+
}

DynamoDbEncryption/runtimes/rust/src/bin/example/keyring/raw_rsa_keyring.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ pub async fn put_item_get_item() {
8080

8181
// 2. Create the keyring.
8282
// The DynamoDb encryption client uses this to encrypt and decrypt items.
83-
let provider_config = MaterialProvidersConfig::builder().build().unwrap();
84-
let mpl = mpl_client::Client::from_conf(provider_config).unwrap();
83+
let mpl_config = MaterialProvidersConfig::builder().build().unwrap();
84+
let mpl = mpl_client::Client::from_conf(mpl_config).unwrap();
8585
let raw_rsa_keyring = mpl
8686
.create_raw_rsa_keyring()
8787
.key_name("my-rsa-key-name")

DynamoDbEncryption/runtimes/rust/src/bin/example/main.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,15 @@ pub async fn main() {
2222
multi_get_put_example::multi_put_get().await;
2323
keyring::raw_rsa_keyring::put_item_get_item().await;
2424
keyring::kms_rsa_keyring::put_item_get_item().await;
25+
keyring::multi_mrk_keyring::put_item_get_item().await;
26+
keyring::raw_aes_keyring::put_item_get_item().await;
27+
keyring::multi_keyring::put_item_get_item().await;
2528

2629
let key_id = create_keystore_key::keystore_create_key().await;
2730
let key_id2 = create_keystore_key::keystore_create_key().await;
2831
// Key creation is eventually consistent, so wait 5 seconds to decrease the likelihood
2932
// our test fails due to eventual consistency issues.
30-
println!("Key Store Keys created. Waiting 5 seconds for consistency.\n");
33+
println!("Key Store Keys created. Waiting 5 seconds for consistency.");
3134
std::thread::sleep(std::time::Duration::from_secs(5));
3235

3336
searchableencryption::basic_searchable_encryption::put_and_query_with_beacon(&key_id).await;
@@ -36,11 +39,8 @@ pub async fn main() {
3639

3740
/*
3841
await ClientSupplierExample.ClientSupplierPutItemGetItem();
39-
await MultiMrkKeyringExample.MultiMrkKeyringGetItemPutItem();
40-
await RawAesKeyringExample.RawAesKeyringGetItemPutItem();
4142
await MrkDiscoveryMultiKeyringExample.MultiMrkDiscoveryKeyringGetItemPutItem();
4243
await MultiKeyringExample.MultiKeyringGetItemPutItem();
43-
await RawRsaKeyringExample.RawRsaKeyringGetItemPutItem();
4444
4545
await CompoundBeaconSearchableEncryptionExample.PutItemQueryItemWithCompoundBeacon(keyId);
4646
await VirtualBeaconSearchableEncryptionExample.PutItemQueryItemWithVirtualBeacon(keyId);

0 commit comments

Comments
 (0)