Skip to content

Commit 5d70d74

Browse files
Merge branch 'main' into scchatur/PerfTest
2 parents 08f4ceb + 9d3e101 commit 5d70d74

File tree

40 files changed

+437
-178
lines changed

40 files changed

+437
-178
lines changed

.github/workflows/ci_examples_java.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
# Don't run the nightly build on forks
2929
if: github.event_name != 'schedule' || github.repository_owner == 'awslabs'
3030
strategy:
31-
max-parallel: 1 # TODO: Fix jobs failing when running in parallel
31+
max-parallel: 1
3232
matrix:
3333
java-version: [ 8, 11, 16, 17 ]
3434
os: [

.github/workflows/ci_test_java.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
strategy:
3131
matrix:
3232
library: [
33-
DynamoDbEncryption,
33+
DynamoDbEncryption
3434
]
3535
java-version: [ 8, 11, 16, 17 ]
3636
os: [
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# This workflow performs test vectors in Java.
2+
name: Library Java Test Vectors
3+
4+
on:
5+
pull_request:
6+
push:
7+
branches:
8+
- main
9+
10+
jobs:
11+
testJava:
12+
strategy:
13+
matrix:
14+
java-version: [ 8, 11, 16, 17 ]
15+
os: [
16+
# Run on ubuntu image that comes pre-configured with docker
17+
ubuntu-latest
18+
]
19+
runs-on: ${{ matrix.os }}
20+
environment: "MPL CI"
21+
permissions:
22+
id-token: write
23+
contents: read
24+
steps:
25+
- name: Setup DynamoDB Local
26+
uses: rrainn/[email protected]
27+
with:
28+
port: 8000
29+
cors: '*'
30+
31+
- name: Configure AWS Credentials
32+
uses: aws-actions/configure-aws-credentials@v1
33+
with:
34+
aws-region: us-west-2
35+
role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-DDBEC-Dafny-Role-us-west-2
36+
role-session-name: DDBEC-Dafny-Java-Tests
37+
38+
- uses: actions/checkout@v3
39+
40+
- name: Init Submodules
41+
env:
42+
# This secret is in the configured environment,
43+
# and set to expire every 30 days
44+
MPL_PAT: ${{ secrets.MPL_PAT }}
45+
run: |
46+
AUTH="$(echo -n "pat:${MPL_PAT}" | base64 | tr -d '\n')"
47+
git config --global http.https://github.com/.extraheader "AUTHORIZATION: basic $AUTH"
48+
git config --global --add url.https://github.com/.insteadOf [email protected]:
49+
git submodule update --init --recursive submodules/MaterialProviders
50+
51+
- name: Setup Dafny
52+
uses: dafny-lang/[email protected]
53+
with:
54+
dafny-version: '4.1.0'
55+
56+
- name: Setup Java ${{ matrix.java-version }}
57+
uses: actions/setup-java@v3
58+
with:
59+
distribution: 'corretto'
60+
java-version: ${{ matrix.java-version }}
61+
62+
- name: Build TestVectors implementation
63+
shell: bash
64+
working-directory: ./TestVectors
65+
run: |
66+
# This works because `node` is installed by default on GHA runners
67+
CORES=$(node -e 'console.log(os.cpus().length)')
68+
make build_java CORES=$CORES
69+
70+
- name: Test TestVectors
71+
working-directory: ./TestVectors
72+
run: |
73+
make test_java

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[submodule "submodules/MaterialProviders"]
22
path = submodules/MaterialProviders
3-
url = https://github.com/aws/aws-cryptographic-material-providers-library-dafny.git
3+
url = https://github.com/aws/aws-cryptographic-material-providers-library-java.git
44
[submodule "submodules/smithy-dafny"]
55
path = submodules/smithy-dafny
66
url = [email protected]:awslabs/smithy-dafny.git

DynamoDbEncryption/dafny/StructuredEncryption/src/AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations.dfy

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -344,31 +344,25 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
344344
)
345345
}
346346

