@@ -6,174 +6,180 @@ use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::types::DynamoDbTable
6
6
use aws_db_esdk:: aws_cryptography_dbEncryptionSdk_structuredEncryption:: types:: CryptoAction ;
7
7
use aws_db_esdk:: aws_cryptography_materialProviders:: client as mpl_client;
8
8
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 ;
10
10
use aws_db_esdk:: intercept:: DbEsdkInterceptor ;
11
11
use aws_db_esdk:: DynamoDbTablesEncryptionConfig ;
12
12
use aws_sdk_dynamodb:: types:: AttributeValue ;
13
13
use std:: collections:: HashMap ;
14
- use std:: fs:: File ;
15
- use std:: io:: Read ;
16
- use std:: io:: Write ;
17
- use std:: path:: Path ;
18
14
19
15
/*
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)
165
38
*/
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
+ }
0 commit comments