@@ -109,6 +109,7 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
109
109
110
110
// Fail unless the field exists, and is a binary terminal
111
111
function method {:opaque} GetBinary (data : AuthList , path : Path ): (result: Result< StructuredDataTerminal, Error> )
112
+ ensures result. Success? ==> exists x :: x in data && x. key == path
112
113
{
113
114
var data := FindAuth (data, path);
114
115
@@ -250,6 +251,7 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
250
251
ensures result. origKey == data. key
251
252
ensures result. data == data. data
252
253
ensures result. action == data. action
254
+ ensures SameAuth (data, result)
253
255
{
254
256
CanonAuthItem (Paths.CanonPath(tableName, data.key), data. key, data. data, data. action)
255
257
}
@@ -259,7 +261,7 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
259
261
: (ret : Result< CanonCryptoList, Error> )
260
262
ensures ret. Success? ==>
261
263
&& (forall k < - data :: Paths. ValidPath (k.key))
262
- && (forall k < - data :: (exists x :: x in ret. value && x. origKey == k. key))
264
+ && (forall k < - data :: (exists x :: x in ret. value && x. origKey == k. key && k . data == x . data ))
263
265
&& |data| == |ret. value|
264
266
&& (forall k < - ret. value :: Paths. ValidPath (k.origKey))
265
267
&& (forall k < - ret. value :: k. key == Paths. CanonPath (tableName, k.origKey))
@@ -269,7 +271,7 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
269
271
270
272
assert |canonList| == |data|;
271
273
assert forall i | 0 <= i < |data| :: canonList[i] == MakeCanon (tableName, data[i]);
272
- assert forall k < - data :: (exists x :: x in canonList && k. key == x. origKey);
274
+ assert forall k < - data :: (exists x :: x in canonList && k. key == x. origKey && k . data == x . data );
273
275
assert forall k < - canonList :: Paths. ValidPath (k.origKey);
274
276
assert forall k < - canonList :: k. key == Paths. CanonPath (tableName, k.origKey);
275
277
@@ -304,6 +306,28 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
304
306
&& x. data == y. data
305
307
}
306
308
309
+ predicate method SameAuth (x : AuthItem , y : CanonAuthItem )
310
+ {
311
+ && x. key == y. origKey
312
+ && x. data == y. data
313
+ }
314
+
315
+ predicate method SameAuthCrypto (x : AuthItem , y : CanonCryptoItem )
316
+ {
317
+ && x. key == y. origKey
318
+ && x. data == y. data
319
+ }
320
+
321
+ lemma SameSame (x : AuthItem , y : CanonAuthItem , z : CanonCryptoItem )
322
+ requires SameAuth (x, y)
323
+ requires Same (y, z)
324
+ ensures SameAuthCrypto (x, z)
325
+ {}
326
+
327
+ lemma SameSame2 (x : AuthItem , z : CanonCryptoItem )
328
+ ensures exists y :: SameAuth (x, y) && Same (y, z) ==> SameAuthCrypto (x, z)
329
+ {}
330
+
307
331
function method MakeCryptoItem (x : CanonAuthItem , action : CryptoAction ) : (ret : CanonCryptoItem)
308
332
ensures Same (x, ret)
309
333
{
@@ -339,7 +363,7 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
339
363
: (ret : Result< CanonCryptoList, Error> )
340
364
ensures ret. Success? ==>
341
365
&& (forall k < - data :: Paths. ValidPath (k.key))
342
- && (forall k < - data :: (exists x :: x in ret. value && x. origKey == k . key ))
366
+ && (forall k < - data :: (exists x :: x in ret. value && k . key == x. origKey && k . data == x . data ))
343
367
&& |data| == |ret. value|
344
368
&& (forall k < - ret. value :: Paths. ValidPath (k.origKey))
345
369
&& (forall k < - ret. value :: k. key == Paths. CanonPath (tableName, k.origKey))
@@ -349,7 +373,7 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
349
373
350
374
assert |canonList| == |data|;
351
375
assert forall i | 0 <= i < |data| :: canonList[i] == MakeCanonAuth (tableName, data[i]);
352
- assert forall k < - data :: (exists x :: x in canonList && k. key == x. origKey);
376
+ assert forall k < - data :: (exists x :: x in canonList && k. key == x. origKey && k . data == x . data );
353
377
assert forall k < - canonList :: Paths. ValidPath (k.origKey);
354
378
assert forall k < - canonList :: k. key == Paths. CanonPath (tableName, k.origKey);
355
379
@@ -360,7 +384,7 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
360
384
assert forall k < - canonList :: k in canonSorted;
361
385
assert forall k < - canonSorted :: k in multiset (canonSorted);
362
386
assert forall k < - canonSorted :: k in canonList;
363
- assert forall k < - data :: (exists x :: x in canonSorted && k. key == x. origKey);
387
+ assert forall k < - data :: (exists x :: x in canonSorted && k. key == x. origKey && k . data == x . data );
364
388
assert forall k < - canonSorted :: Paths. ValidPath (k.origKey);
365
389
assert forall k < - canonSorted :: k. key == Paths. CanonPath (tableName, k.origKey);
366
390
@@ -371,7 +395,7 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
371
395
var canonResolved :- ResolveLegend (canonSorted, legend, canonSorted, acc);
372
396
373
397
assert |canonResolved| == |data|;
374
- assert forall k < - data :: (exists x :: x in canonResolved && k. key == x. origKey);
398
+ assert forall k < - data :: (exists x :: x in canonResolved && k. key == x. origKey && k . data == x . data );
375
399
assert forall k < - canonResolved :: Paths. ValidPath (k.origKey);
376
400
assert forall k < - canonResolved :: k. key == Paths. CanonPath (tableName, k.origKey);
377
401
@@ -400,7 +424,8 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
400
424
Find (haystack[1..], needle)
401
425
}
402
426
403
- function method {:opaque} FindAuth (haystack : AuthList , needle : Path ) : Option< AuthItem>
427
+ function method {:opaque} FindAuth (haystack : AuthList , needle : Path ) : (result : Option< AuthItem> )
428
+ ensures result. Some? ==> exists x :: x in haystack && x. key == needle
404
429
{
405
430
if |haystack| == 0 then
406
431
None
@@ -964,9 +989,6 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
964
989
}
965
990
966
991
method {:vcs_split_on_every_assert} DecryptPathStructure (config: InternalConfig , input: DecryptPathStructureInput )
967
- // = specification/structured-encryption/decrypt-path-structure.md#construct-decrypted-structured-data
968
- // = type=implication
969
- // # This operation MUST output a [Structured Data](#structured-data) with the following specifics:
970
992
returns (output: Result< DecryptPathStructureOutput, Error> )
971
993
972
994
ensures output. Success? ==>
@@ -978,6 +1000,11 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
978
1000
// # this operation MUST access the [Terminal Data](./structures.md#terminal-data)
979
1001
// # at the "aws_dbe_head"
980
1002
1003
+ // = specification/structured-encryption/decrypt-path-structure.md#auth-list
1004
+ // = type=implication
1005
+ // # This Auth List MUST contain data located at the [header index](./header.md#header-index)
1006
+ // # and the [footer index](./footer.md#footer-index).
1007
+
981
1008
// = specification/structured-encryption/decrypt-path-structure.md#parse-the-header
982
1009
// = type=implication
983
1010
// # The [Terminal Type Id](./structures.md#terminal-type-id) on this Terminal Data MUST be `0xFFFF`.
@@ -994,6 +1021,10 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
994
1021
&& GetBinary (encRecord, FooterPath). Success?
995
1022
&& var footerSerialized := GetBinary (encRecord, FooterPath). value;
996
1023
1024
+ // = specification/structured-encryption/decrypt-path-structure.md#auth-list
1025
+ // = type=implication
1026
+ // # The Auth List MUST include at least one [SIGN Authenticate Action](./structures.md#sign);
1027
+ // # otherwise, this operation MUST yield an error.
997
1028
&& (exists x :: (x in encRecord && x. action == SIGN))
998
1029
999
1030
// = specification/structured-encryption/decrypt-path-structure.md#parse-the-header
@@ -1002,30 +1033,64 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
1002
1033
// # according to the [header format](./header.md).
1003
1034
&& Header. PartialDeserialize (headerSerialized.value). Success?
1004
1035
1005
- // //= specification/structured-encryption/decrypt-path-structure.md#construct-decrypted-structured-data
1006
- // //= type=implication
1007
- // //# - [Terminal Data](./structures.md#terminal-data) MUST NOT exist at the "aws_dbe_head"
1008
- // //# or "aws_dbe_foot".
1036
+ // = specification/structured-encryption/decrypt-path-structure.md#construct-decrypted-structured-data
1037
+ // = type=implication
1038
+ // # - An entry MUST NOT exist with the key "aws_dbe_head" or "aws_dbe_foot".
1009
1039
&& (! exists x :: x in output. value. plaintextStructure && x. key == HeaderPath)
1010
1040
&& (! exists x :: x in output. value. plaintextStructure && x. key == FooterPath)
1041
+
1042
+ // = specification/structured-encryption/decrypt-path-structure.md#construct-decrypted-structured-data
1043
+ // = type=implication
1044
+ // # - For every entry in the [input Auth List](#auth-list), other than the header and footer,
1045
+ // # an entry MUST exist with the same key in the output Crypto List.
1011
1046
&& (forall k < - input. encryptedStructure | k. key ! in HeaderPaths ::
1012
1047
(exists x :: x in output. value. plaintextStructure && x. key == k. key))
1048
+
1049
+ // = specification/structured-encryption/decrypt-path-structure.md#construct-decrypted-structured-data
1050
+ // = type=implication
1051
+ // # - The output Crypto List MUST NOT have any additional entries.
1052
+ && |output. value. plaintextStructure| == |input. encryptedStructure| - 2
1053
+
1054
+ // = specification/structured-encryption/decrypt-path-structure.md#construct-decrypted-structured-data
1055
+ // = type=implication
1056
+ // # If the action is [ENCRYPT_AND_SIGN](./structures.md#encryptandsign)
1057
+ // # this Terminal Data MUST have [Terminal Type ID](./structures.md#terminal-type-id)
1058
+ // # equal to the first two bytes of the input Terminal Data's value,
1059
+ // # and a value equal to the [decryption](#terminal-data-decryption) of the input Terminal Data's value.
1060
+
1061
+ // = specification/structured-encryption/decrypt-path-structure.md#construct-decrypted-structured-data
1062
+ // = type=implication
1063
+ // # Otherwise, this Terminal Data MUST have [Terminal Type ID](./structures.md#terminal-type-id) and
1064
+ // # [Terminal Value](./structures.md#terminal-value) equal to the input Terminal Data.
1065
+ && (forall k < - input. encryptedStructure | k. key ! in HeaderPaths ::
1066
+ (exists x ::
1067
+ && x in output. value. plaintextStructure
1068
+ && x. key == k. key
1069
+ && (
1070
+ || x. action == ENCRYPT_AND_SIGN
1071
+ || x. data == k. data
1072
+ )))
1073
+
1013
1074
{
1014
- var encRecord : AuthList := input. encryptedStructure;
1075
+ : - Need (exists x :: (x in input.encryptedStructure && x.action == SIGN), E ("At least one Authenticate Action must be SIGN")) ;
1015
1076
1016
- :- Need (exists x :: (x in encRecord && x.action == SIGN), E ("At least one Authenticate Action must be SIGN"));
1077
+ var headerSerialized :- GetBinary (input.encryptedStructure, HeaderPath);
1078
+ var footerSerialized :- GetBinary (input.encryptedStructure, FooterPath);
1079
+ assert exists x :: x in input. encryptedStructure && x. key == HeaderPath;
1080
+ assert exists x :: x in input. encryptedStructure && x. key == FooterPath;
1017
1081
1018
- var headerSerialized :- GetBinary (encRecord, HeaderPath);
1019
- var footerSerialized :- GetBinary (encRecord, FooterPath);
1020
1082
// = specification/structured-encryption/decrypt-path-structure.md#parse-the-header
1021
1083
// # This operation MUST deserialize the header bytes
1022
1084
// # according to the [header format](./header.md).
1023
1085
var head :- Header. PartialDeserialize (headerSerialized.value);
1024
1086
var headerAlgorithmSuite :- head. GetAlgorithmSuite (config.materialProviders);
1025
1087
1026
1088
:- Need (ValidString(input.tableName), E ("Bad Table Name"));
1027
- var canonData :- CanonizeForDecrypt (input.tableName, encRecord, head.legend);
1028
- assert forall k < - input. encryptedStructure :: (exists x :: x in canonData && x. origKey == k. key);
1089
+ var canonData :- CanonizeForDecrypt (input.tableName, input.encryptedStructure, head.legend);
1090
+ assert forall k < - input. encryptedStructure :: (exists x :: x in canonData && k. key == x. origKey && k. data == x. data);
1091
+ assert |canonData| == |input. encryptedStructure|;
1092
+ assert exists x :: x in canonData && x. origKey == HeaderPath;
1093
+ assert exists x :: x in canonData && x. origKey == FooterPath;
1029
1094
1030
1095
assume {:axiom} input. cmm. Modifies !! {config. materialProviders. History};
1031
1096
@@ -1126,13 +1191,6 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
1126
1191
// # The header field value MUST be [verified](header.md#commitment-verification)
1127
1192
var ok :- head. verifyCommitment (config.primitives, postCMMAlg, commitKey, headerSerialized.value);
1128
1193
1129
- // = specification/structured-encryption/decrypt-path-structure.md#calculate-signed-and-encrypted-field-lists
1130
- // = type=implication
1131
- // # Decryption MUST fail if the length of this list does not equal the
1132
- // # length of the header's [Encrypt Legend](header.md.#encrypt-legend).
1133
- // this assert can be an implication, because it is explicitly ensuring an intermediate state.
1134
- // assert |head.legend| == |canonData.signedFields_c|;
1135
-
1136
1194
// = specification/structured-encryption/decrypt-path-structure.md#verify-signatures
1137
1195
// # This operation MUST deserialize the bytes in [Terminal Value](./structures.md#terminal-value)
1138
1196
// # according to the [footer format](./footer.md).
@@ -1145,27 +1203,44 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
1145
1203
// # Decryption MUST fail immediately if verification fails.
1146
1204
var _ :- footer. validate (config.primitives, mat, head.dataKeys, canonData, headerSerialized.value);
1147
1205
var decryptedItems : CanonCryptoList :- Crypt. Decrypt (config.primitives, postCMMAlg, key, head, canonData);
1148
-
1149
- // = specification/structured-encryption/decrypt-path-structure.md#construct-decrypted-structured-data
1150
- // # - For every [input Terminal Data](./structures.md#terminal-data) in the [input Structured Data](#structured-data)
1151
- // # (aside from the header and footer),
1152
- // # a Terminal Data MUST exist with the same [canonical path](./header.md#canonical-path) in the output Structured Data.
1153
- // at this point both result and encRecord have header and footer
1206
+ assert |decryptedItems| == |input. encryptedStructure|;
1154
1207
assert forall k < - input. encryptedStructure :: (exists x :: x in decryptedItems && x. origKey == k. key);
1208
+ assert exists x :: x in decryptedItems && x. origKey == HeaderPath;
1209
+ assert exists x :: x in decryptedItems && x. origKey == FooterPath;
1155
1210
1156
- // = specification/structured-encryption/decrypt-path-structure.md#construct-decrypted-structured-data
1157
- // # - for every [Terminal Data](./structures.md#terminal-data) in the output Structured Data,
1158
- // # a Terminal Data MUST exist with the same [canonical path](./header.md#canonical-path) in the [input Structured Data](#structured-data).
1211
+ assert (forall k < - input. encryptedStructure ::
1212
+ (exists x ::
1213
+ && x in decryptedItems
1214
+ && x. origKey == k. key
1215
+ && Crypt. Updated2 (k, x, Crypt.DoDecrypt)
1216
+ ));
1159
1217
1160
1218
var largeResult := UnCanon (decryptedItems);
1219
+ assert |largeResult| == |input. encryptedStructure|;
1161
1220
assert forall k < - input. encryptedStructure :: (exists x :: x in largeResult && x. key == k. key);
1221
+ assert (forall k < - input. encryptedStructure ::
1222
+ (exists x ::
1223
+ && x in largeResult
1224
+ && x. key == k. key
1225
+ && Crypt. Updated3 (k, x, Crypt.DoDecrypt)
1226
+ ));
1162
1227
1228
+ assert exists x :: x in largeResult && x. key == HeaderPath;
1229
+ assert exists x :: x in largeResult && x. key == FooterPath;
1163
1230
var smallResult := Seq. Filter ((x : CryptoItem ) => x. key ! in HeaderPaths, largeResult);
1164
1231
reveal Seq. Filter ();
1165
1232
assert ! exists x :: x in smallResult && x. key == HeaderPath;
1166
1233
assert ! exists x :: x in smallResult && x. key == FooterPath;
1167
- assume {:axiom} forall k < - input. encryptedStructure | k. key ! in HeaderPaths ::
1168
- (exists x :: x in smallResult && x. key == k. key);
1234
+ assume {:axiom} forall k < - largeResult | k. key ! in HeaderPaths :: (exists x :: x in smallResult && x == k);
1235
+ :- Need (|smallResult| == |input.encryptedStructure| - 2, E("Internal Error."));
1236
+ assert |smallResult| == |input. encryptedStructure| - 2;
1237
+
1238
+ assert (forall k < - input. encryptedStructure | k. key ! in HeaderPaths ::
1239
+ (exists x ::
1240
+ && x in smallResult
1241
+ && x. key == k. key
1242
+ && Crypt. Updated3 (k, x, Crypt.DoDecrypt)
1243
+ ));
1169
1244
1170
1245
// = specification/structured-encryption/decrypt-path-structure.md#construct-decrypted-structured-data
1171
1246
// = type=implication
@@ -1183,8 +1258,6 @@ module AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations refines Abst
1183
1258
parsedHeader := parsedHeader
1184
1259
);
1185
1260
1186
- // assert forall k <- decryptOutput.plaintextStructure :: k in encRecord;
1187
-
1188
1261
output := Success (decryptOutput);
1189
1262
}
1190
1263
0 commit comments