Skip to content

Commit 38a5614

Browse files
add raw aes example and refactor
1 parent 151649b commit 38a5614

File tree

3 files changed

+207
-8
lines changed

3 files changed

+207
-8
lines changed

Examples/runtimes/go/keyring/awskmskeyring.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ import (
88
"fmt"
99
"reflect"
1010

11+
mpl "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygenerated"
12+
mpltypes "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygeneratedtypes"
1113
dbesdkdynamodbencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkdynamodbsmithygeneratedtypes"
1214
dbesdkstructuredencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkstructuredencryptionsmithygeneratedtypes"
15+
"github.com/aws/aws-database-encryption-sdk-dynamodb/dbesdkmiddleware"
16+
1317
"github.com/aws/aws-sdk-go-v2/aws"
1418
"github.com/aws/aws-sdk-go-v2/config"
1519
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
1620
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
1721
"github.com/aws/aws-sdk-go-v2/service/kms"
18-
19-
mpl "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygenerated"
20-
mpltypes "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygeneratedtypes"
21-
"github.com/aws/aws-database-encryption-sdk-dynamodb/dbesdkmiddleware"
2222
)
2323

2424
/*
@@ -65,9 +65,9 @@ func AwsKmsKeyringExample(kmsKeyID, ddbTableName string) {
6565
// 2. Configure which attributes are encrypted and/or signed when writing new items.
6666
// For each attribute that may exist on the items we plan to write to our DynamoDbTable,
6767
// we must explicitly configure how they should be treated during item encryption:
68-
// - EncryptAndSign: The attribute is encrypted and included in the signature
69-
// - SignOnly: The attribute not encrypted, but is still included in the signature
70-
// - DoNothing: The attribute is not encrypted and not included in the signature
68+
// - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
69+
// - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
70+
// - DO_NOTHING: The attribute is not encrypted and not included in the signature
7171
attributeActions := map[string]dbesdkstructuredencryptiontypes.CryptoAction{
7272
"partition_key": dbesdkstructuredencryptiontypes.CryptoActionSignOnly, // Partition key must be SIGN_ONLY
7373
"sort_key": dbesdkstructuredencryptiontypes.CryptoActionSignOnly, // Sort key must be SIGN_ONLY
@@ -107,11 +107,12 @@ func AwsKmsKeyringExample(kmsKeyID, ddbTableName string) {
107107
allowedUnsignedAttributePrefix := ":"
108108

109109
// 4. Create the DynamoDb Encryption configuration for the table we will be writing to.
110+
partitionKey := "partition_key"
110111
sortKeyName := "sort_key"
111112
algorithmSuiteId := mpltypes.DBEAlgorithmSuiteIdAlgAes256GcmHkdfSha512CommitKeyEcdsaP384SymsigHmacSha384
112113
tableConfig := dbesdkdynamodbencryptiontypes.DynamoDbTableEncryptionConfig{
113114
LogicalTableName: ddbTableName,
114-
PartitionKeyName: "partition_key",
115+
PartitionKeyName: partitionKey,
115116
SortKeyName: &sortKeyName,
116117
AttributeActionsOnEncrypt: attributeActions,
117118
Keyring: keyring,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package keyring
5+
6+
import (
7+
"context"
8+
"crypto/rand"
9+
"fmt"
10+
"reflect"
11+
12+
mpl "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygenerated"
13+
mpltypes "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygeneratedtypes"
14+
dbesdkdynamodbencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkdynamodbsmithygeneratedtypes"
15+
dbesdkstructuredencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkstructuredencryptionsmithygeneratedtypes"
16+
"github.com/aws/aws-database-encryption-sdk-dynamodb/dbesdkmiddleware"
17+
"github.com/aws/aws-sdk-go-v2/aws"
18+
"github.com/aws/aws-sdk-go-v2/config"
19+
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
20+
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
21+
)
22+
23+
/*
24+
This example sets up DynamoDb Encryption for the AWS SDK client
25+
using the raw AES Keyring. This keyring takes in an AES key
26+
and uses that key to protect the data keys that encrypt and
27+
decrypt DynamoDb table items.
28+
29+
This example takes in an `aesKeyBytes` parameter. This parameter
30+
should be a ByteBuffer representing a 256-bit AES key. If this example
31+
is run through the class' main method, it will create a new key.
32+
In practice, users of this library should not randomly generate a key,
33+
and should instead retrieve an existing key from a secure key
34+
management system (e.g. an HSM).
35+
36+
This example encrypts a test item using the provided AES key and puts the
37+
encrypted item to the provided DynamoDb table. Then, it gets the
38+
item from the table and decrypts it.
39+
40+
Running this example requires access to the DDB Table whose name
41+
is provided in CLI arguments.
42+
This table must be configured with the following
43+
primary key configuration:
44+
- Partition key is named "partition_key" with type (S)
45+
- Sort key is named "sort_key" with type (S)
46+
*/
47+
48+
func RawAesExample(ddbTableName string) {
49+
aesKeyBytes, err := generateAes256KeyBytes()
50+
if err != nil {
51+
panic(err)
52+
}
53+
// 1. Create the keyring.
54+
// The DynamoDb encryption client uses this to encrypt and decrypt items.
55+
56+
// Initialize the mpl client
57+
matProv, err := mpl.NewClient(mpltypes.MaterialProvidersConfig{})
58+
if err != nil {
59+
panic(err)
60+
}
61+
// Create the Raw Aes Keyring
62+
var keyNamespace = "my-key-namespace"
63+
var keyName = "my-aes-key-name"
64+
rawAesKeyRingInput := mpltypes.CreateRawAesKeyringInput{
65+
KeyName: keyName,
66+
KeyNamespace: keyNamespace,
67+
WrappingKey: aesKeyBytes,
68+
WrappingAlg: mpltypes.AesWrappingAlgAlgAes256GcmIv12Tag16,
69+
}
70+
rawAesKeyring, err := matProv.CreateRawAesKeyring(context.Background(), rawAesKeyRingInput)
71+
if err != nil {
72+
panic(err)
73+
}
74+
// 2. Configure which attributes are encrypted and/or signed when writing new items.
75+
// For each attribute that may exist on the items we plan to write to our DynamoDbTable,
76+
// we must explicitly configure how they should be treated during item encryption:
77+
// - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
78+
// - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
79+
// - DO_NOTHING: The attribute is not encrypted and not included in the signature
80+
attributeActionsOnEncrypt := map[string]dbesdkstructuredencryptiontypes.CryptoAction{
81+
"partition_key": dbesdkstructuredencryptiontypes.CryptoActionSignOnly, // Partition key must be SIGN_ONLY
82+
"sort_key": dbesdkstructuredencryptiontypes.CryptoActionSignOnly, // Sort key must be SIGN_ONLY
83+
"sensitive_data": dbesdkstructuredencryptiontypes.CryptoActionEncryptAndSign,
84+
}
85+
// 3. Configure which attributes we expect to be included in the signature
86+
// when reading items. There are two options for configuring this:
87+
//
88+
// - (Recommended) Configure `allowedUnsignedAttributesPrefix`:
89+
// When defining your DynamoDb schema and deciding on attribute names,
90+
// choose a distinguishing prefix (such as ":") for all attributes that
91+
// you do not want to include in the signature.
92+
// This has two main benefits:
93+
// - It is easier to reason about the security and authenticity of data within your item
94+
// when all unauthenticated data is easily distinguishable by their attribute name.
95+
// - If you need to add new unauthenticated attributes in the future,
96+
// you can easily make the corresponding update to your `attributeActionsOnEncrypt`
97+
// and immediately start writing to that new attribute, without
98+
// any other configuration update needed.
99+
// Once you configure this field, it is not safe to update it.
100+
//
101+
// - Configure `allowedUnsignedAttributes`: You may also explicitly list
102+
// a set of attributes that should be considered unauthenticated when encountered
103+
// on read. Be careful if you use this configuration. Do not remove an attribute
104+
// name from this configuration, even if you are no longer writing with that attribute,
105+
// as old items may still include this attribute, and our configuration needs to know
106+
// to continue to exclude this attribute from the signature scope.
107+
// If you add new attribute names to this field, you must first deploy the update to this
108+
// field to all readers in your host fleet before deploying the update to start writing
109+
// with that new attribute.
110+
//
111+
// For this example, we currently authenticate all attributes. To make it easier to
112+
// add unauthenticated attributes in the future, we define a prefix ":" for such attributes.
113+
unsignedAttrPrefix := ":"
114+
115+
// 4. Create the DynamoDb Encryption configuration for the table we will be writing to.
116+
partitionKey := "partition_key"
117+
sortKeyName := "sort_key"
118+
tableConfig := dbesdkdynamodbencryptiontypes.DynamoDbTableEncryptionConfig{
119+
LogicalTableName: ddbTableName,
120+
PartitionKeyName: partitionKey,
121+
SortKeyName: &sortKeyName,
122+
AttributeActionsOnEncrypt: attributeActionsOnEncrypt,
123+
Keyring: rawAesKeyring,
124+
AllowedUnsignedAttributePrefix: &unsignedAttrPrefix,
125+
}
126+
tableConfigsMap := make(map[string]dbesdkdynamodbencryptiontypes.DynamoDbTableEncryptionConfig)
127+
tableConfigsMap[ddbTableName] = tableConfig
128+
listOfTableConfigs := dbesdkdynamodbencryptiontypes.DynamoDbTablesEncryptionConfig{
129+
TableEncryptionConfigs: tableConfigsMap,
130+
}
131+
// 5. Create a new AWS SDK DynamoDb client using the Config above
132+
133+
// Create DBESDK middleware
134+
dbEsdkMiddleware, err := dbesdkmiddleware.NewDBEsdkMiddleware(listOfTableConfigs)
135+
if err != nil {
136+
panic(err)
137+
}
138+
// Create aws config
139+
cfg, err := config.LoadDefaultConfig(context.TODO())
140+
if err != nil {
141+
panic(err)
142+
}
143+
ddb := dynamodb.NewFromConfig(cfg, dbEsdkMiddleware.CreateMiddleware())
144+
145+
// 6. Put an item into our table using the above client.
146+
// Before the item gets sent to DynamoDb, it will be encrypted
147+
// client-side, according to our configuration.
148+
item := map[string]types.AttributeValue{
149+
"partition_key": &types.AttributeValueMemberS{Value: "rawAesKeyringItem"},
150+
"sort_key": &types.AttributeValueMemberN{Value: "0"},
151+
"sensitive_data": &types.AttributeValueMemberS{Value: "encrypt and sign me!"},
152+
}
153+
putInput := &dynamodb.PutItemInput{
154+
TableName: aws.String(ddbTableName),
155+
Item: item,
156+
}
157+
_, err = ddb.PutItem(context.TODO(), putInput)
158+
if err != nil {
159+
panic(err)
160+
}
161+
// 7. Get the item back from our table using the same client.
162+
// The client will decrypt the item client-side, and return
163+
// back the original item.
164+
key := map[string]types.AttributeValue{
165+
"partition_key": &types.AttributeValueMemberS{Value: "rawAesKeyringItem"},
166+
"sort_key": &types.AttributeValueMemberN{Value: "0"},
167+
}
168+
getInput := &dynamodb.GetItemInput{
169+
TableName: aws.String(ddbTableName),
170+
Key: key,
171+
// In this example we configure a strongly consistent read
172+
// because we perform a read immediately after a write (for demonstrative purposes).
173+
// By default, reads are only eventually consistent.
174+
// Read our docs to determine which read consistency to use for your application:
175+
// https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html
176+
ConsistentRead: aws.Bool(true),
177+
}
178+
result, err := ddb.GetItem(context.TODO(), getInput)
179+
if err != nil {
180+
panic(err)
181+
}
182+
// Verify the decrypted item
183+
if !reflect.DeepEqual(item, result.Item) {
184+
panic("Decrypted item does not match original item")
185+
}
186+
fmt.Println("Raw Aes Example successful.")
187+
}
188+
189+
func generateAes256KeyBytes() ([]byte, error) {
190+
key := make([]byte, 32) // 256 bits = 32 bytes
191+
// Use crypto/rand for cryptographically secure random numbers
192+
_, err := rand.Read(key)
193+
if err != nil {
194+
return nil, err
195+
}
196+
return key, nil
197+
}

Examples/runtimes/go/main.go

+1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ import (
77

88
func main() {
99
keyring.AwsKmsKeyringExample(utils.KmsKeyID(), utils.DdbTableName())
10+
keyring.RawAesExample(utils.DdbTableName())
1011
}

0 commit comments

Comments
 (0)