347-
// TODO this is a workaround for a very silly issue with case sensitivity between package names,
348-
// that prevents this code from always correctly finding `dafny.Function4`.
349-
// For now, put all inputs into one datatype so we are only using `dafny.Function1` here.
350-
datatype CanonizeForDecryptInput = CanonizeForDecryptInput(
347+
// construct the DecryptCanon
348+
function method {:opaque} {:vcs_split_on_every_assert} CanonizeForDecrypt(
351349
tableName: GoodString,
352350
data: StructuredDataPlain,
353351
authSchema: AuthSchemaPlain,
354352
legend: Header.Legend
355-
)
356-
357-
// construct the DecryptCanon
358-
function method {:opaque} {:vcs_split_on_every_assert} CanonizeForDecrypt(input: CanonizeForDecryptInput)
359-
: (ret : Result<DecryptCanon, Error>)
360-
requires input.authSchema.Keys == input.data.Keys
353+
) : (ret : Result<DecryptCanon, Error>)
354+
requires authSchema.Keys == data.Keys
361355
ensures ret.Success? ==>
362-
&& |ret.value.signedFields_c| == |input.legend|
356+
&& |ret.value.signedFields_c| == |legend|
363357
ensures ret.Success? ==>
364-
&& (forall k :: k in input.data.Keys && input.authSchema[k].content.Action.SIGN? ==> Paths.SimpleCanon(input.tableName, k) in ret.value.data_c.Keys)
358+
&& (forall k :: k in data.Keys && authSchema[k].content.Action.SIGN? ==> Paths.SimpleCanon(tableName, k) in ret.value.data_c.Keys)
365359
ensures ret.Success? ==>
366-
&& (forall v :: v in ret.value.data_c.Values ==> v in input.data.Values)
360+
&& (forall v :: v in ret.value.data_c.Values ==> v in data.Values)
367361
ensures ret.Success? ==>
368362
&& ret.value.cryptoSchema.content.SchemaMap?
369363
&& CryptoSchemaMapIsFlat(ret.value.cryptoSchema.content.SchemaMap)
370-
&& AuthSchemaIsFlat(input.authSchema)
371-
&& ValidParsedCryptoSchema(ret.value.cryptoSchema.content.SchemaMap, input.authSchema, input.tableName)
364+
&& AuthSchemaIsFlat(authSchema)
365+
&& ValidParsedCryptoSchema(ret.value.cryptoSchema.content.SchemaMap, authSchema, tableName)
372366
{
373367
//= specification/structured-encryption/decrypt-structure.md#calculate-signed-and-encrypted-field-lists
374368
//# The `signed field list` MUST be all fields for which
@@ -378,18 +372,18 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
378372
//# sorted by the [Canonical Path](header.md.#canonical-path).
379373

380374
reveal Maps.Injective();
381-
Paths.SimpleCanonUnique(input.tableName);
382-
var fieldMap := map k <- input.data | input.authSchema[k].content.Action == SIGN ::
383-
Paths.SimpleCanon(input.tableName, k) := k;
375+
Paths.SimpleCanonUnique(tableName);
376+
var fieldMap := map k <- data | authSchema[k].content.Action == SIGN ::
377+
Paths.SimpleCanon(tableName, k) := k;
384378
assert Maps.Injective(fieldMap);
385379

386-
var data_c := map k <- fieldMap :: k := input.data[fieldMap[k]];
380+
var data_c := map k <- fieldMap :: k := data[fieldMap[k]];
387381
var signedFields_c := SortedSets.ComputeSetToOrderedSequence2(data_c.Keys, ByteLess);
388382

389-
if |input.legend| < |signedFields_c| then
383+
if |legend| < |signedFields_c| then
390384
Failure(E("Schema changed : something that was unsigned is now signed."))
391385
else
392-
if |input.legend| > |signedFields_c| then
386+
if |legend| > |signedFields_c| then
393387
Failure(E("Schema changed : something that was signed is now unsigned."))
394388
else
395389

@@ -398,11 +392,11 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
398392
//# for which the corresponding byte in the [Encrypt Legend](header.md.#encrypt-legend)
399393
//# is `0x65` indicating [Encrypt and Sign](header.md.#encrypt-legend-bytes),
400394
//# sorted by the field's [canonical path](./header.md#canonical-path).
401-
var encFields_c : seq<CanonicalPath> := FilterEncrypted(signedFields_c, input.legend);
395+
var encFields_c : seq<CanonicalPath> := FilterEncrypted(signedFields_c, legend);
402396
:- Need(|encFields_c| < (UINT32_LIMIT / 3), E("Too many encrypted fields."));
403397

404398
var actionMap := map k <- fieldMap ::
405-
fieldMap[k] := if Paths.SimpleCanon(input.tableName, fieldMap[k]) in encFields_c then
399+
fieldMap[k] := if Paths.SimpleCanon(tableName, fieldMap[k]) in encFields_c then
406400
CryptoSchema(
407401
content := CryptoSchemaContent.Action(ENCRYPT_AND_SIGN),
408402
attributes := None
@@ -815,8 +809,7 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
815809
var ok :- head.verifyCommitment(config.primitives, postCMMAlg, commitKey, headerSerialized);
816810

817811
:- Need(ValidString(input.tableName), E("Bad Table Name"));
818-
var canonData :- CanonizeForDecrypt(
819-
CanonizeForDecryptInput(input.tableName, encRecord, authSchema, head.legend));
812+
var canonData :- CanonizeForDecrypt(input.tableName, encRecord, authSchema, head.legend);
820813

821814
//= specification/structured-encryption/decrypt-structure.md#calculate-signed-and-encrypted-field-lists
822815
//= type=implication
@@ -899,7 +892,7 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
899892
output := Success(decryptOutput);
900893
}
901894

902-
// TODO This is here temporarially until it gets merged into the standard library
895+
// predicates/lemmas like this are not yet provided out of the box in the standard library.
903896
predicate {:opaque} Contains<X, Y>(big: map<X, Y>, small: map<X, Y>)
904897
{
905898
&& small.Keys <= big.Keys

DynamoDbEncryption/dafny/StructuredEncryption/test/Paths.dfy

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,22 @@ module PathsTests {
1010
import opened StructuredEncryptionPaths
1111

1212
method {:test} TestSpecExamples() {
13-
/*
14-
TODO - remake these tests without the parsing step
15-
1613
var tableName : GoodString := "example_table";
1714
assert(ValidString("example_table"));
18-
var nameSrc :- expect MakeTerminalLocation("name");
19-
expect nameSrc.canonicalPath(tableName) ==
15+
var name := Selector.Map("name");
16+
var pathToTest := TerminalLocation([name]);
17+
expect pathToTest.canonicalPath(tableName) ==
2018
UTF8.EncodeAscii("example_table")
2119
+ [0,0,0,0,0,0,0,1] // depth
2220
+ ['$' as uint8] // map
2321
+ [0,0,0,0,0,0,0,4] // length
2422
+ UTF8.EncodeAscii("name");
2523

26-
var stampSrc :- expect MakeTerminalLocation("status-history[0].timestamp");
27-
expect stampSrc.canonicalPath(tableName) ==
24+
var history := Selector.Map("status-history");
25+
var index := Selector.List(0);
26+
var timestamp := Selector.Map("timestamp");
27+
var pathToTest2 := TerminalLocation([history, index, timestamp]);
28+
expect pathToTest2.canonicalPath(tableName) ==
2829
UTF8.EncodeAscii("example_table")
2930
+ [0,0,0,0,0,0,0,3] // depth
3031
+ ['$' as uint8] // map
@@ -35,6 +36,5 @@ module PathsTests {
3536
+ ['$' as uint8] // map
3637
+ [0,0,0,0,0,0,0,9] // length of "timestamp"
3738
+ UTF8.EncodeAscii("timestamp");
38-
*/
3939
}
4040
}

DynamoDbEncryption/runtimes/java/src/test/sdkv1/com/amazonaws/services/dynamodbv2/datamodeling/TransformerHolisticIT.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,6 @@ public void leadingAndTrailingZeros() {
618618

619619
mapper.save(obj);
620620

621-
// TODO: Update the mock to handle this appropriately.
622621
// DynamoDb discards leading and trailing zeros from numbers
623622
Map<String, AttributeValue> key = new HashMap<String, AttributeValue>();
624623
key.put(HASH_KEY, new AttributeValue().withN("0"));

Examples/runtimes/java/DynamoDbEncryption/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33

44
# Ignore Gradle build output directory
55
build
6+
7+
*.pem

Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/BasicPutGetExample.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -85,48 +85,46 @@ public static void PutItemGetItem(String kmsKeyId, String ddbTableName) {
8585
//
8686
// For this example, we have designed our DynamoDb table such that any attribute name with
8787
// the ":" prefix should be considered unauthenticated.
88-
final String unauthAttrPrefix = ":";
88+
final String unsignAttrPrefix = ":";
8989

90-
// 3. Create the DynamoDb Encryption configuration for the table we will be writing to.
90+
// 4. Create the DynamoDb Encryption configuration for the table we will be writing to.
9191
final Map<String, DynamoDbTableEncryptionConfig> tableConfigs = new HashMap<>();
9292
final DynamoDbTableEncryptionConfig config = DynamoDbTableEncryptionConfig.builder()
9393
.logicalTableName(ddbTableName)
9494
.partitionKeyName("partition_key")
9595
.sortKeyName("sort_key")
9696
.attributeActionsOnEncrypt(attributeActionsOnEncrypt)
9797
.keyring(kmsKeyring)
98-
.allowedUnsignedAttributePrefix(unauthAttrPrefix)
98+
.allowedUnsignedAttributePrefix(unsignAttrPrefix)
9999
// Specifying an algorithm suite is not required,
100100
// but is done here to demonstrate how to do so.
101101
// We suggest using the
102102
// `ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384` suite,
103103
// which includes AES-GCM with key derivation, signing, and key commitment.
104104
// This is also the default algorithm suite if one is not specified in this config.
105-
// For more information on supported algorithm suites, see
106-
// TODO: Add DB ESDK-specific link, similar to
107-
// https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/supported-algorithms.html,
108-
// but with accurate information for DB ESDK
105+
// For more information on supported algorithm suites, see:
106+
// https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/supported-algorithms.html
109107
.algorithmSuiteId(
110108
DBEAlgorithmSuiteId.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384)
111109
.build();
112110
tableConfigs.put(ddbTableName, config);
113111

114-
// 4. Create the DynamoDb Encryption Interceptor
112+
// 5. Create the DynamoDb Encryption Interceptor
115113
DynamoDbEncryptionInterceptor encryptionInterceptor = DynamoDbEncryptionInterceptor.builder()
116114
.config(DynamoDbTablesEncryptionConfig.builder()
117115
.tableEncryptionConfigs(tableConfigs)
118116
.build())
119117
.build();
120118

121-
// 5. Create a new AWS SDK DynamoDb client using the DynamoDb Encryption Interceptor above
119+
// 6. Create a new AWS SDK DynamoDb client using the DynamoDb Encryption Interceptor above
122120
final DynamoDbClient ddb = DynamoDbClient.builder()
123121
.overrideConfiguration(
124122
ClientOverrideConfiguration.builder()
125123
.addExecutionInterceptor(encryptionInterceptor)
126124
.build())
127125
.build();
128126

129-
// 6. Put an item into our table using the above client.
127+
// 7. Put an item into our table using the above client.
130128
// Before the item gets sent to DynamoDb, it will be encrypted
131129
// client-side, according to our configuration.
132130
final HashMap<String, AttributeValue> item = new HashMap<>();
@@ -146,7 +144,7 @@ public static void PutItemGetItem(String kmsKeyId, String ddbTableName) {
146144
// Demonstrate that PutItem succeeded
147145
assert 200 == putResponse.sdkHttpResponse().statusCode();
148146

149-
// 7. Get the item back from our table using the same client.
147+
// 8. Get the item back from our table using the same client.
150148
// The client will decrypt the item client-side, and return
151149
// back the original item.
152150
final HashMap<String, AttributeValue> keyToGet = new HashMap<>();

Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/clientsupplier/ClientSupplierExample.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public static void ClientSupplierPutItemGetItem(String ddbTableName, String keyA
107107
//
108108
// For this example, we currently authenticate all attributes. To make it easier to
109109
// add unauthenticated attributes in the future, we define a prefix ":" for such attributes.
110-
final String unauthAttrPrefix = ":";
110+
final String unsignAttrPrefix = ":";
111111

112112
// 4. Create the DynamoDb Encryption configuration for the table we will be writing to.
113113
final Map<String, DynamoDbTableEncryptionConfig> tableConfigs = new HashMap<>();
@@ -117,7 +117,7 @@ public static void ClientSupplierPutItemGetItem(String ddbTableName, String keyA
117117
.sortKeyName("sort_key")
118118
.attributeActionsOnEncrypt(attributeActionsOnEncrypt)
119119
.keyring(mrkKeyringWithClientSupplier)
120-
.allowedUnsignedAttributePrefix(unauthAttrPrefix)
120+
.allowedUnsignedAttributePrefix(unsignAttrPrefix)
121121
.build();
122122
tableConfigs.put(ddbTableName, config);
123123

@@ -208,7 +208,7 @@ public static void ClientSupplierPutItemGetItem(String ddbTableName, String keyA
208208
.attributeActionsOnEncrypt(attributeActionsOnEncrypt)
209209
// Provide discovery keyring here
210210
.keyring(mrkDiscoveryClientSupplierKeyring)
211-
.allowedUnsignedAttributePrefix(unauthAttrPrefix)
211+
.allowedUnsignedAttributePrefix(unsignAttrPrefix)
212212
.build();
213213
onlyReplicaKeyTableConfigs.put(ddbTableName, onlyReplicaKeyConfig);
214214

@@ -248,9 +248,6 @@ public static void ClientSupplierPutItemGetItem(String ddbTableName, String keyA
248248
assert 200 == onlyReplicaKeyGetResponse.sdkHttpResponse().statusCode();
249249
final Map<String, AttributeValue> onlyReplicaKeyReturnedItem = onlyReplicaKeyGetResponse.item();
250250
assert onlyReplicaKeyReturnedItem.get("sensitive_data").s().equals("encrypt and sign me!");
251-
252-
// TODO: After adding MissingRegionException, give an example with a fake region
253-
// demonstrating that MissingRegionException extends AwsCryptographicMaterialProvidersException
254251
}
255252

256253
public static void main(final String[] args) {

0 commit comments

Comments
 (0)