Skip to content

Commit fb379d4

Browse files
Merge branch 'develop' of github.com:awslabs/aws-encryption-sdk-dafny into examples
2 parents 1928216 + 5ab9ea1 commit fb379d4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1766
-326
lines changed

.pre-commit-config.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
repos:
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: v2.2.3 # Use the ref you want to point at
4+
hooks:
5+
- id: trailing-whitespace

CODE_OF_CONDUCT.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
## Code of Conduct
2-
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
3-
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
2+
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
3+
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
44
[email protected] with any additional questions or comments.

CONTRIBUTING.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
# Contributing Guidelines
22

3-
Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
3+
Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
44
documentation, we greatly value feedback and contributions from our community.
55

6-
Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
6+
Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
77
information to effectively respond to your bug report or contribution.
88

99

1010
## Reporting Bugs/Feature Requests
1111

1212
We welcome you to use the GitHub issue tracker to report bugs or suggest features.
1313

14-
When filing an issue, please check [existing open](https://github.com/awslabs/aws-encryption-sdk-dafny/issues), or [recently closed](https://github.com/awslabs/aws-encryption-sdk-dafny/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already
14+
When filing an issue, please check [existing open](https://github.com/awslabs/aws-encryption-sdk-dafny/issues), or [recently closed](https://github.com/awslabs/aws-encryption-sdk-dafny/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already
1515
reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
1616

1717
* A reproducible test case or series of steps
@@ -41,17 +41,17 @@ To send us a pull request, please:
4141
the resulting commit title and message must adhere to conventional commits.
4242
6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
4343

44-
GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
44+
GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
4545
[creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
4646

4747

4848
## Finding contributions to work on
49-
Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/awslabs/aws-encryption-sdk-dafny/labels/help%20wanted) issues is a great place to start.
49+
Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/awslabs/aws-encryption-sdk-dafny/labels/help%20wanted) issues is a great place to start.
5050

5151

5252
## Code of Conduct
53-
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
54-
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
53+
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
54+
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
5555
[email protected] with any additional questions or comments.
5656

5757

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
FROM ubuntu:18.04
2-
2+
33
USER root
44

55
ENV DEBIAN_FRONTEND=noninteractive

NOTICE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
AWS Encryption SDK Dafny
2-
Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.

README.md

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
1-
# AWS Encryption SDK Dafny
1+
# AWS Encryption SDK Written in Dafny
22

33
![Build Status - master branch](https://codebuild.us-west-2.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoiVmIzeGwwQmY5bXdMQXg2aVBneWtDc3FHSWRHTjYrNnVUem9nNXJFUmY2Rk1yRnJvSjJvK3JCL2RScFRjSVF1UjA1elR3L0xpTVpiNmRZS0RyWjJpTnBFPSIsIml2UGFyYW1ldGVyU3BlYyI6InBBQm1tT1BPNjB3RU9XUS8iLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=master)
44

5-
AWS Encryption SDK for Dafny
5+
AWS Encryption SDK Written in Dafny for .NET
66

7-
## Building
7+
[Security issue notifications](./CONTRIBUTING.md#security-issue-notifications)
8+
9+
## Using the AWS Encryption SDK for .NET
10+
The AWS Encryption SDK is available on [NuGet](https://www.nuget.org/) and can referenced from an existing `.csproj` through typical ways.
11+
12+
```
13+
<!-- TODO: Update with actual NuGet package name, the name below is just an example -->
14+
<PackageReference Include="AWS.EncryptionSDK" />
15+
```
16+
17+
The Encryption SDK source has a target framework of [netstandard2.0](https://docs.microsoft.com/en-us/dotnet/standard/net-standard).
18+
19+
## Building the AWS Encryption SDK Written in Dafny
820

921
To build, the AWS Encryption SDK requires the most up to date version of [dafny](https://github.com/dafny-lang/dafny) on your PATH.
1022

11-
Building and verifying also requires [dotnet 3.0](https://dotnet.microsoft.com/download/dotnet-core/3.0).
23+
The Encryption SDK source has a target framework of [netstandard2.0](https://docs.microsoft.com/en-us/dotnet/standard/net-standard).
24+
Tests and test vectors have a target framework of [netcoreapp3.0](https://docs.microsoft.com/en-us/dotnet/standard/frameworks), which is required for properly building and running tests.
25+
Therefore, building and verifying requires [dotnet 3.0](https://dotnet.microsoft.com/download/dotnet-core/3.0).
1226

1327
To build all source files into one dll:
1428

@@ -23,7 +37,7 @@ To run the dafny verifier across all files:
2337
dotnet build -t:VerifyDafny test
2438
```
2539

26-
## Testing
40+
## Testing the AWS Encryption SDK Written in Dafny
2741

2842
Run the test suite with:
2943

@@ -43,6 +57,8 @@ Run the test vector suite after [set up](testVector/README.md) with:
4357
dotnet test testVectors
4458
```
4559

60+
Please note that tests and test vectors require internet access and valid AWS credentials, since calls to KMS are made as part of the test workflow.
61+
4662
## License
4763

4864
This library is licensed under the Apache 2.0 License.

buildspec.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ phases:
1010
- mozroots --import --sync
1111
# Get Boogie
1212
# Multiple Boogie commits have broken our build or test cases. Locking down Boogie.
13-
- git clone --branch v2.4.2 https://github.com/boogie-org/boogie.git
13+
- git clone --branch v2.4.21 https://github.com/boogie-org/boogie.git
1414
- nuget restore boogie/Source/Boogie.sln
1515
- msbuild boogie/Source/Boogie.sln
1616
# Get Dafny
1717
- git clone https://github.com/microsoft/dafny.git
1818
# Although Dafny does have releases, we often need a newer hash than the latest release, while still needing the
1919
# the security of reproducible builds.
2020
- cd dafny
21-
- git reset --hard 5ca6ef8347c9675b6824e987967925b1208ca47c
21+
- git reset --hard df707bc07e3c39390286dfd0c1576d0a3f556f8b
2222
- cd ..
2323
- nuget restore dafny/Source/Dafny.sln
2424
- msbuild dafny/Source/Dafny.sln

lib/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# ignore all files in this dir...
22
*
3-
3+
44
# ... except for this one.
55
!.gitignore

src/AWSEncryptionSDK.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
<DafnySource Include="Crypto/Random.dfy" />
2424
<DafnySource Include="Crypto/RSAEncryption.dfy" />
2525
<DafnySource Include="Crypto/Signature.dfy" />
26+
<DafnySource Include="KMS/AmazonKeyManagementService.dfy" />
2627
<DafnySource Include="KMS/KMSUtils.dfy" />
2728
<DafnySource Include="SDK/AlgorithmSuite.dfy" />
2829
<DafnySource Include="SDK/Client.dfy" />
30+
<DafnySource Include="SDK/CMM/CachingCMM.dfy" />
2931
<DafnySource Include="SDK/CMM/DefaultCMM.dfy" />
3032
<DafnySource Include="SDK/CMM/Defs.dfy" />
3133
<DafnySource Include="SDK/Deserialize.dfy" />
@@ -45,7 +47,7 @@
4547
<DafnySource Include="Util/UTF8.dfy" />
4648
<DafnySource Include="Util/Sets.dfy" />
4749
</ItemGroup>
48-
50+
4951
<ItemGroup>
5052
<PackageReference Include="dafny.msbuild" Version="1.0.0" />
5153
<PackageReference Include="AWSSDK.Core" Version="3.3.104.1" />

src/Crypto/AESEncryption.dfy

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ module {:extern "AESEncryption"} AESEncryption {
88
import opened UInt = StandardLibrary.UInt
99

1010
export
11-
provides AESDecrypt, AESEncrypt, EncryptionSuites, StandardLibrary, UInt, PlaintextDecryptedWithAAD, EncryptionOutputEncryptedWithAAD
11+
provides AESDecrypt, AESEncrypt, AESDecryptExtern, AESEncryptExtern, EncryptionSuites, StandardLibrary,
12+
UInt, PlaintextDecryptedWithAAD, EncryptionOutputEncryptedWithAAD, CiphertextGeneratedWithPlaintext
1213
reveals EncryptionOutput
1314

1415
datatype EncryptionOutput = EncryptionOutput(cipherText: seq<uint8>, authTag: seq<uint8>)
@@ -18,6 +19,7 @@ module {:extern "AESEncryption"} AESEncryption {
1819
// in order to ensure that the AAD used is as expected.
1920
predicate {:axiom} PlaintextDecryptedWithAAD(plaintext: seq<uint8>, aad: seq<uint8>)
2021
predicate {:axiom} EncryptionOutputEncryptedWithAAD(ciphertext: EncryptionOutput, aad: seq<uint8>)
22+
predicate {:axiom} CiphertextGeneratedWithPlaintext (ciphertext: seq<uint8>, plaintext: seq<uint8>)
2123

2224
function method EncryptionOutputFromByteSeq(s: seq<uint8>, encAlg: EncryptionSuites.EncryptionSuite): (encArt: EncryptionOutput)
2325
requires encAlg.Valid()
@@ -28,7 +30,17 @@ module {:extern "AESEncryption"} AESEncryption {
2830
EncryptionOutput(s[.. |s| - encAlg.tagLen as int], s[|s| - encAlg.tagLen as int ..])
2931
}
3032

31-
method {:extern "AESEncryption.AES_GCM", "AESEncrypt"} AESEncrypt(encAlg: EncryptionSuites.EncryptionSuite, iv: seq<uint8>, key: seq<uint8>, msg: seq<uint8>, aad: seq<uint8>)
33+
method {:extern "AESEncryption.AES_GCM", "AESEncryptExtern"} AESEncryptExtern(encAlg: EncryptionSuites.EncryptionSuite, iv: seq<uint8>, key: seq<uint8>, msg: seq<uint8>, aad: seq<uint8>)
34+
returns (res : Result<EncryptionOutput>)
35+
requires encAlg.Valid()
36+
requires encAlg.alg.AES?
37+
requires encAlg.alg.mode.GCM?
38+
requires |iv| == encAlg.ivLen as int
39+
requires |key| == encAlg.keyLen as int
40+
ensures res.Success? ==> EncryptionOutputEncryptedWithAAD(res.value, aad)
41+
ensures res.Success? ==> CiphertextGeneratedWithPlaintext(res.value.cipherText, msg)
42+
43+
method AESEncrypt(encAlg: EncryptionSuites.EncryptionSuite, iv: seq<uint8>, key: seq<uint8>, msg: seq<uint8>, aad: seq<uint8>)
3244
returns (res : Result<EncryptionOutput>)
3345
requires encAlg.Valid()
3446
requires encAlg.alg.AES?
@@ -38,14 +50,44 @@ module {:extern "AESEncryption"} AESEncryption {
3850
ensures res.Success? ==>
3951
|res.value.cipherText| == |msg| && |res.value.authTag| == encAlg.tagLen as int
4052
ensures res.Success? ==> EncryptionOutputEncryptedWithAAD(res.value, aad)
53+
ensures res.Success? ==> CiphertextGeneratedWithPlaintext(res.value.cipherText, msg)
54+
{
55+
res := AESEncryptExtern(encAlg, iv, key, msg, aad);
56+
if (res.Success? && |res.value.cipherText| != |msg|){
57+
res := Failure("AESEncrypt did not return cipherText of expected length");
58+
}
59+
if (res.Success? && |res.value.authTag| != encAlg.tagLen as int){
60+
res := Failure("AESEncryption did not return valid tag");
61+
}
62+
}
63+
64+
method {:extern "AESEncryption.AES_GCM", "AESDecryptExtern"} AESDecryptExtern(encAlg: EncryptionSuites.EncryptionSuite, key: seq<uint8>, cipherTxt: seq<uint8>, authTag: seq<uint8>, iv: seq<uint8>, aad: seq<uint8>)
65+
returns (res: Result<seq<uint8>>)
66+
requires encAlg.Valid()
67+
requires encAlg.alg.AES?
68+
requires encAlg.alg.mode.GCM?
69+
requires |key| == encAlg.keyLen as int
70+
requires |iv| == encAlg.ivLen as int
71+
requires |authTag| == encAlg.tagLen as int
72+
ensures res.Success? ==> PlaintextDecryptedWithAAD(res.value, aad)
73+
ensures res.Success? ==> CiphertextGeneratedWithPlaintext(cipherTxt, res.value)
4174

42-
method {:extern "AESEncryption.AES_GCM", "AESDecrypt"} AESDecrypt(encAlg: EncryptionSuites.EncryptionSuite, key: seq<uint8>, cipherTxt: seq<uint8>, authTag: seq<uint8>, iv: seq<uint8>, aad: seq<uint8>)
75+
method AESDecrypt(encAlg: EncryptionSuites.EncryptionSuite, key: seq<uint8>, cipherTxt: seq<uint8>, authTag: seq<uint8>, iv: seq<uint8>, aad: seq<uint8>)
4376
returns (res: Result<seq<uint8>>)
4477
requires encAlg.Valid()
4578
requires encAlg.alg.AES?
4679
requires encAlg.alg.mode.GCM?
4780
requires |key| == encAlg.keyLen as int
4881
requires |iv| == encAlg.ivLen as int
4982
requires |authTag| == encAlg.tagLen as int
83+
ensures res.Success? ==> |res.value| == |cipherTxt|
5084
ensures res.Success? ==> PlaintextDecryptedWithAAD(res.value, aad)
85+
ensures res.Success? ==> CiphertextGeneratedWithPlaintext(cipherTxt, res.value)
86+
{
87+
res := AESDecryptExtern(encAlg, key, cipherTxt, authTag, iv, aad);
88+
if (res.Success? && |cipherTxt| != |res.value|){
89+
res := Failure("AESDecrypt did not return plaintext of expected length");
90+
}
91+
}
92+
5193
}

src/Crypto/Digest.dfy

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,10 @@ module {:extern "Digest"} Digest {
77

88
datatype Algorithm = SHA_512
99

10+
function method Length(alg: Algorithm): nat {
11+
match alg
12+
case SHA_512 => 64
13+
}
14+
1015
method {:extern "Digest.SHA", "Digest"} Digest(alg: Algorithm, msg: seq<uint8>) returns (digest: Result<seq<uint8>>)
1116
}

src/Crypto/HKDF/HKDF.dfy

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,23 @@ module HKDF {
3737
}
3838

3939
// T is relational since the external hashMethod hmac.GetKey() ensures that the input and output of the hash method are in the relation hmac.HashSignature
40-
// T depends on Ti and Ti depends on hmac.HashSignature
40+
// T depends on Ti and Ti depends on hmac.HashSignature
4141
predicate T(hmac: HMac, info: seq<uint8>, n: nat, res: seq<uint8>)
42-
requires 0 <= n < 256
42+
requires 0 <= n < 256
4343
decreases n
44-
{
45-
if n == 0 then
44+
{
45+
if n == 0 then
4646
[] == res
47-
else
48-
exists prev1, prev2 :: T(hmac, info, n-1, prev1) && Ti(hmac, info, n, prev2) && prev1 + prev2 == res
47+
else
48+
var nMinusOne := n - 1;
49+
exists prev1, prev2 :: T(hmac, info, nMinusOne, prev1) && Ti(hmac, info, n, prev2) && prev1 + prev2 == res
4950
}
5051

5152
predicate Ti(hmac: HMac, info: seq<uint8>, n: nat, res: seq<uint8>)
5253
requires 0 <= n < 256
5354
decreases n, 1
5455
{
55-
if n == 0 then
56+
if n == 0 then
5657
res == []
5758
else
5859
exists prev :: PreTi(hmac, info, n, prev) && hmac.HashSignature(prev, res)
@@ -63,10 +64,11 @@ module HKDF {
6364
requires 1 <= n < 256
6465
decreases n, 0
6566
{
66-
exists prev | Ti(hmac, info, n - 1, prev) :: res == prev + info + [(n as uint8)]
67+
var nMinusOne := n - 1;
68+
exists prev | Ti(hmac, info, nMinusOne, prev) :: res == prev + info + [(n as uint8)]
6769
}
6870

69-
method Expand(hmac: HMac, prk: seq<uint8>, info: seq<uint8>, expectedLength: int, digest: Digests, ghost salt: seq<uint8>) returns (okm: seq<uint8>)
71+
method Expand(hmac: HMac, prk: seq<uint8>, info: seq<uint8>, expectedLength: int, digest: Digests, ghost salt: seq<uint8>) returns (okm: seq<uint8>, ghost okmUnabridged: seq<uint8>)
7072
requires hmac.GetDigest() == digest
7173
requires 1 <= expectedLength <= 255 * GetHashLength(hmac.GetDigest())
7274
requires |salt| != 0
@@ -76,16 +78,15 @@ module HKDF {
7678
modifies hmac
7779
ensures |okm| == expectedLength
7880
ensures hmac.GetKey() == prk
79-
ensures var n := (GetHashLength(hmac.GetDigest()) + expectedLength - 1) / GetHashLength(hmac.GetDigest());
80-
0 <= n < 256 &&
81-
exists res ::
82-
T(hmac, info, n, res)
83-
&& (|res| <= expectedLength ==> okm == res)
84-
&& (expectedLength < |res| ==> okm == res[..expectedLength])
81+
ensures var n := (GetHashLength(digest) + expectedLength - 1) / GetHashLength(digest);
82+
&& T(hmac, info, n, okmUnabridged)
83+
&& (|okmUnabridged| <= expectedLength ==> okm == okmUnabridged)
84+
&& (expectedLength < |okmUnabridged| ==> okm == okmUnabridged[..expectedLength])
8585
{
8686
// N = ceil(L / Hash Length)
8787
var hashLength := GetHashLength(digest);
8888
var n := (hashLength + expectedLength - 1) / hashLength;
89+
assert 0 <= n < 256;
8990

9091
// T(0) = empty string (zero length)
9192
hmac.Init(prk);
@@ -111,13 +112,13 @@ module HKDF {
111112
hmac.Update(t_prev);
112113
hmac.Update(info);
113114
hmac.Update([i as uint8]);
114-
assert hmac.GetInputSoFar() == t_prev + info + [i as uint8];
115+
assert hmac.GetInputSoFar() == t_prev + info + [i as uint8];
115116

116117
// Add additional verification for T(n): github.com/awslabs/aws-encryption-sdk-dafny/issues/177
117-
t_prev := hmac.GetResult();
118+
t_prev := hmac.GetResult();
118119
// t_n == T(i - 1)
119-
assert T(hmac, info, i - 1, t_n);
120-
assert Ti(hmac, info, i, t_prev) ;
120+
assert T(hmac, info, i - 1, t_n);
121+
assert Ti(hmac, info, i, t_prev);
121122

122123
t_n := t_n + t_prev;
123124
// t_n == T(i) == T(i - 1) + Ti(i)
@@ -126,9 +127,10 @@ module HKDF {
126127

127128
// okm = first L (expectedLength) bytes of T(n)
128129
okm := t_n;
129-
assert T(hmac, info, n, okm);
130+
okmUnabridged := okm;
131+
assert T(hmac, info, n, okmUnabridged);
130132

131-
if |okm| > expectedLength {
133+
if expectedLength < |okm| {
132134
okm := okm[..expectedLength];
133135
}
134136
}
@@ -159,6 +161,7 @@ module HKDF {
159161
}
160162

161163
var prk := Extract(hmac, nonEmptySalt, ikm, digest);
162-
okm := Expand(hmac, prk, info, L, digest, nonEmptySalt);
164+
ghost var okmUnabridged;
165+
okm, okmUnabridged := Expand(hmac, prk, info, L, digest, nonEmptySalt);
163166
}
164167
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Add extern reference for a native AWS KMS service client
2+
module {:extern "Amazon.KeyManagementService"} AmazonKeyManagementService {
3+
// IAmazonKeyManagementService is an interface in target languages, but is listed as a class instead of a trait
4+
// because the Dafny transpiler cannot currently allow an extern interface to be used as a Dafny trait.
5+
// It only allows a Dafny trait to be used as an extern interface, not the other way around.
6+
// By making this a trait, compilation fails because this causes a conflict with the actual Amazon.KeyManagementService.IAmazonKeyManagementService
7+
// TODO: https://github.com/awslabs/aws-encryption-sdk-dafny/issues/284
8+
class {:extern "IAmazonKeyManagementService"} IAmazonKeyManagementService {}
9+
}

0 commit comments

Comments
 (0)