1
+ // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ include "JsonConfig. dfy"
5
+ include "WriteManifest. dfy"
6
+ include ".. / .. / .. / .. / DynamoDbEncryption/ dafny/ DynamoDbItemEncryptor/ src/ Index. dfy"
7
+
8
+ module {:options "- functionSyntax:4"} EncryptManifest {
9
+ import opened Wrappers
10
+ import opened StandardLibrary
11
+ import opened StandardLibrary. UInt
12
+ import opened JSON. Values
13
+ import opened WriteManifest
14
+ import JSON. API
15
+ import JSON. Errors
16
+ import opened DynamoDbEncryptionUtil
17
+ import DdbItemJson
18
+ import StandardLibrary. String
19
+ import FileIO
20
+ import opened JSONHelpers
21
+ import JsonConfig
22
+ import ENC = AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes
23
+
24
+ function Manifest () : (string , JSON)
25
+ {
26
+ var result : seq < (string , JSON)> :=
27
+ [
28
+ ("type ", String (DECRYPT_TYPE)),
29
+ ("version", String ("1"))
30
+ ];
31
+ ("manifest", Object (result))
32
+ }
33
+
34
+ function Client (lang : string , version : string ) : (string , JSON)
35
+ {
36
+ var result : seq < (string , JSON)> :=
37
+ [
38
+ ("name", String (LIB_PREFIX + lang)),
39
+ ("version", String (version))
40
+ ];
41
+ ("client", Object (result))
42
+ }
43
+
44
+ method OnePositiveTest (name : string , theType : string , desc : string , config : JSON , decryptConfig : Option <JSON >, record : JSON ) returns (output : Result< (string , JSON), string > )
45
+ {
46
+ var rec :- JsonConfig. GetRecord (record);
47
+ var encryptor :- JsonConfig. GetItemEncryptor (name, config);
48
+ var encrypted :- expect encryptor. EncryptItem (
49
+ ENC.EncryptItemInput(
50
+ plaintextItem:=rec.item
51
+ )
52
+ );
53
+ var item :- expect DdbItemJson. DdbItemToJson (encrypted.encryptedItem);
54
+
55
+ var result : seq < (string , JSON)> :=
56
+ [
57
+ ("type ", String (theType)),
58
+ ("description", String (desc)),
59
+ ("config", if decryptConfig. Some? then decryptConfig. value else config),
60
+ ("plaintext", record),
61
+ ("encrypted", item)
62
+ ];
63
+ return Success ((name, Object(result)));
64
+ }
65
+
66
+ method OneNegativeTest (name : string , config : JSON , record : JSON ) returns (output : Result< bool , string > )
67
+ {
68
+ var rec :- JsonConfig. GetRecord (record);
69
+ var encryptor :- JsonConfig. GetItemEncryptor (name, config);
70
+ var encrypted := encryptor. EncryptItem (
71
+ ENC.EncryptItemInput(
72
+ plaintextItem:=rec.item
73
+ )
74
+ );
75
+ if encrypted. Success? {
76
+ return Failure ("Test " + name + " failed to fail to encrypt.");
77
+ }
78
+ return Success (true);
79
+ }
80
+
81
+
82
+ method OneTest (name : string , value : JSON ) returns (output : Result< Option< (string , JSON)> , string > )
83
+ {
84
+ :- Need (value.Object?, "Test must be an object");
85
+ print "Examining ", name, "\n";
86
+
87
+ var types : Option< string > := None;
88
+ var description : Option< string > := None;
89
+ var config : Option< JSON> := None;
90
+ var decryptConfig : Option< JSON> := None;
91
+ var record : Option< JSON> := None;
92
+
93
+ for i := 0 to |value. obj| {
94
+ var obj := value. obj[i];
95
+ match obj. 0 {
96
+ case "type " =>
97
+ :- Need (obj.1.String?, "Value of 'type' must be a string.");
98
+ types := Some (obj.1.str);
99
+ case "description" =>
100
+ :- Need (obj.1.String?, "Value of 'description' must be a string.");
101
+ description := Some (obj.1.str);
102
+ case "config" =>
103
+ :- Need (obj.1.Object?, "Value of 'config' must be an object.");
104
+ config := Some (obj.1);
105
+ case "decryptConfig" =>
106
+ :- Need (obj.1.Object?, "Value of 'decryptConfig' must be an object.");
107
+ decryptConfig := Some (obj.1);
108
+ case "record" =>
109
+ :- Need (obj.1.Object?, "Value of 'record' must be an object.");
110
+ record := Some (obj.1);
111
+ case _ => return Failure ("Unknown test member : " + obj.0 + " in " + name);
112
+ }
113
+ }
114
+ :- Need (types.Some?, "Test requires a 'type' member.");
115
+ :- Need (description.Some?, "Test requires a 'description' member.");
116
+ :- Need (config.Some?, "Test requires a 'config' member.");
117
+ :- Need (record.Some?, "Test requires a 'record' member.");
118
+
119
+ if types. value == "positive- encrypt" {
120
+ var x :- OnePositiveTest (name, "positive-decrypt", description.value, config.value, decryptConfig, record.value);
121
+ return Success (Some(x));
122
+ } else if types. value == "negative- decrypt" {
123
+ var x :- OnePositiveTest (name, "negative-decrypt", description.value, config.value, decryptConfig, record.value);
124
+ return Success (Some(x));
125
+ } else if types. value == "negative- encrypt" {
126
+ var _ := OneNegativeTest (name, config.value, record.value);
127
+ return Success (None);
128
+ } else {
129
+ return Failure ("Invalid encrypt type : '" + types.value + "'.");
130
+ }
131
+ }
132
+
133
+ method Encrypt (inFile : string , outFile : string , lang : string , version : string ) returns (output : Result< bool , string > )
134
+ {
135
+ var configBv :- expect FileIO. ReadBytesFromFile (inFile);
136
+ var configBytes := BvToBytes (configBv);
137
+ var json :- expect API. Deserialize (configBytes);
138
+
139
+ :- Need (json.Object?, "Encrypt file must contain a JSON object.");
140
+ var keys : Option< string > := None;
141
+ var manifest : Option< seq < (string , JSON)>> := None;
142
+ var tests : Option< seq < (string , JSON)>> := None;
143
+
144
+ for i := 0 to |json. obj| {
145
+ var obj := json. obj[i];
146
+ match obj. 0 {
147
+ case "keys" =>
148
+ :- Need (obj.1.String?, "Value of 'keys' must be a string.");
149
+ keys := Some (obj.1.str);
150
+ case "manifest" =>
151
+ :- Need (obj.1.Object?, "Value of 'manifest' must be an object.");
152
+ manifest := Some (obj.1.obj);
153
+ case "tests" =>
154
+ :- Need (obj.1.Object?, "Value of 'tests' must be an object.");
155
+ tests := Some (obj.1.obj);
156
+ case _ => return Failure ("Unknown top level encrypt tag : " + obj.0);
157
+ }
158
+ }
159
+ :- Need (keys.Some?, "Encrypt manifest requires a 'keys' member.");
160
+ :- Need (manifest.Some?, "Encrypt manifest requires a 'manifest' member.");
161
+ :- Need (tests.Some?, "Encrypt manifest requires a 'tests' member.");
162
+
163
+ for i := 0 to |manifest. value| {
164
+ var obj := manifest. value[i];
165
+ match obj. 0 {
166
+ case "type " =>
167
+ :- Need (obj.1.String?, "Value of 'type' must be a string.");
168
+ :- Need (obj.1.str == ENCRYPT_TYPE, "Value of 'type' must be '" + ENCRYPT_TYPE + "'.");
169
+ case "version" =>
170
+ :- Need (obj.1.String?, "Value of 'version' must be a string.");
171
+ :- Need (obj.1.str == "1", "Value of 'version' must be '1'");
172
+ case _ => return Failure ("Unknown manifest member : " + obj.0);
173
+ }
174
+ }
175
+
176
+ var result : seq < (string , JSON)> :=
177
+ [Manifest (), Client (lang, version), ("keys", String ("file://keys.json"))];
178
+
179
+ var test : seq < (string , JSON)> := [];
180
+
181
+ for i := 0 to |tests. value| {
182
+ var obj := tests. value[i];
183
+ :- Need (obj.1.Object?, "Value of test '" + obj.0 + "' must be an Object.");
184
+ var newTest :- OneTest (obj.0, obj.1);
185
+ if newTest. Some? {
186
+ test := test + [newTest. value];
187
+ }
188
+ }
189
+
190
+ var final := Object (result + [("tests", Object(test))]);
191
+ var jsonBytes :- expect API. Serialize (final);
192
+ var jsonBv := BytesBv (jsonBytes);
193
+ var x :- expect FileIO. WriteBytesToFile (outFile, jsonBv);
194
+ return Success (true);
195
+ }
196
+
197
+ }
0 commit comments