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