Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: EncryptItem and DecryptItem #22

Merged
merged 10 commits into from
Dec 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions DynamoDbItemEncryptor/Model/DynamoDbItemEncryptor.smithy
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ operation DecryptItem {
output: DecryptItemOutput,
}

//= specification/dynamodb-encryption-client/encrypt-item.md#input
//= type=implication
//# The following inputs to this behavior are REQUIRED:
//# - DynamoDB Item
structure EncryptItemInput {
@required
plaintextItem: AttributeMap,
Expand All @@ -65,6 +69,10 @@ structure EncryptItemOutput {
encryptedItem: AttributeMap,
}

//= specification/dynamodb-encryption-client/decrypt-item.md#input
//= type=implication
//# The following inputs to this behavior are REQUIRED:
ajewellamz marked this conversation as resolved.
Show resolved Hide resolved
//# - DynamoDB Item
structure DecryptItemInput {
@required
encryptedItem: AttributeMap,
Expand Down

Large diffs are not rendered by default.

625 changes: 545 additions & 80 deletions DynamoDbItemEncryptor/src/DynamoToStruct.dfy

Large diffs are not rendered by default.

101 changes: 0 additions & 101 deletions DynamoDbItemEncryptor/src/StubbedData.dfy

This file was deleted.

56 changes: 56 additions & 0 deletions DynamoDbItemEncryptor/test/DynamoDBItemEncryptorTest.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,62 @@ module DynamoDbItemEncryptorTest {
import UTF8
import DDB = ComAmazonawsDynamodbTypes
import TestFixtures
import AwsCryptographyDynamoDbItemEncryptorOperations

// round trip
// encrypt => ecrypted fields changed, others did not
// various errors

function method DDBS(x : string) : DDB.AttributeValue {
DDB.AttributeValue.S(x)
}

method {:test} TestUnexpectedField() {
var encryptor := TestFixtures.GetDynamoDbItemEncryptor();
var inputItem := map["bar" := DDBS("key"), "encrypt" := DDBS("foo"), "sign" := DDBS("bar"), "nothing" := DDBS("baz"), "unknown" := DDBS("other")];
var encryptRes := encryptor.EncryptItem(
Types.EncryptItemInput(
plaintextItem:=inputItem
)
);
expect encryptRes.Failure?;
expect encryptRes.error == Types.DynamoDbItemEncryptorException(message := "No Crypto Action configured for attribute unknown");
}

method {:test} TestRoundTrip() {
var encryptor := TestFixtures.GetDynamoDbItemEncryptor();
var inputItem := map["bar" := DDBS("key"), "encrypt" := DDBS("foo"), "sign" := DDBS("bar"), "nothing" := DDBS("baz")];
var encryptRes := encryptor.EncryptItem(
Types.EncryptItemInput(
plaintextItem:=inputItem
)
);
var encrypted :- expect encryptRes;
var decryptRes := encryptor.DecryptItem(
Types.DecryptItemInput(
encryptedItem:=encrypted.encryptedItem
)
);
var decrypted :- expect decryptRes;
expect decrypted.plaintextItem == inputItem;
}


method {:test} TestMissingSortKey() {
var config := TestFixtures.GetEncryptorConfig();
var inputItem := map["bar" := DDBS("key"), "encrypt" := DDBS("foo"), "sign" := DDBS("bar"), "nothing" := DDBS("baz")];
var config2 := config.(sortKeyName := Some("sort"));
var encryptor := TestFixtures.GetDynamoDbItemEncryptorFrom(config2);
var encryptRes := encryptor.EncryptItem(
Types.EncryptItemInput(
plaintextItem:=inputItem
)
);
expect encryptRes.Failure?;
expect encryptRes.error == Types.DynamoDbItemEncryptorException(message := "Sort key sort not found in Item to be encrypted or decrypted");
}

/*
method {:test} TestEncryptItem() {
// Create the Item Encryptor
var encryptor := TestFixtures.GetDynamoDbItemEncryptor();
Expand Down Expand Up @@ -64,4 +119,5 @@ module DynamoDbItemEncryptorTest {
expect decryptRes.Success?;
expect decryptRes.value.plaintextItem == expectedItem;
}
*/
}
109 changes: 106 additions & 3 deletions DynamoDbItemEncryptor/test/DynamoToStruct.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,21 @@ module DynamoToStructTest {
{
var data := StructuredDataTerminal(value := data, typeId := typeId);
var sdata := StructuredData(content := Terminal(data), attributes := None);
expect StructuredToAttr(sdata).Failure?;
var result := StructuredToAttr(sdata);
if !result.Failure? {
print "\nStructuredToAttr should have failed with this data : ", data, "\n";
}
expect result.Failure?;
}
method DoSucceed(data : seq<uint8>, typeId : TerminalTypeId)
{
var data := StructuredDataTerminal(value := data, typeId := typeId);
var sdata := StructuredData(content := Terminal(data), attributes := None);
expect StructuredToAttr(sdata).Success?;
var result := StructuredToAttr(sdata);
if !result.Success? {
print "\nUnexpected failure of StructuredToAttr : ", result, "\n";
}
expect result.Success?;
}

method {:test} {:vcs_split_on_every_assert} TestZeroBytes() {
Expand All @@ -38,17 +46,48 @@ module DynamoToStructTest {
DoFail([], LIST);
}

const k := 'k' as uint8;
const e := 'e' as uint8;
const y := 'y' as uint8;
const A := 'A' as uint8;
const B := 'B' as uint8;
const C := 'C' as uint8;
const D := 'D' as uint8;

method {:test} {:vcs_split_on_every_assert} TestBadType() {
DoSucceed([0,0,0,1, 0,0, 0,0,0,0], LIST);
DoFail ([0,0,0,1, 3,1, 0,0,0,0], LIST);
}

method {:test} {:vcs_split_on_every_assert} TestBadLength() {
method {:test} {:vcs_split_on_every_assert} TestBadLengthList() {
DoFail ([0,0,0,1, 0,3, 0,0,0,2, 1], LIST);
DoSucceed([0,0,0,1, 0,3, 0,0,0,2, 1,2], LIST);
DoFail ([0,0,0,1, 0,3, 0,0,0,2, 1,2,3], LIST);
}

method {:test} {:vcs_split_on_every_assert} TestBadLengthMap() {
DoFail([0,0,0,1, 0,1, 0,0,0,4, k,e,y,A, 0,3, 0,0,0,5, 1,2,3,4], MAP);
DoSucceed([0,0,0,1, 0,1, 0,0,0,4, k,e,y,A, 0,3, 0,0,0,5, 1,2,3,4,5], MAP);
DoFail([0,0,0,1, 0,1, 0,0,0,4, k,e,y,A, 0,3, 0,0,0,5, 1,2,3,4,5,6], MAP);
}

method {:test} {:vcs_split_on_every_assert} TestBadDupKeys() {
//= specification/dynamodb-encryption-client/ddb-item-conversion.md#duplicates
//= type=test
//# - Conversion from a Structured Data Map MUST fail if it has duplicate keys
DoSucceed([0,0,0,2, 0,1, 0,0,0,4, k,e,y,A, 0,3, 0,0,0,5, 1,2,3,4,5, 0,1, 0,0,0,4, k,e,y,B, 0,3, 0,0,0,5, 1,2,3,4,5], MAP);
DoFail ([0,0,0,2, 0,1, 0,0,0,4, k,e,y,A, 0,3, 0,0,0,5, 1,2,3,4,5, 0,1, 0,0,0,4, k,e,y,A, 0,3, 0,0,0,5, 1,2,3,4,5], MAP);

DoSucceed([0,0,0,2, 0,0,0,3, 49,50,51, 0,0,0,3, 52,53,54], BINARY_SET);
DoFail ([0,0,0,2, 0,0,0,3, 49,50,51, 0,0,0,3, 49,50,51], BINARY_SET);

DoSucceed([0,0,0,2, 0,0,0,3, 49,50,51, 0,0,0,3, 52,53,54], NUMBER_SET);
DoFail ([0,0,0,2, 0,0,0,3, 49,50,51, 0,0,0,3, 49,50,51], NUMBER_SET);

DoSucceed([0,0,0,2, 0,0,0,3, 49,50,51, 0,0,0,3, 52,53,54], STRING_SET);
DoFail ([0,0,0,2, 0,0,0,3, 49,50,51, 0,0,0,3, 49,50,51], STRING_SET);
}

// Split because verification timed out
method {:test} {:vcs_split_on_every_assert} TestEncode2() {
var stringValue := AttributeValue.S("abc");
Expand Down Expand Up @@ -141,6 +180,34 @@ module DynamoToStructTest {
expect newBoolValue.Success?;
expect newBoolValue.value == boolValue;

//= specification/dynamodb-encryption-client/ddb-attribute-serialization.md#list-entries
//= type=test
//# Each list entry in the sequence MUST be serialized as:
ajewellamz marked this conversation as resolved.
Show resolved Hide resolved
//# | Field | Length |
//# | -------------------- | -------------------------- |
//# | List Entry Type | 2 |
//# | List Entry Length | 4 |
//# | List Entry Value | Variable. Equal to Length. |

//= specification/dynamodb-encryption-client/ddb-attribute-serialization.md#list-entries
//= type=test
//# The order of these serialized list entries MUST match
//# the order of the entries in the original list.

// for list-entry-length see also TestBadLengthList() above
//= specification/dynamodb-encryption-client/ddb-attribute-serialization.md#list-entry-length
//= type=test
//# List Entry Length MUST be a big-endian unsigned integer
//# equal to the length of [List Entry Value](#list-entry-value).
lavaleri marked this conversation as resolved.
Show resolved Hide resolved

//= specification/dynamodb-encryption-client/ddb-attribute-serialization.md#list-entry-type
//= type=test
//# List Entry Type MUST be the [Type ID](#type-id) of the type of [List Entry Value](#list-entry-value).

//= specification/dynamodb-encryption-client/ddb-attribute-serialization.md#list-entry-value
//= type=test
//# A List MAY hold any DynamoDB Attribute Value data type,
//# and MAY hold values of different types.
var listValue := AttributeValue.L([binaryValue, nullValue, boolValue]);
var encodedListData := StructuredDataTerminal(value := [0,0,0,3, 0,3, 0,0,0,5, 1,2,3,4,5, 0,0, 0,0,0,0, 0,4, 0,0,0,1, 0], typeId := [3,0]);
var encodedListValue := StructuredData(content := Terminal(encodedListData), attributes := None);
Expand All @@ -161,6 +228,36 @@ module DynamoToStructTest {
var C := 'C' as uint8;
var D := 'D' as uint8;

//= specification/dynamodb-encryption-client/ddb-attribute-serialization.md#key-value-pair-entries
//= type=test
//# Each key-value pair MUST be serialized as:
lavaleri marked this conversation as resolved.
Show resolved Hide resolved
//# | Field | Length |
//# | ------------ | -------- |
//# | Key Type | 2 |
//# | Key Length | 4 |
//# | Map Key | Variable |
//# | Value Type | 2 |
//# | Value Length | 4 |
//# | Map Value | Variable |

//= specification/dynamodb-encryption-client/ddb-attribute-serialization.md#value-type
//= type=test
//# Value Type MUST be the [Type ID](#type-id) of the type of [Map Value](#map-value).

// for value-length see also TestBadLengthMap() above
//= specification/dynamodb-encryption-client/ddb-attribute-serialization.md#value-length
//= type=test
//# Value Length MUST be a big-endian unsigned integer
//# equal to the length of [Map Value](#map-value).
lavaleri marked this conversation as resolved.
Show resolved Hide resolved

//= specification/dynamodb-encryption-client/ddb-attribute-serialization.md#map-value
//= type=test
//# Map Value MUST be a [Value](#value).

//= specification/dynamodb-encryption-client/ddb-attribute-serialization.md#map-value
//= type=test
//# A Map MAY hold any DynamoDB Attribute Value data type,
//# and MAY hold values of different types.
var encodedMapData := StructuredDataTerminal(value :=
[0,0,0,4,
0,1, 0,0,0,4, k,e,y,A, 0,3, 0,0,0,5, 1,2,3,4,5,
Expand All @@ -178,6 +275,12 @@ module DynamoToStructTest {
expect newMapValue.value == mapValue;
}

//= specification/dynamodb-encryption-client/ddb-item-conversion.md#overview
//= type=test
//# The conversion from DDB Item to Structured Data must be lossless,
//# meaning that converting a DDB Item to
//# a Structured Data and back to a DDB Item again
//# MUST result in the exact same DDB Item.
method {:test} {:vcs_split_on_every_assert} TestRoundTrip() {

var val1 := AttributeValue.S("astring");
Expand Down
Loading