diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index c23fc89fd..2afa2468c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,8 +1,7 @@ -*Issue #, if available:* +_Issue #, if available:_ -*Description of changes:* - -*Squash/merge commit message, if applicable:* +_Description of changes:_ +_Squash/merge commit message, if applicable:_ By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. diff --git a/.github/actions/polymorph_codegen/action.yml b/.github/actions/polymorph_codegen/action.yml index bd5fee546..4eed3a9c5 100644 --- a/.github/actions/polymorph_codegen/action.yml +++ b/.github/actions/polymorph_codegen/action.yml @@ -88,7 +88,7 @@ runs: make -C mpl/AwsCryptographicMaterialProviders setup_prettier make -C mpl/ComAmazonawsKms setup_prettier make -C mpl/ComAmazonawsDynamodb setup_prettier - + # In the ESDK Dafny it does not make sense to run smithy dafny for java code # since the java esdk written natively and not through dafny #- name: Regenerate Java code using smithy-dafny diff --git a/.github/workflows/dafny_format_version.yaml b/.github/workflows/dafny_format_version.yaml new file mode 100644 index 000000000..3f1fe9bda --- /dev/null +++ b/.github/workflows/dafny_format_version.yaml @@ -0,0 +1,25 @@ +# This workflow reads the project.properties +# into the environment variables +# and then creates an output variable for `dafnyFormatVersion ` +name: Dafny Format Version + +on: + workflow_call: + outputs: + version: + description: "The dafny version for format" + value: ${{ jobs.getDafnyFormatVersion.outputs.version }} + +jobs: + getDafnyFormatVersion: + runs-on: ubuntu-22.04 + outputs: + version: ${{ steps.read_property.outputs.dafnyFormatVersion }} + steps: + - uses: actions/checkout@v4 + - name: Read version from Properties-file + id: read_property + uses: christian-draeger/read-properties@1.1.1 + with: + path: "./project.properties" + properties: "dafnyFormatVersion" diff --git a/.github/workflows/dafny_interop_test_net.yml b/.github/workflows/dafny_interop_test_net.yml index 2fefcb3cc..cef93d84d 100644 --- a/.github/workflows/dafny_interop_test_net.yml +++ b/.github/workflows/dafny_interop_test_net.yml @@ -34,11 +34,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ - windows-latest, - ubuntu-22.04, - macos-13, - ] + os: [windows-latest, ubuntu-22.04, macos-13] runs-on: ${{ matrix.os }} permissions: id-token: write @@ -58,7 +54,7 @@ jobs: - name: Setup .NET Core SDK 6 uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.x' + dotnet-version: "6.0.x" - name: Setup MPL Dafny uses: dafny-lang/setup-dafny-action@v1.7.2 @@ -82,12 +78,12 @@ jobs: uses: aws-actions/configure-aws-credentials@v4 with: aws-region: us-west-2 - role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 role-session-name: NetTests - name: Compile MPL with Dafny ${{inputs.mpl-dafny}} shell: bash - working-directory: mpl/TestVectorsAwsCryptographicMaterialProviders + working-directory: mpl/TestVectorsAwsCryptographicMaterialProviders run: | make setup_net # This works because `node` is installed by default on GHA runners @@ -109,7 +105,7 @@ jobs: - name: Test .NET Framework net48 working-directory: ./AwsEncryptionSDK - if: matrix.os == 'windows-latest' + if: matrix.os == 'windows-latest' shell: bash run: | make test_net FRAMEWORK=net48 @@ -126,7 +122,7 @@ jobs: - name: Test Examples on .NET Framework net48 working-directory: ./AwsEncryptionSDK - if: matrix.os == 'windows-latest' + if: matrix.os == 'windows-latest' shell: bash run: | dotnet test \ @@ -215,7 +211,7 @@ jobs: # We want this to fail, so if it returned 1, step passes, else it fails # TODO Post-#619: Refactor Test Vectors to expect failure, # as I doubt this true false logic works - + - name: Run ESDK-NET @ v4.0.0 Invalid Vectors .NET expect Success working-directory: ./AwsEncryptionSDK/runtimes/net/TestVectorsNative/TestVectors shell: bash diff --git a/.github/workflows/dafny_interop_test_vector_net.yml b/.github/workflows/dafny_interop_test_vector_net.yml index 8ca08f3af..0205ea83a 100644 --- a/.github/workflows/dafny_interop_test_vector_net.yml +++ b/.github/workflows/dafny_interop_test_vector_net.yml @@ -33,11 +33,7 @@ jobs: decrypt_python_vectors: strategy: matrix: - os: [ - windows-latest, - ubuntu-22.04, - macos-13, - ] + os: [windows-latest, ubuntu-22.04, macos-13] runs-on: ${{matrix.os}} permissions: id-token: write @@ -57,7 +53,7 @@ jobs: - name: Setup .NET Core SDK 6 uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.x' + dotnet-version: "6.0.x" - name: Setup MPL Dafny uses: dafny-lang/setup-dafny-action@v1.7.2 @@ -81,12 +77,12 @@ jobs: uses: aws-actions/configure-aws-credentials@v4 with: aws-region: us-west-2 - role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 role-session-name: NetTests - name: Compile MPL with Dafny ${{inputs.mpl-dafny}} shell: bash - working-directory: mpl/TestVectorsAwsCryptographicMaterialProviders + working-directory: mpl/TestVectorsAwsCryptographicMaterialProviders run: | make setup_net # This works because `node` is installed by default on GHA runners @@ -125,7 +121,7 @@ jobs: PYTHON_23_VECTOR_PATH=$GITHUB_WORKSPACE/python23/vectors DAFNY_AWS_ESDK_TEST_VECTOR_MANIFEST_PATH="$PYTHON_23_VECTOR_PATH/manifest.json" \ dotnet test --framework net48 - + - name: Decrypt Python 2.3.0 Test Vectors on .net6.0 working-directory: ./AwsEncryptionSDK/runtimes/net/TestVectorsNative/TestVectors if: matrix.os != 'windows-latest' @@ -144,10 +140,7 @@ jobs: generate_vectors: strategy: matrix: - os: [ - ubuntu-22.04, - macos-13, - ] + os: [ubuntu-22.04, macos-13] runs-on: ${{ matrix.os }} permissions: id-token: write @@ -167,7 +160,7 @@ jobs: - name: Setup .NET Core SDK 6 uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.x' + dotnet-version: "6.0.x" - name: Setup MPL Dafny uses: dafny-lang/setup-dafny-action@v1.7.2 @@ -191,12 +184,12 @@ jobs: uses: aws-actions/configure-aws-credentials@v4 with: aws-region: us-west-2 - role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 role-session-name: NetTests - name: Compile MPL with Dafny ${{inputs.mpl-dafny}} shell: bash - working-directory: mpl/TestVectorsAwsCryptographicMaterialProviders + working-directory: mpl/TestVectorsAwsCryptographicMaterialProviders run: | make setup_net # This works because `node` is installed by default on GHA runners @@ -228,7 +221,7 @@ jobs: dotnet run --project $GEN_PATH --framework net6.0 -- \ --encrypt-manifest $GEN_PATH/resources/0006-awses-message-decryption-generation.v2.json \ --output-dir $NET_41_VECTOR_PATH - + - name: Zip the Generated Test Vectors for ESDK-JS on Mac/Linux if: matrix.os != 'windows-latest' working-directory: ./AwsEncryptionSDK @@ -237,7 +230,7 @@ jobs: NET_41_VECTOR_PATH=net41/vectors cd $NET_41_VECTOR_PATH zip -qq net41.zip -r . - + - name: Upload Zip File uses: actions/upload-artifact@v4 if: matrix.os != 'windows-latest' @@ -249,10 +242,7 @@ jobs: needs: generate_vectors strategy: matrix: - os: [ - ubuntu-22.04, - macos-13, - ] + os: [ubuntu-22.04, macos-13] runs-on: ${{ matrix.os }} permissions: id-token: write @@ -267,36 +257,36 @@ jobs: run: | git submodule update --init libraries git submodule update --init --recursive mpl - + - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-region: us-west-2 - role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 role-session-name: NetTests - + - name: Set up Dirs working-directory: ./AwsEncryptionSDK run: | NET_41_VECTOR_PATH=AwsEncryptionSDK/net41/vectors mkdir -p $NET_41_VECTOR_PATH - + - name: Download Encrypt Manifest Artifact uses: actions/download-artifact@v4 with: name: ${{matrix.os}}_vector_artifact path: AwsEncryptionSDK/net41/vectors - + - uses: actions/setup-node@v4 with: - node-version: 17 + node-version: 17 - name: Install deps run: | openssl version npm install @aws-crypto/integration-node npm install fast-xml-parser - + - name: Decrypt Generated Test Vectors with ESDK-JS working-directory: ./AwsEncryptionSDK # TODO Post-#619: Fix Zip file creation on Windows diff --git a/.github/workflows/dafny_verify_version.yaml b/.github/workflows/dafny_verify_version.yaml new file mode 100644 index 000000000..ec9ce95b9 --- /dev/null +++ b/.github/workflows/dafny_verify_version.yaml @@ -0,0 +1,25 @@ +# This workflow reads the project.properties +# into the environment variables +# and then creates an output variable for `dafnyVerifyVersion ` +name: Dafny Verify Version + +on: + workflow_call: + outputs: + version: + description: "The dafny version for verify" + value: ${{ jobs.getDafnyVerifyVersion.outputs.version }} + +jobs: + getDafnyVerifyVersion: + runs-on: ubuntu-22.04 + outputs: + version: ${{ steps.read_property.outputs.dafnyVerifyVersion }} + steps: + - uses: actions/checkout@v4 + - name: Read version from Properties-file + id: read_property + uses: christian-draeger/read-properties@1.1.1 + with: + path: "./project.properties" + properties: "dafnyVerifyVersion" diff --git a/.github/workflows/dafny_version.yaml b/.github/workflows/dafny_version.yaml new file mode 100644 index 000000000..c20e01a43 --- /dev/null +++ b/.github/workflows/dafny_version.yaml @@ -0,0 +1,25 @@ +# This workflow reads the project.properties +# into the environment variables +# and then creates an output variable for `dafnyVersion` +name: Dafny Version + +on: + workflow_call: + outputs: + version: + description: "The dafny version" + value: ${{ jobs.getDafnyVersion.outputs.version }} + +jobs: + getDafnyVersion: + runs-on: ubuntu-22.04 + outputs: + version: ${{ steps.read_property.outputs.dafnyVersion }} + steps: + - uses: actions/checkout@v4 + - name: Read version from Properties-file + id: read_property + uses: christian-draeger/read-properties@1.1.1 + with: + path: "./project.properties" + properties: "dafnyVersion" diff --git a/.github/workflows/daily_ci.yml b/.github/workflows/daily_ci.yml index effd77843..87d3dfb23 100644 --- a/.github/workflows/daily_ci.yml +++ b/.github/workflows/daily_ci.yml @@ -6,18 +6,32 @@ on: - cron: "00 15 * * 1-5" jobs: + getVersion: + uses: ./.github/workflows/dafny_version.yaml + getVerifyVersion: + uses: ./.github/workflows/dafny_verify_version.yaml + # not yet used, because we don't actually CI formatting in this project?!? + getFormatVersion: + uses: ./.github/workflows/dafny_format_version.yaml + pr-ci-format: + needs: getFormatVersion + uses: ./.github/workflows/library_format.yml + with: + dafny: ${{needs.getFormatVersion.outputs.version}} daily-ci-codegen: # Don't run the cron builds on forks if: github.event_name != 'schedule' || github.repository_owner == 'aws' + needs: getVersion uses: ./.github/workflows/library_codegen.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} daily-ci-verification: # Don't run the cron builds on forks if: github.event_name != 'schedule' || github.repository_owner == 'aws' + needs: getVerifyVersion uses: ./.github/workflows/library_dafny_verification.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVerifyVersion.outputs.version}} # daily-ci-java: # if: github.event_name != 'schedule' || github.repository_owner == 'aws' # uses: ./.github/workflows/library_java_tests.yml @@ -25,34 +39,40 @@ jobs: # dafny: '4.2.0' daily-ci-net: if: github.event_name != 'schedule' || github.repository_owner == 'aws' + needs: getVersion uses: ./.github/workflows/library_net_tests.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} daily-ci-rust: if: github.event_name != 'schedule' || github.repository_owner == 'aws' + needs: getVersion uses: ./.github/workflows/library_rust_tests.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} daily-ci-go: if: github.event_name != 'schedule' || github.repository_owner == 'aws' + needs: getVersion uses: ./.github/workflows/library_go_tests.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} daily-ci-interop-tests: if: github.event_name != 'schedule' || github.repository_owner == 'aws' + needs: getVersion uses: ./.github/workflows/library_interop_tests.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} daily-dafny-test-vectors: if: github.event_name != 'schedule' || github.repository_owner == 'aws' + needs: getVersion uses: ./.github/workflows/library_interop_test_vectors.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} daily-dafny-legacy-test-vectors: if: github.event_name != 'schedule' || github.repository_owner == 'aws' + needs: getVersion uses: ./.github/workflows/library_legacy_interop_test_vectors.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} diff --git a/.github/workflows/duvet.yaml b/.github/workflows/duvet.yaml index db9513192..2286dc849 100644 --- a/.github/workflows/duvet.yaml +++ b/.github/workflows/duvet.yaml @@ -3,7 +3,7 @@ # with respect to the specification name: Duvet report -on: +on: pull_request: push: branches: @@ -23,10 +23,10 @@ jobs: - name: Support longpaths on Git checkout run: | git config --global core.longpaths true - + - uses: actions/checkout@v3 with: - submodules: true + submodules: true - name: Install duvet shell: bash @@ -43,7 +43,7 @@ jobs: run: | make duvet - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: always() with: name: specification_compliance_report diff --git a/.github/workflows/library_codegen.yml b/.github/workflows/library_codegen.yml index 500950e02..c2f9bc87a 100644 --- a/.github/workflows/library_codegen.yml +++ b/.github/workflows/library_codegen.yml @@ -13,10 +13,7 @@ jobs: strategy: fail-fast: false matrix: - library: - [ - AwsEncryptionSDK, - ] + library: [AwsEncryptionSDK] # Note dotnet is only used for formatting generated code # in this workflow dotnet-version: ["6.0.x"] @@ -62,7 +59,7 @@ jobs: with: distribution: "corretto" java-version: "17" - + - name: Install Smithy-Dafny codegen dependencies uses: ./.github/actions/install_smithy_dafny_codegen_dependencies diff --git a/.github/workflows/library_dafny_verification.yml b/.github/workflows/library_dafny_verification.yml index c97c33fd0..c269a7f68 100644 --- a/.github/workflows/library_dafny_verification.yml +++ b/.github/workflows/library_dafny_verification.yml @@ -5,7 +5,7 @@ on: workflow_call: inputs: dafny: - description: 'The Dafny version to run' + description: "The Dafny version to run" required: true type: string regenerate-code: @@ -18,11 +18,8 @@ jobs: verification: strategy: matrix: - library: [ - AwsEncryptionSDK, - TestVectors - ] - os: [ macos-13 ] + library: [AwsEncryptionSDK, TestVectors] + os: [macos-13] runs-on: ${{ matrix.os }} env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 @@ -31,12 +28,12 @@ jobs: - name: Support longpaths run: | git config --global core.longpaths true - + - uses: actions/checkout@v2 - name: Init Submodules run: | - git submodule update --init libraries - git submodule update --init --recursive mpl + git submodule update --init libraries + git submodule update --init --recursive mpl # dafny-reportgenerator requires next6 # but only 7.0 is installed on macos-13-large @@ -58,7 +55,7 @@ jobs: library: ${{ matrix.library }} diff-generated-code: false update-and-regenerate-mpl: true - + - name: Verify ${{ matrix.library }} Dafny code shell: bash working-directory: ./${{ matrix.library }} diff --git a/.github/workflows/library_format.yml b/.github/workflows/library_format.yml new file mode 100644 index 000000000..9ed7ef6d4 --- /dev/null +++ b/.github/workflows/library_format.yml @@ -0,0 +1,58 @@ +# This workflow performs static analysis checks. +name: Library format check + +on: + workflow_call: + inputs: + dafny: + description: "The Dafny version to run" + required: true + type: string + regenerate-code: + description: "Regenerate code using smithy-dafny" + required: false + default: false + type: boolean +jobs: + format_projects: + # Don't run the nightly build on forks + if: github.event_name != 'schedule' || github.repository_owner == 'aws' + strategy: + matrix: + os: [macos-13] + runs-on: ${{ matrix.os }} + defaults: + run: + shell: bash + env: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_NOLOGO: 1 + steps: + - name: Support longpaths + run: | + git config --global core.longpaths true + + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup Dafny + uses: dafny-lang/setup-dafny-action@v1.8.0 + with: + dafny-version: ${{ inputs.dafny }} + + - name: Check format of Java code et al + run: | + make format_java_misc-check + + - name: Check format of Dafny code + run: | + make format_dafny-check + + # ensure that we format with dotnet 6 + - name: Create temporary global.json + run: echo '{"sdk":{"rollForward":"latestFeature","version":"6.0.0"}}' > ./global.json + + - name: Check format of Dotnet code + run: | + make format_net-check diff --git a/.github/workflows/library_go_tests.yml b/.github/workflows/library_go_tests.yml index e3e44b54e..0bdc7c484 100644 --- a/.github/workflows/library_go_tests.yml +++ b/.github/workflows/library_go_tests.yml @@ -5,7 +5,7 @@ on: workflow_call: inputs: dafny: - description: 'The Dafny version to run' + description: "The Dafny version to run" required: true type: string regenerate-code: @@ -20,13 +20,13 @@ jobs: fail-fast: false matrix: library: [AwsEncryptionSDK, TestVectors] - go-version: [ "1.23" ] + go-version: ["1.23"] os: [ - # Sed script doesn't work properly on windows - # windows-latest, - ubuntu-22.04, - macos-13, - ] + # Sed script doesn't work properly on windows + # windows-latest, + ubuntu-22.04, + macos-13, + ] runs-on: ${{ matrix.os }} permissions: id-token: write @@ -65,7 +65,7 @@ jobs: - name: Install Go imports run: | - go install golang.org/x/tools/cmd/goimports@latest + go install golang.org/x/tools/cmd/goimports@latest - name: Compile ${{ matrix.library }} implementation shell: bash @@ -74,7 +74,7 @@ jobs: # This works because `node` is installed by default on GHA runners CORES=$(node -e 'console.log(os.cpus().length)') make transpile_go CORES=$CORES - + - name: Unzip .NET Retry Flag Manifests shell: bash working-directory: TestVectors/dafny/TestVectors/test/ @@ -96,10 +96,10 @@ jobs: shell: bash run: | make test_go - + - name: Test Examples for Go if: matrix.library == 'AwsEncryptionSDK' working-directory: ${{ matrix.library }}/runtimes/go/examples shell: bash run: | - go run main.go \ No newline at end of file + go run main.go diff --git a/.github/workflows/library_interop_test_vectors.yml b/.github/workflows/library_interop_test_vectors.yml index 84b6f874d..07a5f2cbc 100644 --- a/.github/workflows/library_interop_test_vectors.yml +++ b/.github/workflows/library_interop_test_vectors.yml @@ -32,166 +32,166 @@ jobs: permissions: id-token: write contents: read - + steps: - - name: Support longpaths on Git checkout - run: | - git config --global core.longpaths true - - # TestVectors will call KMS - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v2 - with: - aws-region: us-west-2 - role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 - role-session-name: InterOpTests - - - uses: actions/checkout@v3 - # Not all submodules are needed. - # We manually pull the submodule we DO need. - - run: git submodule update --init libraries - - run: git submodule update --init --recursive mpl - - # Set up runtimes - - name: Setup .NET Core SDK ${{ matrix.dotnet-version }} - if: matrix.language == 'net' - uses: actions/setup-dotnet@v3 - with: - dotnet-version: ${{ matrix.dotnet-version }} - - # Setup Java in Rust is needed for running polymorph - - name: Setup Java 17 - if: matrix.language == 'java' || matrix.language == 'rust' - uses: actions/setup-java@v3 - with: - distribution: "corretto" - java-version: 17 - - - name: Setup Rust Toolchain for GitHub CI - if: matrix.language == 'rust' - uses: actions-rust-lang/setup-rust-toolchain@v1.10.1 - with: - components: rustfmt - # TODO - uncomment this after Rust formatter works - # - name: Rustfmt Check - # uses: actions-rust-lang/rustfmt@v1 - - # TODO: Remove this after the formatting in Rust starts working - - name: smithy-dafny Rust hacks - if: matrix.language == 'rust' - shell: bash - run: | - if [ "$RUNNER_OS" == "macOS" ]; then - sed -i '' 's|rustfmt --edition 2021 runtimes/rust/src/implementation_from_dafny.rs|#&|' mpl/smithy-dafny/SmithyDafnyMakefile.mk - else - sed -i 's|rustfmt --edition 2021 runtimes/rust/src/implementation_from_dafny.rs|#&|' mpl/smithy-dafny/SmithyDafnyMakefile.mk - fi - - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version: "1.23" - - - name: Install Go imports - run: | - go install golang.org/x/tools/cmd/goimports@latest - - - name: Setup NASM for Windows in Rust (aws-lc-sys) - if: matrix.language == 'rust' && matrix.os == 'windows-latest' - uses: ilammy/setup-nasm@v1 - - - name: Setup Dafny - uses: dafny-lang/setup-dafny-action@v1.7.0 - with: - dafny-version: ${{ inputs.dafny }} - - - name: Regenerate code using smithy-dafny if necessary - if: ${{ inputs.regenerate-code }} - uses: ./.github/actions/polymorph_codegen - with: - dafny: ${{ inputs.dafny }} - library: ${{ matrix.library }} - diff-generated-code: false - - # Build implementation for each runtime - - name: Build ${{ matrix.library }} implementation in Java - if: matrix.language == 'java' - shell: bash - working-directory: ./${{ matrix.library }} - run: | - # This works because `node` is installed by default on GHA runners - CORES=$(node -e 'console.log(os.cpus().length)') - make build_java CORES=$CORES - - - name: Build ${{ matrix.library }} implementation in .NET - if: matrix.language == 'net' - shell: bash - working-directory: ./${{ matrix.library }} - run: | - # This works because `node` is installed by default on GHA runners - CORES=$(node -e 'console.log(os.cpus().length)') - make transpile_net - - - name: Install Smithy-Dafny codegen dependencies - if: matrix.language == 'rust' - uses: ./.github/actions/install_smithy_dafny_codegen_dependencies - - # TODO: Remove this after checking in Rust polymorph code - - name: Run make polymorph_rust - if: matrix.language == 'rust' - shell: bash - working-directory: ./${{ matrix.library }} - run: | - make polymorph_rust - - - name: Build ${{ matrix.library }} implementation in Rust - if: matrix.language == 'rust' - shell: bash - working-directory: ./${{ matrix.library }} - run: | - CORES=$(node -e 'console.log(os.cpus().length)') - make transpile_rust CORES=$CORES - - - name: Build ${{ matrix.library }} implementation in Go - if: matrix.language == 'go' - shell: bash - working-directory: ./${{ matrix.library }} - run: | - # This works because `node` is installed by default on GHA runners - CORES=$(node -e 'console.log(os.cpus().length)') - make transpile_go - - # TODO: Remove this after Go polymorph does not generate unwanted duplicate code. - - name: Purge polymorph code in Go - if: matrix.language == 'go' - shell: bash - working-directory: ./${{ matrix.library }} - run: | - make purge_polymorph_code - - - name: Setup gradle - if: matrix.language == 'java' - uses: gradle/gradle-build-action@v2 - with: - gradle-version: 7.2 - - - name: Create Manifests - working-directory: ./${{ matrix.library }} - run: make test_generate_vectors_${{ matrix.language }} - - - name: Create Encrypt Manifests - working-directory: ./${{ matrix.library }} - run: make test_encrypt_vectors_${{ matrix.language }} - - - name: Upload Encrypt Manifest and keys.json files - uses: actions/upload-artifact@v4 - with: - name: ${{matrix.os}}_vector_artifact_${{matrix.language}}_${{github.sha}} - path: | - ./${{matrix.library}}/runtimes/${{matrix.language}}/*.json - ./${{matrix.library}}/runtimes/${{matrix.language}}/plaintexts - ./${{matrix.library}}/runtimes/${{matrix.language}}/ciphertexts - + - name: Support longpaths on Git checkout + run: | + git config --global core.longpaths true + + # TestVectors will call KMS + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-region: us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 + role-session-name: InterOpTests + + - uses: actions/checkout@v3 + # Not all submodules are needed. + # We manually pull the submodule we DO need. + - run: git submodule update --init libraries + - run: git submodule update --init --recursive mpl + + # Set up runtimes + - name: Setup .NET Core SDK ${{ matrix.dotnet-version }} + if: matrix.language == 'net' + uses: actions/setup-dotnet@v3 + with: + dotnet-version: ${{ matrix.dotnet-version }} + + # Setup Java in Rust is needed for running polymorph + - name: Setup Java 17 + if: matrix.language == 'java' || matrix.language == 'rust' + uses: actions/setup-java@v3 + with: + distribution: "corretto" + java-version: 17 + + - name: Setup Rust Toolchain for GitHub CI + if: matrix.language == 'rust' + uses: actions-rust-lang/setup-rust-toolchain@v1.10.1 + with: + components: rustfmt + # TODO - uncomment this after Rust formatter works + # - name: Rustfmt Check + # uses: actions-rust-lang/rustfmt@v1 + + # TODO: Remove this after the formatting in Rust starts working + - name: smithy-dafny Rust hacks + if: matrix.language == 'rust' + shell: bash + run: | + if [ "$RUNNER_OS" == "macOS" ]; then + sed -i '' 's|rustfmt --edition 2021 runtimes/rust/src/implementation_from_dafny.rs|#&|' mpl/smithy-dafny/SmithyDafnyMakefile.mk + else + sed -i 's|rustfmt --edition 2021 runtimes/rust/src/implementation_from_dafny.rs|#&|' mpl/smithy-dafny/SmithyDafnyMakefile.mk + fi + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: "1.23" + + - name: Install Go imports + run: | + go install golang.org/x/tools/cmd/goimports@latest + + - name: Setup NASM for Windows in Rust (aws-lc-sys) + if: matrix.language == 'rust' && matrix.os == 'windows-latest' + uses: ilammy/setup-nasm@v1 + + - name: Setup Dafny + uses: dafny-lang/setup-dafny-action@v1.7.0 + with: + dafny-version: ${{ inputs.dafny }} + + - name: Regenerate code using smithy-dafny if necessary + if: ${{ inputs.regenerate-code }} + uses: ./.github/actions/polymorph_codegen + with: + dafny: ${{ inputs.dafny }} + library: ${{ matrix.library }} + diff-generated-code: false + + # Build implementation for each runtime + - name: Build ${{ matrix.library }} implementation in Java + if: matrix.language == 'java' + shell: bash + working-directory: ./${{ matrix.library }} + run: | + # This works because `node` is installed by default on GHA runners + CORES=$(node -e 'console.log(os.cpus().length)') + make build_java CORES=$CORES + + - name: Build ${{ matrix.library }} implementation in .NET + if: matrix.language == 'net' + shell: bash + working-directory: ./${{ matrix.library }} + run: | + # This works because `node` is installed by default on GHA runners + CORES=$(node -e 'console.log(os.cpus().length)') + make transpile_net + + - name: Install Smithy-Dafny codegen dependencies + if: matrix.language == 'rust' + uses: ./.github/actions/install_smithy_dafny_codegen_dependencies + + # TODO: Remove this after checking in Rust polymorph code + - name: Run make polymorph_rust + if: matrix.language == 'rust' + shell: bash + working-directory: ./${{ matrix.library }} + run: | + make polymorph_rust + + - name: Build ${{ matrix.library }} implementation in Rust + if: matrix.language == 'rust' + shell: bash + working-directory: ./${{ matrix.library }} + run: | + CORES=$(node -e 'console.log(os.cpus().length)') + make transpile_rust CORES=$CORES + + - name: Build ${{ matrix.library }} implementation in Go + if: matrix.language == 'go' + shell: bash + working-directory: ./${{ matrix.library }} + run: | + # This works because `node` is installed by default on GHA runners + CORES=$(node -e 'console.log(os.cpus().length)') + make transpile_go + + # TODO: Remove this after Go polymorph does not generate unwanted duplicate code. + - name: Purge polymorph code in Go + if: matrix.language == 'go' + shell: bash + working-directory: ./${{ matrix.library }} + run: | + make purge_polymorph_code + + - name: Setup gradle + if: matrix.language == 'java' + uses: gradle/gradle-build-action@v2 + with: + gradle-version: 7.2 + + - name: Create Manifests + working-directory: ./${{ matrix.library }} + run: make test_generate_vectors_${{ matrix.language }} + + - name: Create Encrypt Manifests + working-directory: ./${{ matrix.library }} + run: make test_encrypt_vectors_${{ matrix.language }} + + - name: Upload Encrypt Manifest and keys.json files + uses: actions/upload-artifact@v4 + with: + name: ${{matrix.os}}_vector_artifact_${{matrix.language}}_${{github.sha}} + path: | + ./${{matrix.library}}/runtimes/${{matrix.language}}/*.json + ./${{matrix.library}}/runtimes/${{matrix.language}}/plaintexts + ./${{matrix.library}}/runtimes/${{matrix.language}}/ciphertexts + testInteroperablity: needs: generateEncryptVectors strategy: @@ -211,7 +211,7 @@ jobs: permissions: id-token: write contents: read - + steps: - name: Support longpaths on Git checkout run: | @@ -222,9 +222,9 @@ jobs: uses: aws-actions/configure-aws-credentials@v2 with: aws-region: us-west-2 - role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 role-session-name: InterOpTests - + - uses: actions/checkout@v3 # Not all submodules are needed. # We manually pull the submodule we DO need. @@ -314,7 +314,7 @@ jobs: - name: Install Smithy-Dafny codegen dependencies if: matrix.decrypting_language == 'rust' uses: ./.github/actions/install_smithy_dafny_codegen_dependencies - + # TODO: Remove this after checking in Rust polymorph code - name: Run make polymorph_rust if: matrix.decrypting_language == 'rust' @@ -330,7 +330,7 @@ jobs: run: | CORES=$(node -e 'console.log(os.cpus().length)') make transpile_rust CORES=$CORES - + - name: Build ${{ matrix.library }} implementation in Go if: matrix.decrypting_language == 'go' shell: bash @@ -339,7 +339,7 @@ jobs: # This works because `node` is installed by default on GHA runners CORES=$(node -e 'console.log(os.cpus().length)') make transpile_go - + # TODO: Remove this after Go polymorph does not generate unwanted duplicate code. - name: Purge polymorph code in Go if: matrix.decrypting_language == 'go' @@ -357,4 +357,3 @@ jobs: - name: Decrypt Encrypt Manifest working-directory: ./${{ matrix.library }} run: make test_decrypt_encrypt_vectors_${{matrix.decrypting_language}} - diff --git a/.github/workflows/library_interop_tests.yml b/.github/workflows/library_interop_tests.yml index 579dd42b5..01404c2f7 100644 --- a/.github/workflows/library_interop_tests.yml +++ b/.github/workflows/library_interop_tests.yml @@ -1,13 +1,13 @@ # This workflow performs tests in .NET. name: Library net tests -on: +on: workflow_call: inputs: dafny: - description: 'The Dafny version to run' + description: "The Dafny version to run" required: true - type: string + type: string env: # Used in examples @@ -24,11 +24,7 @@ jobs: decrypt_python_vectors: strategy: matrix: - os: [ - windows-latest, - ubuntu-22.04, - macos-13, - ] + os: [windows-latest, ubuntu-22.04, macos-13] runs-on: ${{ matrix.os }} permissions: id-token: write @@ -46,25 +42,25 @@ jobs: run: | git submodule update --init libraries git submodule update --init --recursive mpl - + - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-region: us-west-2 - role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 role-session-name: NetTests - + - name: Setup .NET Core SDK 6 uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.x' + dotnet-version: "6.0.x" - name: Setup Dafny uses: dafny-lang/setup-dafny-action@v1.6.1 with: dafny-version: ${{ inputs.dafny }} - - name: Download Dependencies + - name: Download Dependencies working-directory: ./AwsEncryptionSDK run: make setup_net @@ -83,7 +79,7 @@ jobs: # This works because `node` is installed by default on GHA runners CORES=$(node -e 'console.log(os.cpus().length)') make transpile_net CORES=$CORES - + - name: Fetch Python 2.3.0 Test Vectors working-directory: ./ shell: bash @@ -94,7 +90,7 @@ jobs: curl --no-progress-meter --output $DOWNLOAD_NAME --location $VECTORS_URL unzip -o -qq $DOWNLOAD_NAME -d $PYTHON_23_VECTOR_PATH rm $DOWNLOAD_NAME - + - name: Decrypt Python 2.3.0 Test Vectors on .net48 (Windows ONLY) working-directory: ./AwsEncryptionSDK/runtimes/net/TestVectorsNative/TestVectors if: matrix.os == 'windows-latest' @@ -103,7 +99,7 @@ jobs: PYTHON_23_VECTOR_PATH=$GITHUB_WORKSPACE/python23/vectors DAFNY_AWS_ESDK_TEST_VECTOR_MANIFEST_PATH="$PYTHON_23_VECTOR_PATH/manifest.json" \ dotnet test --framework net48 - + - name: Decrypt Python 2.3.0 Test Vectors on .net6.0 working-directory: ./AwsEncryptionSDK/runtimes/net/TestVectorsNative/TestVectors if: matrix.os != 'windows-latest' @@ -118,14 +114,11 @@ jobs: DAFNY_AWS_ESDK_TEST_VECTOR_MANIFEST_PATH="$PYTHON_23_VECTOR_PATH/manifest.json" \ dotnet test --framework net6.0 fi - + generate_vectors: strategy: matrix: - os: [ - ubuntu-22.04, - macos-13, - ] + os: [ubuntu-22.04, macos-13] runs-on: ${{ matrix.os }} permissions: id-token: write @@ -143,26 +136,25 @@ jobs: run: | git submodule update --init libraries git submodule update --init --recursive mpl - - + - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-region: us-west-2 - role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 role-session-name: NetTests - + - name: Setup .NET Core SDK 6 uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.x' + dotnet-version: "6.0.x" - name: Setup Dafny uses: dafny-lang/setup-dafny-action@v1.6.1 with: dafny-version: ${{ inputs.dafny }} - - name: Download Dependencies + - name: Download Dependencies working-directory: ./AwsEncryptionSDK run: make setup_net @@ -174,7 +166,6 @@ jobs: CORES=$(node -e 'console.log(os.cpus().length)') make transpile_net CORES=$CORES - - name: Compile MPL TestVectors implementation shell: bash working-directory: ./mpl/TestVectorsAwsCryptographicMaterialProviders @@ -182,7 +173,6 @@ jobs: # This works because `node` is installed by default on GHA runners CORES=$(node -e 'console.log(os.cpus().length)') make transpile_net CORES=$CORES - # # TODO: Fix Zip file creation on Windows # # - name: Zip the Generated Test Vectors for ESDK-JS on Windows @@ -191,9 +181,8 @@ jobs: # # run: | # # # NET_41_VECTOR_PATH=$GITHUB_WORKSPACE/net41/vectors # # Set-Location -Path "$env:GITHUB_WORKSPACE\net41\vectors" - # # Compress-Archive -Path "$env:GITHUB_WORKSPACE\net41\vectors\*" -DestinationPath "$env:GITHUB_WORKSPACE\net41\vectors\net41.zip" + # # Compress-Archive -Path "$env:GITHUB_WORKSPACE\net41\vectors\*" -DestinationPath "$env:GITHUB_WORKSPACE\net41\vectors\net41.zip" - - name: Generate Test Vectors with .NET Framework net6.0 # TODO Post-#619: Fix Zip file creation on Windows if: matrix.os != 'windows-latest' @@ -206,7 +195,7 @@ jobs: dotnet run --project $GEN_PATH --framework net6.0 -- \ --encrypt-manifest $GEN_PATH/resources/0006-awses-message-decryption-generation.v2.json \ --output-dir $NET_41_VECTOR_PATH - + - name: Zip the Generated Test Vectors for ESDK-JS on Mac/Linux if: matrix.os != 'windows-latest' working-directory: ./AwsEncryptionSDK @@ -215,22 +204,19 @@ jobs: NET_41_VECTOR_PATH=net41/vectors cd $NET_41_VECTOR_PATH zip -qq net41.zip -r . - + - name: Upload Zip File uses: actions/upload-artifact@v4 if: matrix.os != 'windows-latest' with: name: ${{matrix.os}}_vector_artifact path: AwsEncryptionSDK/net41/vectors/*.zip - + decrypt_net_vectors_with_js: needs: generate_vectors strategy: matrix: - os: [ - ubuntu-22.04, - macos-13, - ] + os: [ubuntu-22.04, macos-13] runs-on: ${{ matrix.os }} permissions: id-token: write @@ -245,37 +231,36 @@ jobs: run: | git submodule update --init libraries git submodule update --init --recursive mpl - - + - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-region: us-west-2 - role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 role-session-name: NetTests - + - name: Set up Dirs working-directory: ./AwsEncryptionSDK run: | NET_41_VECTOR_PATH=AwsEncryptionSDK/net41/vectors mkdir -p $NET_41_VECTOR_PATH - + - name: Download Encrypt Manifest Artifact uses: actions/download-artifact@v4 with: name: ${{matrix.os}}_vector_artifact path: AwsEncryptionSDK/net41/vectors - + - uses: actions/setup-node@v4 with: - node-version: 17 + node-version: 17 - name: Install deps run: | openssl version npm install @aws-crypto/integration-node npm install fast-xml-parser - + - name: Decrypt Generated Test Vectors with ESDK-JS working-directory: ./AwsEncryptionSDK # TODO Post-#619: Fix Zip file creation on Windows @@ -284,5 +269,3 @@ jobs: NET_41_VECTOR_PATH=net41/vectors cd $NET_41_VECTOR_PATH npx -y @aws-crypto/integration-node decrypt -v net41.zip -c cpu -f 100 - - diff --git a/.github/workflows/library_java_tests.yml b/.github/workflows/library_java_tests.yml index 5fbf911c9..3f3307238 100644 --- a/.github/workflows/library_java_tests.yml +++ b/.github/workflows/library_java_tests.yml @@ -1,11 +1,11 @@ # This workflow performs tests in Java. name: Library Java tests -on: +on: workflow_call: inputs: dafny: - description: 'The Dafny version to run' + description: "The Dafny version to run" required: true type: string regenerate-code: @@ -18,15 +18,14 @@ jobs: testJava: strategy: matrix: - library: [ - #AwsEncryptionSDK - ] + library: [] + #AwsEncryptionSDK os: [ - # TODO just test on mac for now - #windows-latest, - #ubuntu-22.04, - macos-13 - ] + # TODO just test on mac for now + #windows-latest, + #ubuntu-22.04, + macos-13, + ] runs-on: ${{ matrix.os }} permissions: id-token: write @@ -35,12 +34,12 @@ jobs: - name: Support longpaths run: | git config --global core.longpaths true - + - uses: actions/checkout@v3 - name: Init Submodules run: | - git submodule update --init libraries - git submodule update --init --recursive mpl + git submodule update --init libraries + git submodule update --init --recursive mpl - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v2 @@ -66,8 +65,8 @@ jobs: - name: Setup Java 8 uses: actions/setup-java@v3 with: - distribution: 'corretto' - java-version: 8 + distribution: "corretto" + java-version: 8 - name: Build ${{ matrix.library }} implementation shell: bash @@ -85,15 +84,15 @@ jobs: - name: Setup Java 11 uses: actions/setup-java@v3 with: - distribution: 'corretto' + distribution: "corretto" java-version: 11 - name: Clean for next Java uses: gradle/gradle-build-action@v2 with: arguments: clean - build-root-directory: ./${{ matrix.library }}/runtimes/java - + build-root-directory: ./${{ matrix.library }}/runtimes/java + - name: Compile Java 11 uses: gradle/gradle-build-action@v2 with: @@ -105,11 +104,11 @@ jobs: with: arguments: runTests build-root-directory: ./${{ matrix.library }}/runtimes/java - + - name: Setup Java 16 uses: actions/setup-java@v3 with: - distribution: 'corretto' + distribution: "corretto" java-version: 16 - name: Clean for next Java @@ -128,12 +127,12 @@ jobs: uses: gradle/gradle-build-action@v2 with: arguments: runTests - build-root-directory: ./${{ matrix.library }}/runtimes/java - + build-root-directory: ./${{ matrix.library }}/runtimes/java + - name: Setup Java 17 uses: actions/setup-java@v3 with: - distribution: 'corretto' + distribution: "corretto" java-version: 17 - name: Clean for next Java @@ -152,4 +151,4 @@ jobs: uses: gradle/gradle-build-action@v2 with: arguments: runTests - build-root-directory: ./${{ matrix.library }}/runtimes/java + build-root-directory: ./${{ matrix.library }}/runtimes/java diff --git a/.github/workflows/library_legacy_interop_test_vectors.yml b/.github/workflows/library_legacy_interop_test_vectors.yml index 3cd760996..222e2b4da 100644 --- a/.github/workflows/library_legacy_interop_test_vectors.yml +++ b/.github/workflows/library_legacy_interop_test_vectors.yml @@ -30,106 +30,106 @@ jobs: # vectors. More important for the dafny-x implementations to be able # to decrypt these language: [net] - legacy_zips: [ - aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-1.3.5, - aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-1.3.7, - aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-1.3.8, - aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-2.0.0, - aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-2.2.0, - aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-2.3.0 - ] + legacy_zips: + [ + aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-1.3.5, + aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-1.3.7, + aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-1.3.8, + aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-2.0.0, + aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-2.2.0, + aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-2.3.0, + ] # https://taskei.amazon.dev/tasks/CrypTool-5284 dotnet-version: ["6.0.x"] runs-on: ${{ matrix.os }} permissions: id-token: write contents: read - + steps: - - name: Support longpaths on Git checkout - run: | - git config --global core.longpaths true + - name: Support longpaths on Git checkout + run: | + git config --global core.longpaths true + + - uses: actions/checkout@v3 + with: + submodules: true + # Not all submodules are needed. + # We manually pull the submodule we DO need. + - run: git submodule update --init libraries + - run: git submodule update --init --recursive mpl + + # Set up runtimes + - name: Setup .NET Core SDK ${{ matrix.dotnet-version }} + if: matrix.language == 'net' + uses: actions/setup-dotnet@v3 + with: + dotnet-version: ${{ matrix.dotnet-version }} + + - name: Setup Java 17 + if: matrix.language == 'java' + uses: actions/setup-java@v3 + with: + distribution: "corretto" + java-version: 17 + + - name: Setup Dafny + uses: dafny-lang/setup-dafny-action@v1.6.1 + with: + dafny-version: ${{ inputs.dafny }} - - uses: actions/checkout@v3 - with: - submodules: true - # Not all submodules are needed. - # We manually pull the submodule we DO need. - - run: git submodule update --init libraries - - run: git submodule update --init --recursive mpl + - name: Regenerate code using smithy-dafny if necessary + if: ${{ inputs.regenerate-code }} + uses: ./.github/actions/polymorph_codegen + with: + dafny: ${{ inputs.dafny }} + library: ${{ matrix.library }} + diff-generated-code: false - # Set up runtimes - - name: Setup .NET Core SDK ${{ matrix.dotnet-version }} - if: matrix.language == 'net' - uses: actions/setup-dotnet@v3 - with: - dotnet-version: ${{ matrix.dotnet-version }} + # Build implementation for each runtime + - name: Build ${{ matrix.library }} implementation in Java + if: matrix.language == 'java' + shell: bash + working-directory: ./${{ matrix.library }} + run: | + # This works because `node` is installed by default on GHA runners + CORES=$(node -e 'console.log(os.cpus().length)') + make build_java CORES=$CORES - - name: Setup Java 17 - if: matrix.language == 'java' - uses: actions/setup-java@v3 - with: - distribution: "corretto" - java-version: 17 + - name: Build ${{ matrix.library }} implementation in .NET + if: matrix.language == 'net' + shell: bash + working-directory: ./${{ matrix.library }} + run: | + # This works because `node` is installed by default on GHA runners + CORES=$(node -e 'console.log(os.cpus().length)') + make transpile_net - - name: Setup Dafny - uses: dafny-lang/setup-dafny-action@v1.6.1 - with: - dafny-version: ${{ inputs.dafny }} + - name: Setup gradle + if: matrix.language == 'java' + uses: gradle/gradle-build-action@v2 + with: + gradle-version: 7.2 - - name: Regenerate code using smithy-dafny if necessary - if: ${{ inputs.regenerate-code }} - uses: ./.github/actions/polymorph_codegen - with: - dafny: ${{ inputs.dafny }} - library: ${{ matrix.library }} - diff-generated-code: false - - # Build implementation for each runtime - - name: Build ${{ matrix.library }} implementation in Java - if: matrix.language == 'java' - shell: bash - working-directory: ./${{ matrix.library }} - run: | - # This works because `node` is installed by default on GHA runners - CORES=$(node -e 'console.log(os.cpus().length)') - make build_java CORES=$CORES + # TestVectors will call KMS + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-region: us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 + role-session-name: LegacyInterOpTests - - name: Build ${{ matrix.library }} implementation in .NET - if: matrix.language == 'net' - shell: bash - working-directory: ./${{ matrix.library }} - run: | - # This works because `node` is installed by default on GHA runners - CORES=$(node -e 'console.log(os.cpus().length)') - make transpile_net - - - name: Setup gradle - if: matrix.language == 'java' - uses: gradle/gradle-build-action@v2 - with: - gradle-version: 7.2 + # Extract test vector zips + - name: Unzip legacy test vectors + working-directory: ./${{matrix.library}} + run: | + unzip ${{matrix.legacy_zips}}.zip -d ${{matrix.legacy_zips}} - # TestVectors will call KMS - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v2 - with: - aws-region: us-west-2 - role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 - role-session-name: LegacyInterOpTests - - # Extract test vector zips - - name: Unzip legacy test vectors - working-directory: ./${{matrix.library}} - run: | - unzip ${{matrix.legacy_zips}}.zip -d ${{matrix.legacy_zips}} - - # Test Legacy Vectors - - name: Test legacy vectors via CLI - working-directory: ./${{matrix.library}} - env: - MANIFEST_PATH: ${{matrix.legacy_zips}}/ - MANIFEST_NAME: ${{ matrix.legacy_zips == 'aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-1.3.5' && 'decrypt_message.json' || 'manifest.json'}} - run: | - make test_decrypt_encrypt_vectors_net_legacy - + # Test Legacy Vectors + - name: Test legacy vectors via CLI + working-directory: ./${{matrix.library}} + env: + MANIFEST_PATH: ${{matrix.legacy_zips}}/ + MANIFEST_NAME: ${{ matrix.legacy_zips == 'aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-1.3.5' && 'decrypt_message.json' || 'manifest.json'}} + run: | + make test_decrypt_encrypt_vectors_net_legacy diff --git a/.github/workflows/library_net_tests.yml b/.github/workflows/library_net_tests.yml index 976769cf2..e0bab62c6 100644 --- a/.github/workflows/library_net_tests.yml +++ b/.github/workflows/library_net_tests.yml @@ -1,13 +1,13 @@ # This workflow performs tests in .NET. name: Library net tests -on: +on: workflow_call: inputs: dafny: - description: 'The Dafny version to run' + description: "The Dafny version to run" required: true - type: string + type: string regenerate-code: description: "Regenerate code using smithy-dafny" required: false @@ -31,11 +31,7 @@ jobs: fail-fast: false matrix: library: [AwsEncryptionSDK] - os: [ - windows-latest, - ubuntu-22.04, - macos-13, - ] + os: [windows-latest, ubuntu-22.04, macos-13] runs-on: ${{ matrix.os }} permissions: id-token: write @@ -53,18 +49,18 @@ jobs: run: | git submodule update --init libraries git submodule update --init --recursive mpl - + - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v2 with: aws-region: us-west-2 - role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 role-session-name: NetTests - + - name: Setup .NET Core SDK 6 uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.x' + dotnet-version: "6.0.x" - name: Setup Dafny uses: dafny-lang/setup-dafny-action@v1.7.0 @@ -80,7 +76,7 @@ jobs: diff-generated-code: false update-and-regenerate-mpl: true - - name: Download Dependencies + - name: Download Dependencies working-directory: ${{ matrix.library }} run: make setup_net @@ -110,7 +106,7 @@ jobs: - name: Test Examples on .NET Framework net48 working-directory: ${{ matrix.library }} - if: matrix.os == 'windows-latest' + if: matrix.os == 'windows-latest' shell: bash run: | dotnet test \ @@ -137,11 +133,11 @@ jobs: matrix: library: [TestVectors] os: [ - # Sed script doesn't work properly on windows - # windows-latest, - ubuntu-22.04, - macos-13, - ] + # Sed script doesn't work properly on windows + # windows-latest, + ubuntu-22.04, + macos-13, + ] runs-on: ${{ matrix.os }} permissions: id-token: write @@ -159,18 +155,18 @@ jobs: run: | git submodule update --init libraries git submodule update --init --recursive mpl - + - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v2 with: aws-region: us-west-2 - role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Dafny-Role-us-west-2 role-session-name: NetTestVectors - + - name: Setup .NET Core SDK 6 uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.x' + dotnet-version: "6.0.x" - name: Setup Dafny uses: dafny-lang/setup-dafny-action@v1.7.0 @@ -186,7 +182,7 @@ jobs: diff-generated-code: false update-and-regenerate-mpl: true - - name: Download Dependencies + - name: Download Dependencies working-directory: ${{ matrix.library }} run: make setup_net @@ -197,7 +193,7 @@ jobs: # This works because `node` is installed by default on GHA runners CORES=$(node -e 'console.log(os.cpus().length)') make transpile_net CORES=$CORES - + - name: Unzip .NET Retry Flag Manifests shell: bash working-directory: TestVectors/dafny/TestVectors/test/ diff --git a/.github/workflows/library_rust_tests.yml b/.github/workflows/library_rust_tests.yml index 72693b220..f5924dad5 100644 --- a/.github/workflows/library_rust_tests.yml +++ b/.github/workflows/library_rust_tests.yml @@ -5,7 +5,7 @@ on: workflow_call: inputs: dafny: - description: 'The Dafny version to run' + description: "The Dafny version to run" required: true type: string regenerate-code: @@ -20,11 +20,7 @@ jobs: fail-fast: false matrix: library: [AwsEncryptionSDK] - os: [ - windows-latest, - ubuntu-22.04, - macos-13, - ] + os: [windows-latest, ubuntu-22.04, macos-13] runs-on: ${{ matrix.os }} permissions: id-token: write @@ -133,11 +129,11 @@ jobs: matrix: library: [TestVectors] os: [ - # Sed script doesn't work properly on windows - # windows-latest, - ubuntu-22.04, - macos-13, - ] + # Sed script doesn't work properly on windows + # windows-latest, + ubuntu-22.04, + macos-13, + ] runs-on: ${{ matrix.os }} permissions: id-token: write diff --git a/.github/workflows/manual.yml b/.github/workflows/manual.yml index 41d221b19..5832f3e82 100644 --- a/.github/workflows/manual.yml +++ b/.github/workflows/manual.yml @@ -41,4 +41,4 @@ jobs: uses: ./.github/workflows/library_go_tests.yml with: dafny: ${{ inputs.dafny }} - regenerate-code: ${{ inputs.regenerate-code }} \ No newline at end of file + regenerate-code: ${{ inputs.regenerate-code }} diff --git a/.github/workflows/nighly_dafny.yml b/.github/workflows/nighly_dafny.yml index 85316b99e..c3604217a 100644 --- a/.github/workflows/nighly_dafny.yml +++ b/.github/workflows/nighly_dafny.yml @@ -17,7 +17,7 @@ jobs: if: github.event_name != 'schedule' || github.repository_owner == 'aws' uses: ./.github/workflows/library_dafny_verification.yml with: - dafny: 'nightly-latest' + dafny: "nightly-latest" regenerate-code: true # dafny-nightly-java: # if: github.event_name != 'schedule' || github.repository_owner == 'aws' @@ -29,31 +29,27 @@ jobs: if: github.event_name != 'schedule' || github.repository_owner == 'aws' uses: ./.github/workflows/library_net_tests.yml with: - dafny: 'nightly-latest' + dafny: "nightly-latest" regenerate-code: true dafny-nightly-rust: if: github.event_name != 'schedule' || github.repository_owner == 'aws' uses: ./.github/workflows/library_rust_tests.yml with: - dafny: 'nightly-latest' + dafny: "nightly-latest" regenerate-code: true dafny-nightly-go: if: github.event_name != 'schedule' || github.repository_owner == 'aws' uses: ./.github/workflows/library_go_tests.yml with: - dafny: 'nightly-latest' + dafny: "nightly-latest" regenerate-code: true - + cut-issue-on-failure: runs-on: ubuntu-22.04 permissions: id-token: write contents: read - needs: - [ - dafny-nightly-verification, - dafny-nightly-net, - ] + needs: [dafny-nightly-verification, dafny-nightly-net] if: ${{ always() && contains(needs.*.result, 'failure') }} steps: # We need access to the role that is able to get CI Bot Creds diff --git a/.github/workflows/pull.yml b/.github/workflows/pull.yml index a4727c23c..f6caa5860 100644 --- a/.github/workflows/pull.yml +++ b/.github/workflows/pull.yml @@ -5,42 +5,62 @@ on: pull_request: jobs: + getVersion: + uses: ./.github/workflows/dafny_version.yaml + getVerifyVersion: + uses: ./.github/workflows/dafny_verify_version.yaml + getFormatVersion: + uses: ./.github/workflows/dafny_format_version.yaml + pr-ci-format: + needs: getFormatVersion + uses: ./.github/workflows/library_format.yml + with: + dafny: ${{needs.getFormatVersion.outputs.version}} pr-ci-codegen: + needs: getVersion uses: ./.github/workflows/library_codegen.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} pr-ci-verification: + needs: getVerifyVersion uses: ./.github/workflows/library_dafny_verification.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVerifyVersion.outputs.version}} # pr-ci-java: + # needs: getVerifyVersion # uses: ./.github/workflows/library_java_tests.yml # with: - # dafny: '4.2.0' + # dafny: ${{needs.getVersion.outputs.version}} pr-ci-net: + needs: getVersion uses: ./.github/workflows/library_net_tests.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} pr-ci-rust: + needs: getVersion uses: ./.github/workflows/library_rust_tests.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} pr-ci-go: + needs: getVersion uses: ./.github/workflows/library_go_tests.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} pr-test-vectors: + needs: getVersion uses: ./.github/workflows/library_interop_tests.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} pr-dafny-test-vectors: + needs: getVersion uses: ./.github/workflows/library_interop_test_vectors.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} pr-dafny-legacy-test-vectors: + needs: getVersion uses: ./.github/workflows/library_legacy_interop_test_vectors.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} pr-ci-all-required: if: always() needs: diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index a0a084d3a..386dded5d 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -4,34 +4,52 @@ name: Push CI on: push: branches: - - main + - main jobs: + getVersion: + uses: ./.github/workflows/dafny_version.yaml + getVerifyVersion: + uses: ./.github/workflows/dafny_verify_version.yaml + getFormatVersion: + uses: ./.github/workflows/dafny_format_version.yaml + pr-ci-format: + needs: getFormatVersion + uses: ./.github/workflows/library_format.yml + with: + dafny: ${{needs.getFormatVersion.outputs.version}} pr-ci-codegen: + needs: getVersion uses: ./.github/workflows/library_codegen.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} push-ci-verification: + needs: getVerifyVersion uses: ./.github/workflows/library_dafny_verification.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVerifyVersion.outputs.version}} # push-ci-java: + # needs: getVersion # uses: ./.github/workflows/library_java_tests.yml # with: - # dafny: '4.2.0' + # dafny: ${{needs.getVersion.outputs.version}} push-ci-net: + needs: getVersion uses: ./.github/workflows/library_net_tests.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} push-ci-rust: + needs: getVersion uses: ./.github/workflows/library_rust_tests.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} push-ci-go: + needs: getVersion uses: ./.github/workflows/library_go_tests.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} pr-test-vectors: + needs: getVersion uses: ./.github/workflows/library_interop_tests.yml with: - dafny: '4.9.0' + dafny: ${{needs.getVersion.outputs.version}} diff --git a/.github/workflows/sem_ver.yml b/.github/workflows/sem_ver.yml index eb2752675..283707c3c 100644 --- a/.github/workflows/sem_ver.yml +++ b/.github/workflows/sem_ver.yml @@ -14,7 +14,7 @@ jobs: - name: Support longpaths on Git checkout run: | git config --global core.longpaths true - + - uses: actions/checkout@v3 with: submodules: recursive diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 57dbcdd42..8305b9c86 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,5 @@ repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.2.3 # Use the ref you want to point at + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.2.3 # Use the ref you want to point at hooks: - - id: trailing-whitespace + - id: trailing-whitespace diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..0d1f9d8c7 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +mpl +aws-encryption-sdk-specification +libraries +TestVectors/aws-encryption-sdk-test-vectors +AwsEncryptionSDK/runtimes/net/TestVectorsNative/TestVectorGenerator/resources/**/*.json +TestVectors/dafny/TestVectors/**/*.json diff --git a/.releaserc.cjs b/.releaserc.cjs index b7b1d08ea..9f3b7943e 100644 --- a/.releaserc.cjs +++ b/.releaserc.cjs @@ -22,8 +22,8 @@ const Runtimes = { net: { "AwsEncryptionSDK/runtimes/net/ESDK.csproj": { dependencies: [], - assemblyInfo: [] - } + assemblyInfo: [], + }, }, }; @@ -32,57 +32,58 @@ const Runtimes = { */ module.exports = { branches: ["mainline"], - repositoryUrl: - "git@github.com:aws/aws-encryption-sdk-dafny.git", + repositoryUrl: "git@github.com:aws/aws-encryption-sdk-dafny.git", plugins: [ // Check the commits since the last release - ["@semantic-release/commit-analyzer", + [ + "@semantic-release/commit-analyzer", { - "preset": "conventionalcommits", - "parserOpts": { - "noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES"] + preset: "conventionalcommits", + parserOpts: { + noteKeywords: ["BREAKING CHANGE", "BREAKING CHANGES"], }, - "presetConfig": { - "types": [ - {"type": "feat", "section": "Features"}, - {"type": "fix", "section": "Fixes"}, - {"type": "chore", "section": "Maintenance"}, - {"type": "docs", "section": "Maintenance"}, - {"type": "revert", "section": "Fixes"}, - {"type": "style", "hidden": true}, - {"type": "refactor", "hidden": true}, - {"type": "perf", "hidden": true}, - {"type": "test", "hidden": true} - ] + presetConfig: { + types: [ + { type: "feat", section: "Features" }, + { type: "fix", section: "Fixes" }, + { type: "chore", section: "Maintenance" }, + { type: "docs", section: "Maintenance" }, + { type: "revert", section: "Fixes" }, + { type: "style", hidden: true }, + { type: "refactor", hidden: true }, + { type: "perf", hidden: true }, + { type: "test", hidden: true }, + ], }, - "releaseRules": [ - {"type": "docs", "release": "patch"}, - {"type": "revert", "release": "patch"}, - {"type": "chore", "release": "patch"} - ] + releaseRules: [ + { type: "docs", release: "patch" }, + { type: "revert", release: "patch" }, + { type: "chore", release: "patch" }, + ], }, ], // Based on the commits generate release notes - ["@semantic-release/release-notes-generator", + [ + "@semantic-release/release-notes-generator", { - "preset": "conventionalcommits", - "parserOpts": { - "noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES"] + preset: "conventionalcommits", + parserOpts: { + noteKeywords: ["BREAKING CHANGE", "BREAKING CHANGES"], }, - "presetConfig": { - "types": [ - {"type": "feat", "section": "Features"}, - {"type": "fix", "section": "Fixes"}, - {"type": "chore", "section": "Maintenance"}, - {"type": "docs", "section": "Maintenance"}, - {"type": "revert", "section": "Fixes"}, - {"type": "style", "hidden": true}, - {"type": "refactor", "hidden": true}, - {"type": "perf", "hidden": true}, - {"type": "test", "hidden": true} - ] - } - } + presetConfig: { + types: [ + { type: "feat", section: "Features" }, + { type: "fix", section: "Fixes" }, + { type: "chore", section: "Maintenance" }, + { type: "docs", section: "Maintenance" }, + { type: "revert", section: "Fixes" }, + { type: "style", hidden: true }, + { type: "refactor", hidden: true }, + { type: "perf", hidden: true }, + { type: "test", hidden: true }, + ], + }, + }, ], // Update the change log with the generated release notes [ diff --git a/AwsEncryptionSDK/codebuild/release/release-prod.yml b/AwsEncryptionSDK/codebuild/release/release-prod.yml index 12b06afe1..e88cc3903 100644 --- a/AwsEncryptionSDK/codebuild/release/release-prod.yml +++ b/AwsEncryptionSDK/codebuild/release/release-prod.yml @@ -35,7 +35,7 @@ phases: - echo "Using unique id for flow $UNIQUE_ID" - make transpile_net - dotnet build runtimes/net /p:Configuration=Release -nowarn:CS0162,CS0168 - # This step assumes signing has already happened and we just need to retrieve + # This step assumes signing has already happened and we just need to retrieve # the signed artifacts - export BASE=codebuild/release - python $BASE/retrieve_signed_assembly.py --target net6.0 --unique-id $UNIQUE_ID diff --git a/AwsEncryptionSDK/codebuild/release/release-staging.yml b/AwsEncryptionSDK/codebuild/release/release-staging.yml index 914aecb9e..882c68bcf 100644 --- a/AwsEncryptionSDK/codebuild/release/release-staging.yml +++ b/AwsEncryptionSDK/codebuild/release/release-staging.yml @@ -17,7 +17,6 @@ env: VECTORS_URL: >- https://github.com/awslabs/aws-encryption-sdk-test-vectors/raw/master/vectors/awses-decrypt/python-2.3.0.zip - phases: install: runtime-versions: @@ -29,7 +28,7 @@ phases: - curl https://github.com/dafny-lang/dafny/releases/download/v4.9.0/dafny-4.9.0-x64-ubuntu-20.04.zip -L -o dafny.zip - unzip -qq dafny.zip && rm dafny.zip - export PATH="$PWD/dafny:$PATH" - # install mono to run net48 copied from + # install mono to run net48 copied from # https://www.mono-project.com/download/stable/#download-lin - sudo apt install ca-certificates gnupg - sudo gpg --homedir /tmp --no-default-keyring --keyring /usr/share/keyrings/mono-official-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF @@ -50,7 +49,7 @@ phases: # the signed artifacts # Build unsigned source - dotnet build runtimes/net /p:Configuration=Release -nowarn:CS0162,CS0168 - # This step assumes signing has already happened and we just need to retrieve + # This step assumes signing has already happened and we just need to retrieve # the signed artifacts - export BASE=codebuild/release - python $BASE/retrieve_signed_assembly.py --target net6.0 --unique-id $UNIQUE_ID @@ -76,10 +75,10 @@ phases: # run tests - TMP_ROLE=$(aws sts assume-role --role-arn "arn:aws:iam::370957321024:role/GitHub-CI-MPL-Dafny-Role-us-west-2" --role-session-name "CB-TestVectorResources") - - export TMP_ROLE - - export AWS_ACCESS_KEY_ID=$(echo "${TMP_ROLE}" | jq -r '.Credentials.AccessKeyId') - - export AWS_SECRET_ACCESS_KEY=$(echo "${TMP_ROLE}" | jq -r '.Credentials.SecretAccessKey') - - export AWS_SESSION_TOKEN=$(echo "${TMP_ROLE}" | jq -r '.Credentials.SessionToken') + - export TMP_ROLE + - export AWS_ACCESS_KEY_ID=$(echo "${TMP_ROLE}" | jq -r '.Credentials.AccessKeyId') + - export AWS_SECRET_ACCESS_KEY=$(echo "${TMP_ROLE}" | jq -r '.Credentials.SecretAccessKey') + - export AWS_SESSION_TOKEN=$(echo "${TMP_ROLE}" | jq -r '.Credentials.SessionToken') - aws sts get-caller-identity - make test_net @@ -114,7 +113,7 @@ phases: dotnet run --project $GEN_PATH --framework net6.0 -- \ --encrypt-manifest $GEN_PATH/resources/0006-awses-message-decryption-generation.v2.json \ --output-dir $NET_41_VECTOR_PATH - + # Zip the Generated Test Vectors for ESDK-JS on Mac/Linux - cd $NET_41_VECTOR_PATH - zip -qq net41.zip -r . diff --git a/AwsEncryptionSDK/codebuild/release/sign.yml b/AwsEncryptionSDK/codebuild/release/sign.yml index 5b30acdcc..a533dbff2 100644 --- a/AwsEncryptionSDK/codebuild/release/sign.yml +++ b/AwsEncryptionSDK/codebuild/release/sign.yml @@ -23,15 +23,15 @@ phases: - cd AwsEncryptionSDK - make transpile_net - TMP_ROLE=$(aws sts assume-role --role-arn "arn:aws:iam::370957321024:role/GitHub-CI-MPL-Dafny-Role-us-west-2" --role-session-name "CB-TestVectorResources") - - export TMP_ROLE - - export AWS_ACCESS_KEY_ID=$(echo "${TMP_ROLE}" | jq -r '.Credentials.AccessKeyId') - - export AWS_SECRET_ACCESS_KEY=$(echo "${TMP_ROLE}" | jq -r '.Credentials.SecretAccessKey') - - export AWS_SESSION_TOKEN=$(echo "${TMP_ROLE}" | jq -r '.Credentials.SessionToken') + - export TMP_ROLE + - export AWS_ACCESS_KEY_ID=$(echo "${TMP_ROLE}" | jq -r '.Credentials.AccessKeyId') + - export AWS_SECRET_ACCESS_KEY=$(echo "${TMP_ROLE}" | jq -r '.Credentials.SecretAccessKey') + - export AWS_SESSION_TOKEN=$(echo "${TMP_ROLE}" | jq -r '.Credentials.SessionToken') - aws sts get-caller-identity - make test_net ## Unset temp creds so that we get dropped back into the aws codebuild service role - - unset AWS_ACCESS_KEY_ID; unset AWS_SECRET_ACCESS_KEY; unset AWS_SESSION_TOKEN; + - unset AWS_ACCESS_KEY_ID; unset AWS_SECRET_ACCESS_KEY; unset AWS_SESSION_TOKEN; - dotnet build runtimes/net /p:Configuration=Release -nowarn:CS0162,CS0168 - export BASE=codebuild/release diff --git a/AwsEncryptionSDK/codebuild/release/test-prod.yml b/AwsEncryptionSDK/codebuild/release/test-prod.yml index 7f91d440b..901cba5a6 100644 --- a/AwsEncryptionSDK/codebuild/release/test-prod.yml +++ b/AwsEncryptionSDK/codebuild/release/test-prod.yml @@ -16,7 +16,7 @@ phases: - curl https://github.com/dafny-lang/dafny/releases/download/v4.9.0/dafny-4.9.0-x64-ubuntu-20.04.zip -L -o dafny.zip - unzip -qq dafny.zip && rm dafny.zip - export PATH="$PWD/dafny:$PATH" - # install mono to run net48 copied from + # install mono to run net48 copied from # https://www.mono-project.com/download/stable/#download-lin - sudo apt install ca-certificates gnupg - sudo gpg --homedir /tmp --no-default-keyring --keyring /usr/share/keyrings/mono-official-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF @@ -33,20 +33,20 @@ phases: - export VERSION=`grep '' runtimes/net/ESDK.csproj | sed 's/.*\(.*\)<\/Version>/\1/'` - sed -i.backup "/\/d" runtimes/net/tests/Test-ESDK.csproj - dotnet add runtimes/net/tests/Test-ESDK.csproj package AWS.Cryptography.EncryptionSDK --version $VERSION - - # run tests + + # run tests - TMP_ROLE=$(aws sts assume-role --role-arn "arn:aws:iam::370957321024:role/GitHub-CI-MPL-Dafny-Role-us-west-2" --role-session-name "CB-TestVectorResources") - - export TMP_ROLE - - export AWS_ACCESS_KEY_ID=$(echo "${TMP_ROLE}" | jq -r '.Credentials.AccessKeyId') - - export AWS_SECRET_ACCESS_KEY=$(echo "${TMP_ROLE}" | jq -r '.Credentials.SecretAccessKey') - - export AWS_SESSION_TOKEN=$(echo "${TMP_ROLE}" | jq -r '.Credentials.SessionToken') + - export TMP_ROLE + - export AWS_ACCESS_KEY_ID=$(echo "${TMP_ROLE}" | jq -r '.Credentials.AccessKeyId') + - export AWS_SECRET_ACCESS_KEY=$(echo "${TMP_ROLE}" | jq -r '.Credentials.SecretAccessKey') + - export AWS_SESSION_TOKEN=$(echo "${TMP_ROLE}" | jq -r '.Credentials.SessionToken') - aws sts get-caller-identity - make test_net - + # add released artifact to testvectors - sed -i.backup "/\/d" runtimes/net/TestVectorsNative/TestVectorLib/AWSEncryptionSDKTestVectorLib.csproj - dotnet add runtimes/net/TestVectorsNative/TestVectorLib/AWSEncryptionSDKTestVectorLib.csproj package AWS.Cryptography.EncryptionSDK --version $VERSION - + # Fetch awses-decrypt/python-2.3.0.zip - cd ../ - pwd @@ -74,11 +74,10 @@ phases: dotnet run --project $GEN_PATH --framework net6.0 -- \ --encrypt-manifest $GEN_PATH/resources/0006-awses-message-decryption-generation.v2.json \ --output-dir $NET_41_VECTOR_PATH - + # Zip the Generated Test Vectors for ESDK-JS on Mac/Linux - cd $NET_41_VECTOR_PATH - zip -qq net41.zip -r . # Decrypt Generated Test Vectors with ESDK-JS - npx -y @aws-crypto/integration-node decrypt -v $NET_41_VECTOR_PATH/net41.zip -c cpu - diff --git a/AwsEncryptionSDK/codebuild/release/verify.yml b/AwsEncryptionSDK/codebuild/release/verify.yml index aa1398339..910e41de0 100644 --- a/AwsEncryptionSDK/codebuild/release/verify.yml +++ b/AwsEncryptionSDK/codebuild/release/verify.yml @@ -3,7 +3,7 @@ version: 0.2 env: variables: FILE_NAME: "AWS.Cryptography.EncryptionSDK.dll" - + phases: install: runtime-versions: @@ -17,7 +17,7 @@ phases: - $sig = Get-AuthenticodeSignature -FilePath net48/$Env:FILE_NAME - $sig | Format-List -Property * # Check signature on net6.0 dll - - mkdir net6.0 + - mkdir net6.0 - python AwsEncryptionSDK/codebuild/release/retrieve_signed_assembly.py --target net6.0 --unique-id $Env:UNIQUE_ID --output net6.0 - $sig = Get-AuthenticodeSignature -FilePath net6.0/$Env:FILE_NAME - $sig | Format-List -Property * diff --git a/AwsEncryptionSDK/codegen-patches/AwsEncryptionSdk/dotnet/dafny-4.9.0.patch b/AwsEncryptionSDK/codegen-patches/AwsEncryptionSdk/dotnet/dafny-4.9.0.patch index 60d69d7da..12ed7918d 100644 --- a/AwsEncryptionSDK/codegen-patches/AwsEncryptionSdk/dotnet/dafny-4.9.0.patch +++ b/AwsEncryptionSDK/codegen-patches/AwsEncryptionSdk/dotnet/dafny-4.9.0.patch @@ -37,7 +37,7 @@ index 2a22994b..f39ded66 100644 + private static string ListAsString(List list) + { + if (list.Count < 1) return ""; -+ string [] msgArr = new string [list.Count]; ++ string[] msgArr = new string[list.Count]; + for (int i = 0; i < list.Count; i++) + msgArr[i] = $"{list[i].GetType().Name} :: {list[i].Message}"; + return String.Join("\n\t", msgArr); diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/AwsEncryptionSdkOperations.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/AwsEncryptionSdkOperations.dfy index 1a89973e7..bba1270d3 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/AwsEncryptionSdkOperations.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/AwsEncryptionSdkOperations.dfy @@ -90,15 +90,15 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp //# a Key Commitment (../framework/algorithm-suites.md#algorithm- //# suites-encryption-key-derivation-settings) value of True ensures - ( - && input.algorithmSuiteId.Some? - && config.mpl.ValidateCommitmentPolicyOnEncrypt(MPL.ValidateCommitmentPolicyOnEncryptInput( - algorithm := MPL.AlgorithmSuiteId.ESDK(input.algorithmSuiteId.value), - commitmentPolicy := MPL.CommitmentPolicy.ESDK(config.commitmentPolicy) - )).Failure? - ) - ==> - output.Failure? + ( + && input.algorithmSuiteId.Some? + && config.mpl.ValidateCommitmentPolicyOnEncrypt(MPL.ValidateCommitmentPolicyOnEncryptInput( + algorithm := MPL.AlgorithmSuiteId.ESDK(input.algorithmSuiteId.value), + commitmentPolicy := MPL.CommitmentPolicy.ESDK(config.commitmentPolicy) + )).Failure? + ) + ==> + output.Failure? //= compliance/client-apis/encrypt.txt#2.4.6 //= type=implication @@ -107,8 +107,8 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp ensures && input.frameLength.Some? && (input.frameLength.value <= 0 || input.frameLength.value > 0xFFFF_FFFF) - ==> - output.Failure? + ==> + output.Failure? // //= compliance/client-apis/encrypt.txt#2.6.1 // //= type=implication @@ -127,10 +127,10 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp { var frameLength : Types.FrameLength :- if input.frameLength.Some? then :- Need( - 0 < input.frameLength.value <= 0xFFFF_FFFF, - Types.AwsEncryptionSdkException( - message := "FrameLength must be greater than 0 and less than 2^32") - ); + 0 < input.frameLength.value <= 0xFFFF_FFFF, + Types.AwsEncryptionSdkException( + message := "FrameLength must be greater than 0 and less than 2^32") + ); Success(input.frameLength.value) else Success(EncryptDecryptHelpers.DEFAULT_FRAME_LENGTH); @@ -154,17 +154,17 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp if algorithmSuiteId.Some? { var _ :- config.mpl .ValidateCommitmentPolicyOnEncrypt(MPL.ValidateCommitmentPolicyOnEncryptInput( - algorithm := algorithmSuiteId.value, - commitmentPolicy := MPL.CommitmentPolicy.ESDK(config.commitmentPolicy) - )) + algorithm := algorithmSuiteId.value, + commitmentPolicy := MPL.CommitmentPolicy.ESDK(config.commitmentPolicy) + )) .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); } - // int64 fits 9 exabytes so we're never going to actually hit this. But if we don't - // include this the verifier is not convinced that we can cast the size to int64 + // int64 fits 9 exabytes so we're never going to actually hit this. But if we don't + // include this the verifier is not convinced that we can cast the size to int64 :- Need(|input.plaintext| < INT64_MAX_LIMIT, - Types.AwsEncryptionSdkException( - message := "Plaintext exceeds maximum allowed size")); + Types.AwsEncryptionSdkException( + message := "Plaintext exceeds maximum allowed size")); var materials :- EncryptDecryptHelpers.GetEncryptionMaterials( cmm, @@ -179,8 +179,8 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp ); :- Need(materials.algorithmSuite.id.ESDK?, - Types.AwsEncryptionSdkException( - message := "Encryption materials contain incompatible algorithm suite for the AWS Encryption SDK.")); + Types.AwsEncryptionSdkException( + message := "Encryption materials contain incompatible algorithm suite for the AWS Encryption SDK.")); :- EncryptDecryptHelpers.ValidateMaxEncryptedDataKeys(config.maxEncryptedDataKeys, materials.encryptedDataKeys); @@ -199,9 +199,9 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp var maybeDerivedDataKeys := KeyDerivation.DeriveKeys( messageId, materials.plaintextDataKey.value, materials.algorithmSuite, config.crypto, config.netV4_0_0_RetryPolicy, false ); - + var derivedDataKeys :- maybeDerivedDataKeys - .MapFailure(e => Types.AwsEncryptionSdkException( message := "Failed to derive data keys")); + .MapFailure(e => Types.AwsEncryptionSdkException( message := "Failed to derive data keys")); var maybeHeader := EncryptDecryptHelpers.BuildHeaderForEncrypt( messageId, @@ -238,7 +238,7 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp method {:vcs_split_on_every_assert} SignAndSerializeMessage( config: InternalConfig, header: Header.HeaderInfo, - framedMessage: MessageBody.FramedMessage, + framedMessage: MessageBody.FramedMessage, materials: MPL.EncryptionMaterials ) returns (output: Result) @@ -247,28 +247,28 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp modifies config.crypto.Modifies ensures config.crypto.ValidState() ensures framedMessage.finalFrame.header.suite.signature.ECDSA? && output.Success? - ==> - && |config.crypto.History.ECDSASign| == |old(config.crypto.History.ECDSASign)| + 1 - && EncryptDecryptHelpers.SerializeMessageWithoutSignature(framedMessage, materials.algorithmSuite).Success? - && materials.signingKey.Some? - && var message := EncryptDecryptHelpers.SerializeMessageWithoutSignature(framedMessage, materials.algorithmSuite).value; - && var ecdsaParams := framedMessage.finalFrame.header.suite.signature.ECDSA.curve; - && var ecdsaSignInput := Seq.Last(config.crypto.History.ECDSASign).input; - && var ecdsaSignOutput := Seq.Last(config.crypto.History.ECDSASign).output; - && ecdsaSignInput.signatureAlgorithm == ecdsaParams - && ecdsaSignInput.signingKey == materials.signingKey.value - && ecdsaSignInput.message == message - - && ecdsaSignOutput.Success? - && var signatureBytes := ecdsaSignOutput.value; - && |signatureBytes| < UINT16_LIMIT - && var signature := UInt16ToSeq(|signatureBytes| as uint16) + signatureBytes; - && EncryptOutput(ciphertext := message + signature, encryptionContext := header.encryptionContext, algorithmSuiteId := header.suite.id.ESDK) == output.value - ensures framedMessage.finalFrame.header.suite.signature.None? && output.Success? - ==> - && EncryptDecryptHelpers.SerializeMessageWithoutSignature(framedMessage, materials.algorithmSuite).Success? - && var message := EncryptDecryptHelpers.SerializeMessageWithoutSignature(framedMessage, materials.algorithmSuite).value; - && EncryptOutput(ciphertext := message, encryptionContext := header.encryptionContext, algorithmSuiteId := header.suite.id.ESDK) == output.value + ==> + && |config.crypto.History.ECDSASign| == |old(config.crypto.History.ECDSASign)| + 1 + && EncryptDecryptHelpers.SerializeMessageWithoutSignature(framedMessage, materials.algorithmSuite).Success? + && materials.signingKey.Some? + && var message := EncryptDecryptHelpers.SerializeMessageWithoutSignature(framedMessage, materials.algorithmSuite).value; + && var ecdsaParams := framedMessage.finalFrame.header.suite.signature.ECDSA.curve; + && var ecdsaSignInput := Seq.Last(config.crypto.History.ECDSASign).input; + && var ecdsaSignOutput := Seq.Last(config.crypto.History.ECDSASign).output; + && ecdsaSignInput.signatureAlgorithm == ecdsaParams + && ecdsaSignInput.signingKey == materials.signingKey.value + && ecdsaSignInput.message == message + + && ecdsaSignOutput.Success? + && var signatureBytes := ecdsaSignOutput.value; + && |signatureBytes| < UINT16_LIMIT + && var signature := UInt16ToSeq(|signatureBytes| as uint16) + signatureBytes; + && EncryptOutput(ciphertext := message + signature, encryptionContext := header.encryptionContext, algorithmSuiteId := header.suite.id.ESDK) == output.value + ensures framedMessage.finalFrame.header.suite.signature.None? && output.Success? + ==> + && EncryptDecryptHelpers.SerializeMessageWithoutSignature(framedMessage, materials.algorithmSuite).Success? + && var message := EncryptDecryptHelpers.SerializeMessageWithoutSignature(framedMessage, materials.algorithmSuite).value; + && EncryptOutput(ciphertext := message, encryptionContext := header.encryptionContext, algorithmSuiteId := header.suite.id.ESDK) == output.value { if framedMessage.finalFrame.header.suite.signature.ECDSA? { //= compliance/client-apis/encrypt.txt#2.7.2 @@ -293,7 +293,7 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp var ecdsaParams := framedMessage.finalFrame.header.suite.signature.ECDSA.curve; // TODO: This should just work, but Proof is difficult :- Need(materials.signingKey.Some?, - Types.AwsEncryptionSdkException( message := "Missing signing key.")); + Types.AwsEncryptionSdkException( message := "Missing signing key.")); //= compliance/client-apis/encrypt.txt#2.7.2 //# To calculate a signature, this operation MUST use the signature @@ -307,18 +307,18 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp //# message header (../data-format/message-header.md) and message body //# (../data-format/message-body.md) var maybeBytes := config.crypto.ECDSASign( - Primitives.Types.ECDSASignInput( - signatureAlgorithm := ecdsaParams, - signingKey := materials.signingKey.value, - message := msg - ) + Primitives.Types.ECDSASignInput( + signatureAlgorithm := ecdsaParams, + signingKey := materials.signingKey.value, + message := msg + ) ); var bytes :- maybeBytes .MapFailure(e => Types.AwsCryptographyPrimitives(e)); :- Need(|bytes| < UINT16_LIMIT, - Types.AwsEncryptionSdkException( - message := "Length of signature bytes is larger than the uint16 limit.")); + Types.AwsEncryptionSdkException( + message := "Length of signature bytes is larger than the uint16 limit.")); // TODO // :- Need(|bytes| == ecdsaParams.SignatureLength() as int, @@ -352,24 +352,24 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp //# * Encryption Context (Section 2.4.2) //# * Algorithm Suite (Section 2.4.5) return Success( - Types.EncryptOutput( - ciphertext := msg, - encryptionContext := header.encryptionContext, - algorithmSuiteId := header.suite.id.ESDK - ) - ); + Types.EncryptOutput( + ciphertext := msg, + encryptionContext := header.encryptionContext, + algorithmSuiteId := header.suite.id.ESDK + ) + ); } else { //= compliance/client-apis/encrypt.txt#2.6 //# Otherwise the encrypt operation MUST //# NOT perform this step. var msg :- EncryptDecryptHelpers.SerializeMessageWithoutSignature(framedMessage, materials.algorithmSuite); return Success( - Types.EncryptOutput( - ciphertext := msg, - encryptionContext := header.encryptionContext, - algorithmSuiteId := header.suite.id.ESDK - ) - ); + Types.EncryptOutput( + ciphertext := msg, + encryptionContext := header.encryptionContext, + algorithmSuiteId := header.suite.id.ESDK + ) + ); } } @@ -412,12 +412,12 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp //# interface.md) //#* Keyring (../framework/keyring-interface.md) ensures - ( - || (input.materialsManager.Some? && input.keyring.Some?) - || (input.materialsManager.None? && input.keyring.None?) - ) - ==> - output.Failure? + ( + || (input.materialsManager.Some? && input.keyring.Some?) + || (input.materialsManager.None? && input.keyring.None?) + ) + ==> + output.Failure? { var cmm :- EncryptDecryptHelpers.CreateCmmFromInput(input.materialsManager, input.keyring); @@ -433,7 +433,7 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp } method {:vcs_split_on_every_assert} InternalDecrypt - ( + ( config: InternalConfig, cmm: AwsCryptographyMaterialProvidersTypes.ICryptographicMaterialsManager, buffer: SerializeFunctions.ReadableBuffer, @@ -457,38 +457,38 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp //# decrypt MUST yield an error. // TODO :: Consider removing from spec as this is redundant ensures - ( - && var headerBody := Header.ReadHeaderBody(buffer, config.maxEncryptedDataKeys, config.mpl); - && headerBody.Success? - && config.mpl.ValidateCommitmentPolicyOnDecrypt(MPL.ValidateCommitmentPolicyOnDecryptInput( - algorithm := headerBody.value.data.algorithmSuite.id, - commitmentPolicy := MPL.CommitmentPolicy.ESDK(config.commitmentPolicy) - )).Failure? - ) - ==> - output.Failure? + ( + && var headerBody := Header.ReadHeaderBody(buffer, config.maxEncryptedDataKeys, config.mpl); + && headerBody.Success? + && config.mpl.ValidateCommitmentPolicyOnDecrypt(MPL.ValidateCommitmentPolicyOnDecryptInput( + algorithm := headerBody.value.data.algorithmSuite.id, + commitmentPolicy := MPL.CommitmentPolicy.ESDK(config.commitmentPolicy) + )).Failure? + ) + ==> + output.Failure? //= compliance/client-apis/decrypt.txt#2.6 //= type=implication //# The client MUST return as output to this operation: ensures output.Success? - ==> - && var headerBody := Header.ReadHeaderBody(buffer, config.maxEncryptedDataKeys, config.mpl); - && headerBody.Success? - // * Algorithm Suite (Section 2.6.3) - && headerBody.value.data.algorithmSuite.id.ESDK? - && output.value.algorithmSuiteId == headerBody.value.data.algorithmSuite.id.ESDK - && old(cmm.History.DecryptMaterials) < cmm.History.DecryptMaterials - && Seq.Last(cmm.History.DecryptMaterials).output.Success? - && var decMat := Seq.Last(cmm.History.DecryptMaterials).output.value.decryptionMaterials; - // * Encryption Context (Section 2.6.2) - && var headerEncryptionContext := EncryptionContext.GetEncryptionContext(headerBody.value.data.encryptionContext); - && output.value.encryptionContext == - headerEncryptionContext + buildEncryptionContextToOnlyAuthenticate(decMat) + ==> + && var headerBody := Header.ReadHeaderBody(buffer, config.maxEncryptedDataKeys, config.mpl); + && headerBody.Success? + // * Algorithm Suite (Section 2.6.3) + && headerBody.value.data.algorithmSuite.id.ESDK? + && output.value.algorithmSuiteId == headerBody.value.data.algorithmSuite.id.ESDK + && old(cmm.History.DecryptMaterials) < cmm.History.DecryptMaterials + && Seq.Last(cmm.History.DecryptMaterials).output.Success? + && var decMat := Seq.Last(cmm.History.DecryptMaterials).output.value.decryptionMaterials; + // * Encryption Context (Section 2.6.2) + && var headerEncryptionContext := EncryptionContext.GetEncryptionContext(headerBody.value.data.encryptionContext); + && output.value.encryptionContext == + headerEncryptionContext + buildEncryptionContextToOnlyAuthenticate(decMat) { // Track if a failure has triggered a V4 Retry var v4Retry := false; - + //= compliance/client-apis/decrypt.txt#2.5.1.1 //= type=TODO //# To make diagnosing this mistake easier, implementations SHOULD detect @@ -498,11 +498,11 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp //# error message. var headerBody :- Header - .ReadHeaderBody(buffer, config.maxEncryptedDataKeys, config.mpl) - .MapFailure(EncryptDecryptHelpers.MapSerializeFailure(": ReadHeaderBody")); + .ReadHeaderBody(buffer, config.maxEncryptedDataKeys, config.mpl) + .MapFailure(EncryptDecryptHelpers.MapSerializeFailure(": ReadHeaderBody")); AnyCorrectlyReadByteRange(buffer, headerBody.tail); - + var rawHeader := buffer.bytes[buffer.start..headerBody.tail.start]; var algorithmSuite := headerBody.data.algorithmSuite; @@ -513,11 +513,11 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp //# (client.md#commitment-policy) configured in the client (client.md) //# decrypt MUST yield an error. var _ :- config.mpl - .ValidateCommitmentPolicyOnDecrypt(MPL.ValidateCommitmentPolicyOnDecryptInput( - algorithm := algorithmSuite.id, - commitmentPolicy := MPL.CommitmentPolicy.ESDK(config.commitmentPolicy) - )) - .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); + .ValidateCommitmentPolicyOnDecrypt(MPL.ValidateCommitmentPolicyOnDecryptInput( + algorithm := algorithmSuite.id, + commitmentPolicy := MPL.CommitmentPolicy.ESDK(config.commitmentPolicy) + )) + .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); //= compliance/client-apis/decrypt.txt#2.5.2 //# This CMM MUST obtain the decryption materials (../framework/ @@ -542,7 +542,7 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp config.commitmentPolicy, config.mpl ); - + // It SHOULD be the case that cmm.History !in config.crypto.Modifies; // However proving this is very expensive. // This is a HACK to address this history element @@ -553,15 +553,15 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp var suite := decMat.algorithmSuite; :- Need(suite == algorithmSuite, - Types.AwsEncryptionSdkException( - message := "Stored header algorithm suite does not match decryption algorithm suite.")); + Types.AwsEncryptionSdkException( + message := "Stored header algorithm suite does not match decryption algorithm suite.")); //= compliance/client-apis/decrypt.txt#2.4.2 //# This operation MUST NOT release any unauthenticated plaintext or //# unauthenticated associated data. var headerAuth :- HeaderAuth - .ReadHeaderAuthTag(headerBody.tail, suite) - .MapFailure(EncryptDecryptHelpers.MapSerializeFailure(": ReadHeaderAuthTag")); + .ReadHeaderAuthTag(headerBody.tail, suite) + .MapFailure(EncryptDecryptHelpers.MapSerializeFailure(": ReadHeaderAuthTag")); if suite.messageVersion == 1 { reveal HeaderAuth.ReadHeaderAuthTag(); @@ -574,20 +574,20 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp } else { assert false; } - + ConcatenateCorrectlyReadByteRanges(buffer, headerBody.tail, headerAuth.tail); - + var maybeDerivedDataKeys := KeyDerivation.DeriveKeys( headerBody.data.messageId, decMat.plaintextDataKey.value, suite, config.crypto, config.netV4_0_0_RetryPolicy, false ); :- Need(maybeDerivedDataKeys.Success?, - Types.AwsEncryptionSdkException( - message := "Failed to derive data keys")); + Types.AwsEncryptionSdkException( + message := "Failed to derive data keys")); var derivedDataKeys := maybeDerivedDataKeys.value; :- Need(Header.HeaderVersionSupportsCommitment?(suite, headerBody.data), - Types.AwsEncryptionSdkException( - message := "Invalid commitment values found in header body")); + Types.AwsEncryptionSdkException( + message := "Invalid commitment values found in header body")); if suite.commitment.HKDF? { reveal Header.HeaderVersionSupportsCommitment?(); var _ :- EncryptDecryptHelpers.ValidateSuiteData(suite, headerBody.data, derivedDataKeys.commitmentKey.value); @@ -612,11 +612,11 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp var encryptionContextToOnlyAuthenticate := buildEncryptionContextToOnlyAuthenticate(decMat); EncryptionContext.SubsetOfESDKEncryptionContextIsESDKEncryptionContext( - decMat.encryptionContext, - encryptionContextToOnlyAuthenticate - ); + decMat.encryptionContext, + encryptionContextToOnlyAuthenticate + ); - var canonicalReqEncryptionContext := + var canonicalReqEncryptionContext := EncryptionContext.GetCanonicalEncryptionContext(encryptionContextToOnlyAuthenticate); var serializedReqEncryptionContext := EncryptionContext.WriteEmptyEcOrWriteAAD(canonicalReqEncryptionContext); @@ -629,23 +629,23 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp //# authenticated encryption algorithm (../framework/algorithm- //# suites.md#encryption-algorithm) to decrypt with the following inputs: config.crypto.AESDecrypt(Primitives.Types.AESDecryptInput( - encAlg := suite.encrypt.AES_GCM, - //#* the cipherkey is the derived data key - key := derivedDataKeys.dataKey, - //#* the ciphertext is an empty byte array - cipherTxt := [], - //#* the tag is the value serialized in the message header's - //# authentication tag field (../data-format/message- - //# header.md#authentication-tag) - authTag := headerAuth.data.headerAuthTag, - //#* the IV is the value serialized in the message header's IV field - //# (../data-format/message-header#iv). - iv := headerAuth.data.headerIv, - //#* MUST be the concatenation of the serialized [message header body] - //# (../data-format/message-header.md#header-body) - //# and the serialization of encryption context to only authenticate. - aad := rawHeader + serializedReqEncryptionContext - )); + encAlg := suite.encrypt.AES_GCM, + //#* the cipherkey is the derived data key + key := derivedDataKeys.dataKey, + //#* the ciphertext is an empty byte array + cipherTxt := [], + //#* the tag is the value serialized in the message header's + //# authentication tag field (../data-format/message- + //# header.md#authentication-tag) + authTag := headerAuth.data.headerAuthTag, + //#* the IV is the value serialized in the message header's IV field + //# (../data-format/message-header#iv). + iv := headerAuth.data.headerIv, + //#* MUST be the concatenation of the serialized [message header body] + //# (../data-format/message-header.md#header-body) + //# and the serialization of encryption context to only authenticate. + aad := rawHeader + serializedReqEncryptionContext + )); // TODO Post-#619: Add to the ESDK Specification the following: @@ -660,8 +660,8 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp // TODO Post-#619: Duvet this section // TODO Post-#619: Refactor this to eliminate duplicate code if maybeHeaderAuth.Failure? - && config.netV4_0_0_RetryPolicy == NetV4_0_0_RetryPolicy.ALLOW_RETRY - && v4Retry == false + && config.netV4_0_0_RetryPolicy == NetV4_0_0_RetryPolicy.ALLOW_RETRY + && v4Retry == false { v4Retry := true; // Derive Keys following ESDK-NET @ v4.0.0 Behavior @@ -669,8 +669,8 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp headerBody.data.messageId, decMat.plaintextDataKey.value, suite, config.crypto, config.netV4_0_0_RetryPolicy, true ); :- Need(maybeDerivedDataKeys.Success?, - Types.AwsEncryptionSdkException( - message := "Failed to derive data keys") + Types.AwsEncryptionSdkException( + message := "Failed to derive data keys") ); derivedDataKeys := maybeDerivedDataKeys.value; // Serialize Required Encryption Context following ESDK-NET @ v4.0.0 Behavior @@ -683,29 +683,29 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp //# authenticated encryption algorithm (../framework/algorithm- //# suites.md#encryption-algorithm) to decrypt with the following inputs: config.crypto.AESDecrypt(Primitives.Types.AESDecryptInput( - encAlg := suite.encrypt.AES_GCM, - //#* the cipherkey is the derived data key - key := derivedDataKeys.dataKey, - //#* the ciphertext is an empty byte array - cipherTxt := [], - //#* the tag is the value serialized in the message header's - //# authentication tag field (../data-format/message- - //# header.md#authentication-tag) - authTag := headerAuth.data.headerAuthTag, - //#* the IV is the value serialized in the message header's IV field - //# (../data-format/message-header#iv). - iv := headerAuth.data.headerIv, - //#* MUST be the concatenation of the serialized [message header body] - //# (../data-format/message-header.md#header-body) - //# and the serialization of encryption context to only authenticate. - aad := rawHeader + serializedReqEncryptionContext - )); + encAlg := suite.encrypt.AES_GCM, + //#* the cipherkey is the derived data key + key := derivedDataKeys.dataKey, + //#* the ciphertext is an empty byte array + cipherTxt := [], + //#* the tag is the value serialized in the message header's + //# authentication tag field (../data-format/message- + //# header.md#authentication-tag) + authTag := headerAuth.data.headerAuthTag, + //#* the IV is the value serialized in the message header's IV field + //# (../data-format/message-header#iv). + iv := headerAuth.data.headerIv, + //#* MUST be the concatenation of the serialized [message header body] + //# (../data-format/message-header.md#header-body) + //# and the serialization of encryption context to only authenticate. + aad := rawHeader + serializedReqEncryptionContext + )); } //= compliance/client-apis/decrypt.txt#2.7.3 //# If this tag verification fails, this operation MUST immediately halt //# and fail. var _ :- maybeHeaderAuth - .MapFailure(e => Types.AwsCryptographyPrimitives(e)); + .MapFailure(e => Types.AwsCryptographyPrimitives(e)); var header := Header.HeaderInfo( body := headerBody.data, @@ -720,7 +720,7 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp var key := derivedDataKeys.dataKey; var plaintext: seq; var messageBodyTail: SerializeFunctions.ReadableBuffer; - + //= compliance/client-apis/decrypt.txt#2.7.4 //# Once the message header is successfully parsed, the next sequential //# bytes MUST be deserialized according to the message body spec @@ -764,8 +764,8 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp ); :- Need(signature.start == |signature.bytes|, - Types.AwsEncryptionSdkException( - message := "Data after message footer.")); + Types.AwsEncryptionSdkException( + message := "Data after message footer.")); //= compliance/client-apis/decrypt.txt#2.7.1 //# Until the header is verified (Section 2.7.3), this operation MUST NOT @@ -808,7 +808,7 @@ module AwsEncryptionSdkOperations refines AbstractAwsCryptographyEncryptionSdkOp map k <- decMat.encryptionContext | - && k in decMat.requiredEncryptionContextKeys + && k in decMat.requiredEncryptionContextKeys :: k := decMat.encryptionContext[k] } diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/EncryptDecrypt.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/EncryptDecrypt.dfy index 5825b02cf..4b3ddbca2 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/EncryptDecrypt.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/EncryptDecrypt.dfy @@ -51,10 +51,10 @@ module EncryptDecryptHelpers { :(res: Result, Types.Error>) requires |signature| < UINT16_LIMIT ensures res.Success? - ==> - && var message := SerializeMessageWithoutSignature(framedMessage, suite); - && message.Success? - && res.value == message.value + WriteShortLengthSeq(signature) + ==> + && var message := SerializeMessageWithoutSignature(framedMessage, suite); + && message.Success? + && res.value == message.value + WriteShortLengthSeq(signature) { var serializedSignature := WriteShortLengthSeq(signature); var serializedMessage :- SerializeMessageWithoutSignature(framedMessage, suite); @@ -118,45 +118,45 @@ module EncryptDecryptHelpers { ensures && decMat.verificationKey.Some? && SerializeFunctions.ReadShortLengthSeq(buffer).Failure? - ==> - && res.Failure? + ==> + && res.Failure? ensures && decMat.verificationKey.Some? && SerializeFunctions.ReadShortLengthSeq(buffer).Success? - ==> - && |old(crypto.History.ECDSAVerify)| + 1 == |crypto.History.ECDSAVerify| - && var ECDSAVerifyInput := Seq.Last(crypto.History.ECDSAVerify).input; - && ECDSAVerifyInput.signatureAlgorithm == decMat.algorithmSuite.signature.ECDSA.curve - && ECDSAVerifyInput.verificationKey == decMat.verificationKey.value - && ECDSAVerifyInput.message == msg - && ECDSAVerifyInput.signature == SerializeFunctions.ReadShortLengthSeq(buffer).value.data + ==> + && |old(crypto.History.ECDSAVerify)| + 1 == |crypto.History.ECDSAVerify| + && var ECDSAVerifyInput := Seq.Last(crypto.History.ECDSAVerify).input; + && ECDSAVerifyInput.signatureAlgorithm == decMat.algorithmSuite.signature.ECDSA.curve + && ECDSAVerifyInput.verificationKey == decMat.verificationKey.value + && ECDSAVerifyInput.message == msg + && ECDSAVerifyInput.signature == SerializeFunctions.ReadShortLengthSeq(buffer).value.data ensures && |old(crypto.History.ECDSAVerify)| + 1 == |crypto.History.ECDSAVerify| - // The verification call succeeded - // and the value it returned was false - // (indicating invalid signature) + // The verification call succeeded + // and the value it returned was false + // (indicating invalid signature) && Seq.Last(crypto.History.ECDSAVerify).output.Success? && !Seq.Last(crypto.History.ECDSAVerify).output.value - ==> - && res.Failure? + ==> + && res.Failure? ensures && |old(crypto.History.ECDSAVerify)| + 1 == |crypto.History.ECDSAVerify| - // The verification call failed + // The verification call failed && Seq.Last(crypto.History.ECDSAVerify).output.Failure? - ==> - && res.Failure? + ==> + && res.Failure? ensures && |old(crypto.History.ECDSAVerify)| + 1 == |crypto.History.ECDSAVerify| - // The verification call succeeded and the value it returned was true - // (indicating valid signature) + // The verification call succeeded and the value it returned was true + // (indicating valid signature) && Seq.Last(crypto.History.ECDSAVerify).output.Success? && Seq.Last(crypto.History.ECDSAVerify).output.value - ==> - res.Success? + ==> + res.Success? { // If there is no verification key, that lets us conclude that the suite does not have a signature. @@ -170,19 +170,19 @@ module EncryptDecryptHelpers { //# If the algorithm suite has a signature algorithm, this operation MUST //# verify the message footer using the specified signature algorithm. - + //= compliance/client-apis/decrypt.txt#2.7 //# ./framework/algorithm- //# suites.md#signature-algorithm), this operation MUST perform //# this step. var signature :- SerializeFunctions - - //= compliance/client-apis/decrypt.txt#2.7.5 - //# After deserializing the body, this operation MUST deserialize the - //# next encrypted message bytes as the message footer (../data-format/ - //# message-footer.md). - .ReadShortLengthSeq(buffer) - .MapFailure(MapSerializeFailure(": ReadShortLengthSeq")); + + //= compliance/client-apis/decrypt.txt#2.7.5 + //# After deserializing the body, this operation MUST deserialize the + //# next encrypted message bytes as the message footer (../data-format/ + //# message-footer.md). + .ReadShortLengthSeq(buffer) + .MapFailure(MapSerializeFailure(": ReadShortLengthSeq")); var ecdsaParams := decMat.algorithmSuite.signature.ECDSA.curve; @@ -193,19 +193,19 @@ module EncryptDecryptHelpers { //# suites.md) in the decryption materials to verify the encrypted //# message, with the following inputs: var maybeSignatureVerifiedResult := crypto.ECDSAVerify(Primitives.Types.ECDSAVerifyInput( - signatureAlgorithm := ecdsaParams, - //#* The verification key is the verification key (../framework/ - //# structures.md#verification-key) in the decryption materials. - verificationKey := decMat.verificationKey.value, - //#* The input to verify is the concatenation of the serialization of - //# the message header (../data-format/message-header.md) and message - //# body (../data-format/message-body.md). - message := msg, - signature := signature.data - )); + signatureAlgorithm := ecdsaParams, + //#* The verification key is the verification key (../framework/ + //# structures.md#verification-key) in the decryption materials. + verificationKey := decMat.verificationKey.value, + //#* The input to verify is the concatenation of the serialization of + //# the message header (../data-format/message-header.md) and message + //# body (../data-format/message-body.md). + message := msg, + signature := signature.data + )); var signatureVerifiedResult :- maybeSignatureVerifiedResult - .MapFailure(e => Types.AwsCryptographyPrimitives(e)); + .MapFailure(e => Types.AwsCryptographyPrimitives(e)); if (!signatureVerifiedResult) { return Failure(Types.AwsEncryptionSdkException( message := "Invalid signature" )); @@ -216,7 +216,7 @@ module EncryptDecryptHelpers { function method MapSerializeFailure(s: string): SerializeFunctions.ReadProblems -> Types.Error { (e: SerializeFunctions.ReadProblems) => - match e + match e case Error(e) => Types.AwsEncryptionSdkException(message := e) case MoreNeeded(_) => Types.AwsEncryptionSdkException(message := "Incomplete message" + s) } @@ -233,24 +233,24 @@ module EncryptDecryptHelpers { ensures && input.Some? && (exists key: UTF8.ValidUTF8Bytes | key in input.value.Keys :: RESERVED_ENCRYPTION_CONTEXT <= key) - ==> - output.Fail? + ==> + output.Fail? { - if + if && input.Some? && exists key: UTF8.ValidUTF8Bytes | key in input.value.Keys :: RESERVED_ENCRYPTION_CONTEXT <= key then Fail(Types.AwsEncryptionSdkException( - message := "Encryption context keys cannot contain reserved prefix 'aws-crypto-'")) + message := "Encryption context keys cannot contain reserved prefix 'aws-crypto-'")) else Pass } - /* - * Helper method for taking optional input keyrings/CMMs and returning a CMM, - * either directly the one that was provided or a new default CMM from the - * provided keyring. - */ + /* + * Helper method for taking optional input keyrings/CMMs and returning a CMM, + * either directly the one that was provided or a new default CMM from the + * provided keyring. + */ method CreateCmmFromInput( inputCmm: Option, inputKeyring: Option @@ -258,14 +258,14 @@ module EncryptDecryptHelpers { returns (res: Result) requires inputKeyring.Some? - ==> - && inputKeyring.value.ValidState() + ==> + && inputKeyring.value.ValidState() requires inputCmm.Some? - ==> - && inputCmm.value.ValidState() + ==> + && inputCmm.value.ValidState() ensures res.Success? - ==> - && res.value.ValidState() + ==> + && res.value.ValidState() modifies (if inputKeyring.Some? then inputKeyring.value.Modifies else {}) @@ -280,33 +280,33 @@ module EncryptDecryptHelpers { ensures && res.Success? && inputCmm.Some? - ==> - res.value == inputCmm.value + ==> + res.value == inputCmm.value ensures && res.Success? && inputKeyring.Some? - ==> - fresh(res.value.Modifies - inputKeyring.value.Modifies) + ==> + fresh(res.value.Modifies - inputKeyring.value.Modifies) ensures && inputCmm.Some? && inputKeyring.Some? - ==> - res.Failure? + ==> + res.Failure? ensures && inputCmm.None? && inputKeyring.None? - ==> - res.Failure? + ==> + res.Failure? { :- Need(inputCmm.None? || inputKeyring.None?, - Types.AwsEncryptionSdkException( - message := "Cannot provide both a keyring and a CMM")); + Types.AwsEncryptionSdkException( + message := "Cannot provide both a keyring and a CMM")); :- Need(inputCmm.Some? || inputKeyring.Some?, - Types.AwsEncryptionSdkException( - message := "Must provide either a keyring or a CMM")); + Types.AwsEncryptionSdkException( + message := "Must provide either a keyring or a CMM")); var cmm : MPL.ICryptographicMaterialsManager; if inputCmm.Some? { @@ -314,7 +314,7 @@ module EncryptDecryptHelpers { } else { var maybeMaterialsProviders := MaterialProviders.MaterialProviders(); var materialProviders :- maybeMaterialsProviders - .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); + .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); // Each of these three citations refer to creating a default CMM from // the input keyring. @@ -336,9 +336,9 @@ module EncryptDecryptHelpers { //# CMM (../framework/default-cmm.md) from the input keyring //# (../framework/keyring-interface.md). var maybeCmm := materialProviders - .CreateDefaultCryptographicMaterialsManager(MPL.CreateDefaultCryptographicMaterialsManagerInput( - keyring := inputKeyring.value - ) + .CreateDefaultCryptographicMaterialsManager(MPL.CreateDefaultCryptographicMaterialsManagerInput( + keyring := inputKeyring.value + ) ); return maybeCmm .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); @@ -354,14 +354,14 @@ module EncryptDecryptHelpers { ensures maxEncryptedDataKeys.None? ==> output.Pass? ensures - && maxEncryptedDataKeys.Some? - && |edks| > maxEncryptedDataKeys.value as int - ==> + && maxEncryptedDataKeys.Some? + && |edks| > maxEncryptedDataKeys.value as int + ==> output.Fail? { if - && maxEncryptedDataKeys.Some? - && |edks| > maxEncryptedDataKeys.value as int + && maxEncryptedDataKeys.Some? + && |edks| > maxEncryptedDataKeys.value as int then Fail(Types.AwsEncryptionSdkException( message := "Encrypted data keys exceed maxEncryptedDataKeys")) else @@ -369,8 +369,8 @@ module EncryptDecryptHelpers { } /* - * Generate a message id of appropriate length for the given algorithm suite. - */ + * Generate a message id of appropriate length for the given algorithm suite. + */ method GenerateMessageId( suite: MPL.AlgorithmSuiteInfo, crypto: Primitives.AtomicPrimitivesClient @@ -382,15 +382,15 @@ module EncryptDecryptHelpers { ensures crypto.ValidState() ensures - && res.Success? - && suite.messageVersion == 1 - ==> + && res.Success? + && suite.messageVersion == 1 + ==> |res.value| == HeaderTypes.MESSAGE_ID_LEN_V1 ensures - && res.Success? - && suite.messageVersion == 2 - ==> + && res.Success? + && suite.messageVersion == 2 + ==> |res.value| == HeaderTypes.MESSAGE_ID_LEN_V2 { var maybeId; @@ -402,12 +402,12 @@ module EncryptDecryptHelpers { Primitives.Types.GenerateRandomBytesInput( length := HeaderTypes.MESSAGE_ID_LEN_V2 as int32)); } var id :- maybeId - .MapFailure(e => Types.AwsCryptographyPrimitives(e)); + .MapFailure(e => Types.AwsCryptographyPrimitives(e)); return Success(id); } - // We restrict this method to the encrypt path so that we can assume the body is framed. + // We restrict this method to the encrypt path so that we can assume the body is framed. method {:vcs_split_on_every_assert} BuildHeaderForEncrypt( messageId: HeaderTypes.MessageId, suite: HeaderTypes.ESDKAlgorithmSuite, @@ -427,77 +427,77 @@ module EncryptDecryptHelpers { ensures crypto.ValidState() requires SerializableTypes.IsESDKEncryptionContext(encryptionContext) - + requires forall k: UTF8.ValidUTF8Bytes | k in requiredEncryptionContextKeys :: k in encryptionContext requires suite.commitment.HKDF? ==> - && derivedDataKeys.commitmentKey.Some? - && |derivedDataKeys.commitmentKey.value| == suite.commitment.HKDF.outputKeyLength as int + && derivedDataKeys.commitmentKey.Some? + && |derivedDataKeys.commitmentKey.value| == suite.commitment.HKDF.outputKeyLength as int requires frameLength > 0 // Make sure the output correctly uses the values that were given as input ensures res.Success? ==> - && res.value.suite == suite - && res.value.body.frameLength == frameLength - && res.value.encryptionContext == encryptionContext + && res.value.suite == suite + && res.value.body.frameLength == frameLength + && res.value.encryptionContext == encryptionContext ensures res.Success? ==> Header.IsHeader(res.value) ensures res.Success? ==> res.value.body.contentType.Framed? { - //= aws-encryption-sdk-specification/client-apis/encrypt.md#construct-the-header - //# - [AAD](../data-format/message-header.md#aad): MUST be the serialization of the [encryption context](../framework/structures.md#encryption-context) - //# in the [encryption materials](../framework/structures.md#encryption-materials), - //# and this serialization MUST NOT contain any key value pairs listed in - //# the [encryption material's](../framework/structures.md#encryption-materials) - //# [required encryption context keys](../framework/structures.md#required-encryption-context-keys). - var reqKeySet : set := set k <- requiredEncryptionContextKeys; - var storedEncryptionContext: MPL.EncryptionContext := - map f | f in (encryptionContext - reqKeySet) :: f := encryptionContext[f]; - EncryptionContext.SubsetOfESDKEncryptionContextIsESDKEncryptionContext(encryptionContext, storedEncryptionContext); - - var canonicalStoredEncryptionContext := EncryptionContext.GetCanonicalEncryptionContext(storedEncryptionContext); - - var body := BuildHeaderBody( - messageId, - suite, - canonicalStoredEncryptionContext, - encryptedDataKeys, - frameLength as uint32, - derivedDataKeys.commitmentKey - ); + //= aws-encryption-sdk-specification/client-apis/encrypt.md#construct-the-header + //# - [AAD](../data-format/message-header.md#aad): MUST be the serialization of the [encryption context](../framework/structures.md#encryption-context) + //# in the [encryption materials](../framework/structures.md#encryption-materials), + //# and this serialization MUST NOT contain any key value pairs listed in + //# the [encryption material's](../framework/structures.md#encryption-materials) + //# [required encryption context keys](../framework/structures.md#required-encryption-context-keys). + var reqKeySet : set := set k <- requiredEncryptionContextKeys; + var storedEncryptionContext: MPL.EncryptionContext := + map f | f in (encryptionContext - reqKeySet) :: f := encryptionContext[f]; + EncryptionContext.SubsetOfESDKEncryptionContextIsESDKEncryptionContext(encryptionContext, storedEncryptionContext); + + var canonicalStoredEncryptionContext := EncryptionContext.GetCanonicalEncryptionContext(storedEncryptionContext); + + var body := BuildHeaderBody( + messageId, + suite, + canonicalStoredEncryptionContext, + encryptedDataKeys, + frameLength as uint32, + derivedDataKeys.commitmentKey + ); - var requiredEncryptionContextMap: MPL.EncryptionContext := - map r | r in reqKeySet :: r := encryptionContext[r]; - EncryptionContext.SubsetOfESDKEncryptionContextIsESDKEncryptionContext(encryptionContext, requiredEncryptionContextMap); - - var canonicalReqEncryptionContext := - EncryptionContext.GetCanonicalEncryptionContext(requiredEncryptionContextMap); - var serializedReqEncryptionContext := - EncryptionContext.WriteEmptyEcOrWriteAAD(canonicalReqEncryptionContext); - - //= compliance/client-apis/encrypt.txt#2.6.2 - //# Before encrypting input plaintext, this operation MUST serialize the - //# message header body (../data-format/message-header.md). - var rawHeader := Header.WriteHeaderBody(body); + var requiredEncryptionContextMap: MPL.EncryptionContext := + map r | r in reqKeySet :: r := encryptionContext[r]; + EncryptionContext.SubsetOfESDKEncryptionContextIsESDKEncryptionContext(encryptionContext, requiredEncryptionContextMap); - //= compliance/client-apis/encrypt.txt#2.6.2 - //# After serializing the message header body, this operation MUST - //# calculate an authentication tag (../data-format/message- - //# header.md#authentication-tag) over the message header body. - var headerAuth :- BuildHeaderAuthTag(suite, derivedDataKeys.dataKey, rawHeader, serializedReqEncryptionContext, crypto); - - var header := Header.HeaderInfo( - body := body, - rawHeader := rawHeader, - encryptionContext := encryptionContext, - suite := suite, - headerAuth := headerAuth - ); + var canonicalReqEncryptionContext := + EncryptionContext.GetCanonicalEncryptionContext(requiredEncryptionContextMap); + var serializedReqEncryptionContext := + EncryptionContext.WriteEmptyEcOrWriteAAD(canonicalReqEncryptionContext); - return Success(header); + //= compliance/client-apis/encrypt.txt#2.6.2 + //# Before encrypting input plaintext, this operation MUST serialize the + //# message header body (../data-format/message-header.md). + var rawHeader := Header.WriteHeaderBody(body); + + //= compliance/client-apis/encrypt.txt#2.6.2 + //# After serializing the message header body, this operation MUST + //# calculate an authentication tag (../data-format/message- + //# header.md#authentication-tag) over the message header body. + var headerAuth :- BuildHeaderAuthTag(suite, derivedDataKeys.dataKey, rawHeader, serializedReqEncryptionContext, crypto); + + var header := Header.HeaderInfo( + body := body, + rawHeader := rawHeader, + encryptionContext := encryptionContext, + suite := suite, + headerAuth := headerAuth + ); + + return Success(header); } method BuildHeaderBody( @@ -509,51 +509,51 @@ module EncryptDecryptHelpers { suiteData: Option> ) returns (res: HeaderTypes.HeaderBody) - requires !suite.commitment.IDENTITY? + requires !suite.commitment.IDENTITY? + + //= compliance/data-format/message-header.txt#2.5.2 + //= type=implication + //# The length of the suite data field MUST be equal to + //# the Algorithm Suite Data Length (../framework/algorithm- + //# suites.md#algorithm-suite-data-length) value of the algorithm suite + //# (../framework/algorithm-suites.md) specified by the Algorithm Suite + //# ID (Section 2.5.1.5) field. + requires suite.commitment.HKDF? ==> + && suiteData.Some? + && |suiteData.value| == suite.commitment.HKDF.outputKeyLength as int - //= compliance/data-format/message-header.txt#2.5.2 - //= type=implication - //# The length of the suite data field MUST be equal to - //# the Algorithm Suite Data Length (../framework/algorithm- - //# suites.md#algorithm-suite-data-length) value of the algorithm suite - //# (../framework/algorithm-suites.md) specified by the Algorithm Suite - //# ID (Section 2.5.1.5) field. - requires suite.commitment.HKDF? ==> - && suiteData.Some? - && |suiteData.value| == suite.commitment.HKDF.outputKeyLength as int - - // This ensures that our header is internally consistent with respect to - // commitment (e.g. creating the right header version for the given suite) - ensures Header.HeaderVersionSupportsCommitment?(suite, res) - - // Correct construction of V2 headers - ensures - && suite.commitment.HKDF? - ==> - && res == HeaderTypes.HeaderBody.V2HeaderBody( - algorithmSuite := suite, - messageId := messageId, - encryptionContext := encryptionContext, - encryptedDataKeys := encryptedDataKeys, - contentType := HeaderTypes.ContentType.Framed, - frameLength := frameLength, - suiteData := suiteData.value - ) + // This ensures that our header is internally consistent with respect to + // commitment (e.g. creating the right header version for the given suite) + ensures Header.HeaderVersionSupportsCommitment?(suite, res) - // Correct construction of V1 headers - ensures - && suite.commitment.None? - ==> - && res == HeaderTypes.HeaderBody.V1HeaderBody( - messageType := HeaderTypes.MessageType.TYPE_CUSTOMER_AED, - algorithmSuite := suite, - messageId := messageId, - encryptionContext := encryptionContext, - encryptedDataKeys := encryptedDataKeys, - contentType := HeaderTypes.ContentType.Framed, - headerIvLength := SerializableTypes.GetIvLength(suite) as nat, - frameLength := frameLength - ) + // Correct construction of V2 headers + ensures + && suite.commitment.HKDF? + ==> + && res == HeaderTypes.HeaderBody.V2HeaderBody( + algorithmSuite := suite, + messageId := messageId, + encryptionContext := encryptionContext, + encryptedDataKeys := encryptedDataKeys, + contentType := HeaderTypes.ContentType.Framed, + frameLength := frameLength, + suiteData := suiteData.value + ) + + // Correct construction of V1 headers + ensures + && suite.commitment.None? + ==> + && res == HeaderTypes.HeaderBody.V1HeaderBody( + messageType := HeaderTypes.MessageType.TYPE_CUSTOMER_AED, + algorithmSuite := suite, + messageId := messageId, + encryptionContext := encryptionContext, + encryptedDataKeys := encryptedDataKeys, + contentType := HeaderTypes.ContentType.Framed, + headerIvLength := SerializableTypes.GetIvLength(suite) as nat, + frameLength := frameLength + ) { reveal Header.HeaderVersionSupportsCommitment?(); @@ -564,24 +564,24 @@ module EncryptDecryptHelpers { match suite.commitment { case None(_) => return HeaderTypes.HeaderBody.V1HeaderBody( - messageType := HeaderTypes.MessageType.TYPE_CUSTOMER_AED, - algorithmSuite := suite, - messageId := messageId, - encryptionContext := encryptionContext, - encryptedDataKeys := encryptedDataKeys, - contentType := contentType, - headerIvLength := SerializableTypes.GetIvLength(suite) as nat, - frameLength := frameLength - ); + messageType := HeaderTypes.MessageType.TYPE_CUSTOMER_AED, + algorithmSuite := suite, + messageId := messageId, + encryptionContext := encryptionContext, + encryptedDataKeys := encryptedDataKeys, + contentType := contentType, + headerIvLength := SerializableTypes.GetIvLength(suite) as nat, + frameLength := frameLength + ); case HKDF(_) => return HeaderTypes.HeaderBody.V2HeaderBody( - algorithmSuite := suite, - messageId := messageId, - encryptionContext := encryptionContext, - encryptedDataKeys := encryptedDataKeys, - contentType := contentType, - frameLength := frameLength, - suiteData := suiteData.value - ); + algorithmSuite := suite, + messageId := messageId, + encryptionContext := encryptionContext, + encryptedDataKeys := encryptedDataKeys, + contentType := contentType, + frameLength := frameLength, + suiteData := suiteData.value + ); } } @@ -608,7 +608,7 @@ module EncryptDecryptHelpers { //# with the following inputs: var keyLength := SerializableTypes.GetEncryptKeyLength(suite) as nat; :- Need(|dataKey| == keyLength, - Types.AwsEncryptionSdkException( message := "Incorrect data key length")); + Types.AwsEncryptionSdkException( message := "Incorrect data key length")); var ivLength := SerializableTypes.GetIvLength(suite); //#* The IV has a value of 0. @@ -622,17 +622,17 @@ module EncryptDecryptHelpers { key := dataKey, //#* The plaintext is an empty byte array msg := [], - //#* The AAD MUST be the concatenation of the serialized + //#* The AAD MUST be the concatenation of the serialized //# [message header body](../data-format/message-header.md#header-body) //# and the serialization of encryption context to only authenticate. aad := rawHeader + serializedReqEncryptionContext ) ); var encryptionOutput :- maybeEncryptionOutput - .MapFailure(e => Types.AwsCryptographyPrimitives(e)); + .MapFailure(e => Types.AwsCryptographyPrimitives(e)); var headerAuth := HeaderTypes.HeaderAuth.AESMac( - headerIv := iv, - headerAuthTag := encryptionOutput.authTag + headerIv := iv, + headerAuthTag := encryptionOutput.authTag ); return Success(headerAuth); } @@ -651,18 +651,18 @@ module EncryptDecryptHelpers { ensures cmm.ValidState() && mpl.ValidState() ensures res.Success? ==> - && mpl.EncryptionMaterialsHasPlaintextDataKey(res.value).Success? - && !res.value.algorithmSuite.commitment.IDENTITY?; + && mpl.EncryptionMaterialsHasPlaintextDataKey(res.value).Success? + && !res.value.algorithmSuite.commitment.IDENTITY?; ensures res.Success? ==> - && SerializableTypes.IsESDKEncryptionContext(res.value.encryptionContext) + && SerializableTypes.IsESDKEncryptionContext(res.value.encryptionContext) ensures res.Success? ==> - && HasUint16Len(res.value.encryptedDataKeys) + && HasUint16Len(res.value.encryptedDataKeys) ensures res.Success? ==> - && forall edk | edk in res.value.encryptedDataKeys - :: SerializableTypes.IsESDKEncryptedDataKey(edk) + && forall edk | edk in res.value.encryptedDataKeys + :: SerializableTypes.IsESDKEncryptedDataKey(edk) { var encMatRequest := MPL.GetEncryptionMaterialsInput( encryptionContext := encryptionContext, @@ -679,7 +679,7 @@ module EncryptDecryptHelpers { //# encryption-materials) on a CMM (../framework/cmm-interface.md). var getEncMatResult := cmm.GetEncryptionMaterials(encMatRequest); var output :- getEncMatResult - .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); + .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); var materials := output.encryptionMaterials; @@ -691,25 +691,25 @@ module EncryptDecryptHelpers { //# by the commitment policy (client.md#commitment-policy) configured in //# the client (client.md) encrypt MUST yield an error. var _ :- mpl - .ValidateCommitmentPolicyOnEncrypt(MPL.ValidateCommitmentPolicyOnEncryptInput( - algorithm := materials.algorithmSuite.id, - commitmentPolicy := MPL.CommitmentPolicy.ESDK(commitmentPolicy) - )) - .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); + .ValidateCommitmentPolicyOnEncrypt(MPL.ValidateCommitmentPolicyOnEncryptInput( + algorithm := materials.algorithmSuite.id, + commitmentPolicy := MPL.CommitmentPolicy.ESDK(commitmentPolicy) + )) + .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); var _ :- mpl.EncryptionMaterialsHasPlaintextDataKey(materials) - .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); + .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); :- Need( SerializableTypes.IsESDKEncryptionContext(materials.encryptionContext), Types.AwsEncryptionSdkException( message := "CMM failed to return serializable encryption materials.") ); :- Need(HasUint16Len(materials.encryptedDataKeys), - Types.AwsEncryptionSdkException( - message := "CMM returned EDKs that exceed the allowed maximum.")); + Types.AwsEncryptionSdkException( + message := "CMM returned EDKs that exceed the allowed maximum.")); :- Need(forall edk | edk in materials.encryptedDataKeys - :: SerializableTypes.IsESDKEncryptedDataKey(edk), - Types.AwsEncryptionSdkException( - message := "CMM returned non-serializable encrypted data key.")); + :: SerializableTypes.IsESDKEncryptedDataKey(edk), + Types.AwsEncryptionSdkException( + message := "CMM returned non-serializable encrypted data key.")); return Success(materials); } @@ -728,14 +728,14 @@ module EncryptDecryptHelpers { ensures cmm.ValidState() && mpl.ValidState() ensures res.Success? ==> - && mpl.DecryptionMaterialsWithPlaintextDataKey(res.value).Success? - && SerializableTypes.IsESDKEncryptionContext(res.value.encryptionContext) + && mpl.DecryptionMaterialsWithPlaintextDataKey(res.value).Success? + && SerializableTypes.IsESDKEncryptionContext(res.value.encryptionContext) ensures old(cmm.History.DecryptMaterials) < cmm.History.DecryptMaterials ensures res.Success? ==> - && Seq.Last(cmm.History.DecryptMaterials).output.Success? - && Seq.Last(cmm.History.DecryptMaterials).output.value.decryptionMaterials == res.value + && Seq.Last(cmm.History.DecryptMaterials).output.Success? + && Seq.Last(cmm.History.DecryptMaterials).output.value.decryptionMaterials == res.value { var encryptionContext := EncryptionContext.GetEncryptionContext(headerBody.encryptionContext); //= compliance/client-apis/decrypt.txt#2.7.2 @@ -761,7 +761,7 @@ module EncryptDecryptHelpers { ); var decMatResult := cmm.DecryptMaterials(decMatRequest); var output :- decMatResult - .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); + .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); var materials := output.decryptionMaterials; //= compliance/client-apis/decrypt.txt#2.7.2 @@ -770,50 +770,50 @@ module EncryptDecryptHelpers { //# (client.md#commitment-policy) configured in the client (client.md) //# decrypt MUST yield an error. var _ :- mpl - .ValidateCommitmentPolicyOnDecrypt(MPL.ValidateCommitmentPolicyOnDecryptInput( - algorithm := materials.algorithmSuite.id, - commitmentPolicy := MPL.CommitmentPolicy.ESDK(commitmentPolicy) - )) - .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); + .ValidateCommitmentPolicyOnDecrypt(MPL.ValidateCommitmentPolicyOnDecryptInput( + algorithm := materials.algorithmSuite.id, + commitmentPolicy := MPL.CommitmentPolicy.ESDK(commitmentPolicy) + )) + .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); var _ :- mpl.DecryptionMaterialsWithPlaintextDataKey(materials) - .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); + .MapFailure(e => Types.AwsCryptographyMaterialProviders(e)); :- Need(SerializableTypes.IsESDKEncryptionContext(materials.encryptionContext), - Types.AwsEncryptionSdkException( - message := "CMM failed to return serializable encryption materials.")); + Types.AwsEncryptionSdkException( + message := "CMM failed to return serializable encryption materials.")); return Success(materials); } /* - * Ensures that the suite data contained in the header of a message matches - * the expected suite data - */ + * Ensures that the suite data contained in the header of a message matches + * the expected suite data + */ method ValidateSuiteData( suite: MPL.AlgorithmSuiteInfo, header: HeaderTypes.HeaderBody, expectedSuiteData: seq ) returns (res: Result<(), Types.Error>) - // Validating suite data is only relevant for suites with commitment - requires suite.commitment.HKDF? + // Validating suite data is only relevant for suites with commitment + requires suite.commitment.HKDF? - // We can't dereference the 'suiteData' portion of the body, which only exists - // in V2 headers, unless we know we have a V2HeaderBody - requires header.V2HeaderBody? + // We can't dereference the 'suiteData' portion of the body, which only exists + // in V2 headers, unless we know we have a V2HeaderBody + requires header.V2HeaderBody? - //= compliance/client-apis/decrypt.txt#2.7.2 - //= type=implication - //# The - //# derived commit key MUST equal the commit key stored in the message - //# header. - ensures res.Success? ==> header.suiteData == expectedSuiteData - - // Failure cases - ensures header.suiteData != expectedSuiteData ==> res.Failure? - ensures |header.suiteData| != suite.commitment.HKDF.outputKeyLength as int ==> res.Failure? + //= compliance/client-apis/decrypt.txt#2.7.2 + //= type=implication + //# The + //# derived commit key MUST equal the commit key stored in the message + //# header. + ensures res.Success? ==> header.suiteData == expectedSuiteData + + // Failure cases + ensures header.suiteData != expectedSuiteData ==> res.Failure? + ensures |header.suiteData| != suite.commitment.HKDF.outputKeyLength as int ==> res.Failure? { :- Need( |header.suiteData| == suite.commitment.HKDF.outputKeyLength as int, @@ -846,25 +846,25 @@ module EncryptDecryptHelpers { requires buffer.start <= |buffer.bytes| requires |key| == SerializableTypes.GetEncryptKeyLength(header.suite) as nat ensures res.Success? ==> - var (plaintext, tail) := res.value; - && buffer.start <= tail.start <= |buffer.bytes| - && SerializeFunctions.CorrectlyReadRange(buffer, tail, buffer.bytes[buffer.start..tail.start]) + var (plaintext, tail) := res.value; + && buffer.start <= tail.start <= |buffer.bytes| + && SerializeFunctions.CorrectlyReadRange(buffer, tail, buffer.bytes[buffer.start..tail.start]) { - assert CorrectlyReadRange(buffer, buffer, []) by { reveal CorrectlyReadRange(); } - CorrectlyReadByteRange(buffer, buffer, []); + assert CorrectlyReadRange(buffer, buffer, []) by { reveal CorrectlyReadRange(); } + CorrectlyReadByteRange(buffer, buffer, []); - var messageBody :- MessageBody.ReadFramedMessageBody(buffer, header, [], buffer) - .MapFailure(MapSerializeFailure(": ReadFramedMessageBody")); + var messageBody :- MessageBody.ReadFramedMessageBody(buffer, header, [], buffer) + .MapFailure(MapSerializeFailure(": ReadFramedMessageBody")); - CorrectlyReadByteRange(buffer, messageBody.tail, MessageBody.WriteFramedMessageBody(messageBody.data)); + CorrectlyReadByteRange(buffer, messageBody.tail, MessageBody.WriteFramedMessageBody(messageBody.data)); - assert header == messageBody.data.finalFrame.header; - assert |key| == SerializableTypes.GetEncryptKeyLength(messageBody.data.finalFrame.header.suite) as nat; + assert header == messageBody.data.finalFrame.header; + assert |key| == SerializableTypes.GetEncryptKeyLength(messageBody.data.finalFrame.header.suite) as nat; - var plaintext :- MessageBody.DecryptFramedMessageBody(messageBody.data, key, crypto); - var messageBodyTail := messageBody.tail; + var plaintext :- MessageBody.DecryptFramedMessageBody(messageBody.data, key, crypto); + var messageBodyTail := messageBody.tail; - return Success((plaintext, messageBodyTail)); + return Success((plaintext, messageBodyTail)); } method {:vcs_split_on_every_assert} ReadAndDecryptNonFramedMessageBody( @@ -882,25 +882,25 @@ module EncryptDecryptHelpers { requires buffer.start <= |buffer.bytes| requires |key| == SerializableTypes.GetEncryptKeyLength(header.suite) as nat ensures res.Success? ==> - var (plaintext, tail) := res.value; - && buffer.start <= tail.start <= |buffer.bytes| - && SerializeFunctions.CorrectlyReadRange(buffer, tail, buffer.bytes[buffer.start..tail.start]) + var (plaintext, tail) := res.value; + && buffer.start <= tail.start <= |buffer.bytes| + && SerializeFunctions.CorrectlyReadRange(buffer, tail, buffer.bytes[buffer.start..tail.start]) { - var messageBody :- MessageBody.ReadNonFramedMessageBody(buffer, header) - .MapFailure(MapSerializeFailure(": ReadNonFramedMessageBody")); + var messageBody :- MessageBody.ReadNonFramedMessageBody(buffer, header) + .MapFailure(MapSerializeFailure(": ReadNonFramedMessageBody")); - CorrectlyReadByteRange(buffer, messageBody.tail, MessageBody.WriteNonFramedMessageBody(messageBody.data)); + CorrectlyReadByteRange(buffer, messageBody.tail, MessageBody.WriteNonFramedMessageBody(messageBody.data)); - var frame: Frames.Frame := messageBody.data; - assert frame.NonFramed?; + var frame: Frames.Frame := messageBody.data; + assert frame.NonFramed?; - assert header == frame.header; - assert |key| == SerializableTypes.GetEncryptKeyLength(frame.header.suite) as nat; + assert header == frame.header; + assert |key| == SerializableTypes.GetEncryptKeyLength(frame.header.suite) as nat; - var plaintext :- MessageBody.DecryptFrame(frame, key, crypto); - var messageBodyTail := messageBody.tail; + var plaintext :- MessageBody.DecryptFrame(frame, key, crypto); + var messageBodyTail := messageBody.tail; - return Success((plaintext, messageBodyTail)); + return Success((plaintext, messageBodyTail)); } } diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Index.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Index.dfy index bdb79f323..a64fbfa91 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Index.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Index.dfy @@ -25,13 +25,13 @@ module {:extern "software.amazon.cryptography.encryptionsdk.internaldafny" } ESD { var maybeCrypto := Primitives.AtomicPrimitives(); var cryptoX: AwsCryptographyPrimitivesTypes.IAwsCryptographicPrimitivesClient :- maybeCrypto - .MapFailure(e => AwsCryptographyPrimitives(e)); + .MapFailure(e => AwsCryptographyPrimitives(e)); assert cryptoX is Primitives.AtomicPrimitivesClient; var crypto := cryptoX as Primitives.AtomicPrimitivesClient; var maybeMpl := MaterialProviders.MaterialProviders(); var mplX: AwsCryptographyMaterialProvidersTypes.IAwsCryptographicMaterialProvidersClient :- maybeMpl - .MapFailure(e => AwsCryptographyMaterialProviders(e)); + .MapFailure(e => AwsCryptographyMaterialProviders(e)); assert mplX is MaterialProviders.MaterialProvidersClient; var mpl := mplX as MaterialProviders.MaterialProvidersClient; diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/KeyDerivation.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/KeyDerivation.dfy index 2456f756e..17ce3598f 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/KeyDerivation.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/KeyDerivation.dfy @@ -42,9 +42,9 @@ module KeyDerivation { requires suite.commitment.None? requires suite.kdf.HKDF? - ==> - && |plaintextDataKey| == suite.kdf.HKDF.inputKeyLength as nat - && suite.kdf.HKDF.outputKeyLength == SerializableTypes.GetEncryptKeyLength(suite) + ==> + && |plaintextDataKey| == suite.kdf.HKDF.inputKeyLength as nat + && suite.kdf.HKDF.outputKeyLength == SerializableTypes.GetEncryptKeyLength(suite) requires suite.kdf.IDENTITY? ==> |plaintextDataKey| == SerializableTypes.GetEncryptKeyLength(suite) as nat requires crypto.ValidState() @@ -91,7 +91,7 @@ module KeyDerivation { ikm := plaintextDataKey, info := suite.binaryId, expectedLength := hkdf.outputKeyLength - ); + ); } var maybeDerivedKey := crypto.Hkdf(hkdfInput); var derivedKey :- maybeDerivedKey.MapFailure(e => Types.AwsCryptographyPrimitives(e)); @@ -100,7 +100,7 @@ module KeyDerivation { } case None => { return Failure(Types.AwsEncryptionSdkException( - message := "None is not a valid Key Derivation Function")); + message := "None is not a valid Key Derivation Function")); } } } @@ -169,8 +169,8 @@ module KeyDerivation { //# data key using the commit key derivation (../framework/algorithm- //# suites.md#algorithm-suites-commit-key-derivation-settings). ensures res.Success? ==> - && res.value.commitmentKey.Some? - && |res.value.commitmentKey.value| == suite.commitment.HKDF.outputKeyLength as nat + && res.value.commitmentKey.Some? + && |res.value.commitmentKey.value| == suite.commitment.HKDF.outputKeyLength as nat ensures res.Success? ==> |res.value.dataKey| == SerializableTypes.GetEncryptKeyLength(suite) as nat @@ -187,7 +187,7 @@ module KeyDerivation { var maybePseudoRandomKey := crypto.HkdfExtract(hkdfExtractInput); var pseudoRandomKey :- maybePseudoRandomKey - .MapFailure(e => Types.AwsCryptographyPrimitives(e)); + .MapFailure(e => Types.AwsCryptographyPrimitives(e)); var encryptKeyInput := AwsCryptographyPrimitivesTypes.HkdfExpandInput( digestAlgorithm := digest, @@ -196,22 +196,22 @@ module KeyDerivation { expectedLength := suite.kdf.HKDF.outputKeyLength ); var commitKeyInput := encryptKeyInput.( - info := COMMIT_LABEL, - expectedLength := suite.commitment.HKDF.outputKeyLength + info := COMMIT_LABEL, + expectedLength := suite.commitment.HKDF.outputKeyLength ); var maybeEncryptKey := crypto.HkdfExpand(encryptKeyInput); var maybeCommitKey := crypto.HkdfExpand(commitKeyInput); var encryptKey :- maybeEncryptKey - .MapFailure(e => Types.AwsCryptographyPrimitives(e)); + .MapFailure(e => Types.AwsCryptographyPrimitives(e)); var commitKey :- maybeCommitKey - .MapFailure(e => Types.AwsCryptographyPrimitives(e)); + .MapFailure(e => Types.AwsCryptographyPrimitives(e)); return Success(ExpandedKeyMaterial( - dataKey:=encryptKey, - commitmentKey:=Some(commitKey) - )); + dataKey:=encryptKey, + commitmentKey:=Some(commitKey) + )); } /* @@ -238,25 +238,25 @@ module KeyDerivation { ensures crypto.ValidState() ensures res.Success? ==> - |res.value.dataKey| == SerializableTypes.GetEncryptKeyLength(suite) as nat + |res.value.dataKey| == SerializableTypes.GetEncryptKeyLength(suite) as nat ensures && res.Success? && suite.commitment.None? - ==> - res.value.commitmentKey.None? + ==> + res.value.commitmentKey.None? ensures && res.Success? && suite.commitment.HKDF? - ==> - && res.value.commitmentKey.Some? - && |res.value.commitmentKey.value| == suite.commitment.HKDF.outputKeyLength as nat + ==> + && res.value.commitmentKey.Some? + && |res.value.commitmentKey.value| == suite.commitment.HKDF.outputKeyLength as nat { var keys : ExpandedKeyMaterial; if (suite.messageVersion == 2) { :- Need(suite.commitment.HKDF? && suite.kdf == suite.commitment, Types.AwsEncryptionSdkException( - message := "Suites with message version 2 must have commitment")); + message := "Suites with message version 2 must have commitment")); :- Need( && SerializableTypes.GetEncryptKeyLength(suite) == suite.kdf.HKDF.outputKeyLength @@ -266,26 +266,26 @@ module KeyDerivation { keys :- ExpandKeyMaterial(messageId, plaintextKey, suite, crypto); } else if (suite.messageVersion == 1) { :- Need(suite.commitment.None?, Types.AwsEncryptionSdkException( - message := "Suites with message version 1 must not have commitment")); + message := "Suites with message version 1 must not have commitment")); :- Need(match suite.kdf { - case IDENTITY(i) => |plaintextKey| == SerializableTypes.GetEncryptKeyLength(suite) as nat - case HKDF(hkdf) => - && |plaintextKey| == suite.kdf.HKDF.inputKeyLength as nat - && suite.kdf.HKDF.outputKeyLength == SerializableTypes.GetEncryptKeyLength(suite) - case None => false - }, Types.AwsEncryptionSdkException( - message := "Suites with message version 1 must not have commitment")); - - if netV4_0_0_RetryPolicy == Types.NetV4_0_0_RetryPolicy.ALLOW_RETRY && onNetV4Retry { - keys :- DeriveKey(messageId, plaintextKey, suite, crypto, true); - } else { - keys :- DeriveKey(messageId, plaintextKey, suite, crypto, false); - } - + case IDENTITY(i) => |plaintextKey| == SerializableTypes.GetEncryptKeyLength(suite) as nat + case HKDF(hkdf) => + && |plaintextKey| == suite.kdf.HKDF.inputKeyLength as nat + && suite.kdf.HKDF.outputKeyLength == SerializableTypes.GetEncryptKeyLength(suite) + case None => false + }, Types.AwsEncryptionSdkException( + message := "Suites with message version 1 must not have commitment")); + + if netV4_0_0_RetryPolicy == Types.NetV4_0_0_RetryPolicy.ALLOW_RETRY && onNetV4Retry { + keys :- DeriveKey(messageId, plaintextKey, suite, crypto, true); + } else { + keys :- DeriveKey(messageId, plaintextKey, suite, crypto, false); + } + } else { return Failure(Types.AwsEncryptionSdkException( - message := "Unknown message version")); + message := "Unknown message version")); } return Success(keys); diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/MessageBody.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/MessageBody.dfy index 96d7261b1..a296fb99a 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/MessageBody.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/MessageBody.dfy @@ -77,7 +77,7 @@ module MessageBody { //# The IV MUST be a unique IV within the message. lemma IVSeqDistinct(suite: MPL.AlgorithmSuiteInfo, m: uint32, n: uint32) requires m != n - requires 4 <= SerializableTypes.GetIvLength(suite) + requires 4 <= SerializableTypes.GetIvLength(suite) ensures IVSeq(suite, m) != IVSeq(suite, n) { var paddingLength := SerializableTypes.GetIvLength(suite) as nat - 4; @@ -101,8 +101,8 @@ module MessageBody { } type MessageRegularFrames = regularFrames: seq - | IsMessageRegularFrames(regularFrames) - witness * + | IsMessageRegularFrames(regularFrames) + witness * predicate MessageFramesAreMonotonic(frames: seq){ if |frames| == 0 then true @@ -116,10 +116,10 @@ module MessageBody { predicate MessageFramesAreForTheSameMessage(frames: seq){ forall i - // This excludes the First frame in the seq - // because all headers are definitionally equal for `[]` and `[frame]`. - | 0 < i < |frames| - :: Seq.First(frames).header == frames[i].header + // This excludes the First frame in the seq + // because all headers are definitionally equal for `[]` and `[frame]`. + | 0 < i < |frames| + :: Seq.First(frames).header == frames[i].header } predicate IsMessageRegularFrames(regularFrames: seq) { @@ -132,18 +132,18 @@ module MessageBody { //# * The number of frames in a single message MUST be less than or //# equal to "2^32 - 1". && 0 <= |regularFrames| < ENDFRAME_SEQUENCE_NUMBER as nat - // The sequence number MUST be monotonic - // - //= compliance/data-format/message-body.txt#2.5.2.1.1 - //= type=implication - //# Framed Data MUST start at Sequence Number 1. - // - //= compliance/data-format/message-body.txt#2.5.2.1.1 - //= type=implication - //# Subsequent frames MUST be in order and MUST contain an increment of 1 - //# from the previous frame. + // The sequence number MUST be monotonic + // + //= compliance/data-format/message-body.txt#2.5.2.1.1 + //= type=implication + //# Framed Data MUST start at Sequence Number 1. + // + //= compliance/data-format/message-body.txt#2.5.2.1.1 + //= type=implication + //# Subsequent frames MUST be in order and MUST contain an increment of 1 + //# from the previous frame. && MessageFramesAreMonotonic(regularFrames) - // All frames MUST all be from the same messages i.e. the same header + // All frames MUST all be from the same messages i.e. the same header && MessageFramesAreForTheSameMessage(regularFrames) } @@ -158,27 +158,27 @@ module MessageBody { ) type FramedMessage = body: FramedMessageBody - | - //= compliance/data-format/message-body.txt#2.5.2.2.2 - //= type=implication - //# The Final Frame Sequence number MUST be equal to the total number of - //# frames in the Framed Data. - && MessageFramesAreMonotonic(body.regularFrames + [body.finalFrame]) - && MessageFramesAreForTheSameMessage(body.regularFrames + [body.finalFrame]) - witness * + | + //= compliance/data-format/message-body.txt#2.5.2.2.2 + //= type=implication + //# The Final Frame Sequence number MUST be equal to the total number of + //# frames in the Framed Data. + && MessageFramesAreMonotonic(body.regularFrames + [body.finalFrame]) + && MessageFramesAreForTheSameMessage(body.regularFrames + [body.finalFrame]) + witness * type MessageFrame = frame: Frames.Frame - | - || Frames.IsFinalFrame(frame) - || Frames.IsRegularFrame(frame) - witness * + | + || Frames.IsFinalFrame(frame) + || Frames.IsRegularFrame(frame) + witness * type Frame = frame: Frames.Frame - | - || Frames.IsFinalFrame(frame) - || Frames.IsRegularFrame(frame) - || Frames.NonFramed?(frame) - witness * + | + || Frames.IsFinalFrame(frame) + || Frames.IsRegularFrame(frame) + || Frames.NonFramed?(frame) + witness * lemma LemmaAddingNextRegularFrame( regularFrames: MessageRegularFrames, @@ -207,25 +207,25 @@ module MessageBody { ensures crypto.ValidState() ensures match result - case Failure(e) => true - case Success(body) => - // add final - && (forall i, j, frame: Frames.Frame, callEvent - | - && 0 <= i < |body.regularFrames| - && |old(crypto.History.AESEncrypt)| < j < |crypto.History.AESEncrypt| - 1 - && i == j - |old(crypto.History.AESEncrypt)| - && frame == body.regularFrames[i] - && callEvent == crypto.History.AESEncrypt[j] - :: - && callEvent.input.key == key - && callEvent.output.Success? - && frame.header == header - && frame.seqNum as nat == i + 1 - && frame.iv == callEvent.input.iv - && frame.encContent == callEvent.output.value.cipherText - && frame.authTag == callEvent.output.value.authTag - ) + case Failure(e) => true + case Success(body) => + // add final + && (forall i, j, frame: Frames.Frame, callEvent + | + && 0 <= i < |body.regularFrames| + && |old(crypto.History.AESEncrypt)| < j < |crypto.History.AESEncrypt| - 1 + && i == j - |old(crypto.History.AESEncrypt)| + && frame == body.regularFrames[i] + && callEvent == crypto.History.AESEncrypt[j] + :: + && callEvent.input.key == key + && callEvent.output.Success? + && frame.header == header + && frame.seqNum as nat == i + 1 + && frame.iv == callEvent.input.iv + && frame.encContent == callEvent.output.value.cipherText + && frame.authTag == callEvent.output.value.authTag + ) { var n : int, sequenceNumber := 0, START_SEQUENCE_NUMBER; var regularFrames: MessageRegularFrames := []; @@ -250,29 +250,29 @@ module MessageBody { invariant START_SEQUENCE_NUMBER <= sequenceNumber <= ENDFRAME_SEQUENCE_NUMBER invariant |regularFrames| == (sequenceNumber - START_SEQUENCE_NUMBER) as nat invariant |crypto.History.AESEncrypt| - |old(crypto.History.AESEncrypt)| - == |regularFrames| + == |regularFrames| invariant 0 < |regularFrames| ==> Seq.First(regularFrames).header == header; invariant IsMessageRegularFrames(regularFrames) invariant forall i: nat, j: nat, frame: Frames.Frame, callEvent - | - && 0 <= i < |regularFrames| - && |old(crypto.History.AESEncrypt)| <= j < |crypto.History.AESEncrypt| - && i == j - |old(crypto.History.AESEncrypt)| - && frame == regularFrames[i] - && callEvent == crypto.History.AESEncrypt[j] - :: - && callEvent.input.key == key - && callEvent.output.Success? - && frame.header == header - && frame.seqNum as nat == i + 1 - && frame.iv == callEvent.input.iv - && frame.encContent == callEvent.output.value.cipherText - && frame.authTag == callEvent.output.value.authTag + | + && 0 <= i < |regularFrames| + && |old(crypto.History.AESEncrypt)| <= j < |crypto.History.AESEncrypt| + && i == j - |old(crypto.History.AESEncrypt)| + && frame == regularFrames[i] + && callEvent == crypto.History.AESEncrypt[j] + :: + && callEvent.input.key == key + && callEvent.output.Success? + && frame.header == header + && frame.seqNum as nat == i + 1 + && frame.iv == callEvent.input.iv + && frame.encContent == callEvent.output.value.cipherText + && frame.authTag == callEvent.output.value.authTag { :- Need(sequenceNumber < ENDFRAME_SEQUENCE_NUMBER, Types.AwsEncryptionSdkException( - message := "too many frames")); + message := "too many frames")); var plaintextFrame := plaintext[n..n + header.body.frameLength as nat]; //= compliance/client-apis/encrypt.txt#2.7 @@ -332,9 +332,9 @@ module MessageBody { ); result := Success(FramedMessageBody( - regularFrames := regularFrames, - finalFrame := finalFrame - )); + regularFrames := regularFrames, + finalFrame := finalFrame + )); } method EncryptRegularFrame( @@ -369,96 +369,96 @@ module MessageBody { ensures crypto.History.AESEncrypt == old(crypto.History.AESEncrypt) + [Seq.Last(crypto.History.AESEncrypt)] ensures match res - case Failure(e) => true - case Success(frame) => - && Seq.Last(crypto.History.AESEncrypt).output.Success? - && var encryptionOutput := Seq.Last(crypto.History.AESEncrypt).output.value; - && var encryptionInput := Seq.Last(crypto.History.AESEncrypt).input; - - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# To construct a regular or final frame that represents the next frame - //# in the encrypted message's body, this operation MUST calculate the - //# encrypted content and an authentication tag using the authenticated - //# encryption algorithm (../framework/algorithm-suites.md#encryption- - //# algorithm) specified by the algorithm suite (../framework/algorithm- - //# suites.md), with the following inputs: - && encryptionInput.encAlg == header.suite.encrypt.AES_GCM - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * The AAD is the serialized message body AAD (../data-format/ - //# message-body-aad.md), constructed as follows: - && encryptionInput.aad == BodyAAD( - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# - The message ID (../data-format/message-body-aad.md#message-id) - //# is the same as the message ID (../data-frame/message- - //# header.md#message-id) serialized in the header of this message. - header.body.messageId, - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# - The Body AAD Content (../data-format/message-body-aad.md#body- - //# aad-content) depends on whether the thing being encrypted is a - //# regular frame or final frame. Refer to Message Body AAD - //# (../data-format/message-body-aad.md) specification for more - //# information. - AADRegularFrame, - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# - The sequence number (../data-format/message-body- - //# aad.md#sequence-number) is the sequence number of the frame - //# being encrypted. - sequenceNumber, - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# - The content length (../data-format/message-body-aad.md#content- - //# length) MUST have a value equal to the length of the plaintext - //# being encrypted. - |plaintext| as uint64 - ) - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * The IV is the sequence number (../data-format/message-body- - //# aad.md#sequence-number) used in the message body AAD above, padded - //# to the IV length (../data-format/message-header.md#iv-length). - && encryptionInput.iv == IVSeq(header.suite, sequenceNumber) - - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * The cipherkey is the derived data key - && encryptionInput.key == key - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * The plaintext is the next subsequence of consumable plaintext - //# bytes that have not yet been encrypted. - && encryptionInput.msg == plaintext - - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# This operation MUST serialize a regular frame or final frame with the - //# following specifics: - && frame.header == header - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * Sequence Number (../data-format/message-body.md#sequence-number): - //# MUST be the sequence number of this frame, as determined above. - && frame.seqNum == sequenceNumber - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * IV (../data-format/message-body.md#iv): MUST be the IV used when - //# calculating the encrypted content above - && frame.iv == encryptionInput.iv - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * Encrypted Content (../data-format/message-body.md#encrypted- - //# content): MUST be the encrypted content calculated above. - && frame.encContent == encryptionOutput.cipherText - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * Authentication Tag (../data-format/message-body.md#authentication- - //# tag): MUST be the authentication tag output when calculating the - //# encrypted content above. - && frame.authTag == encryptionOutput.authTag + case Failure(e) => true + case Success(frame) => + && Seq.Last(crypto.History.AESEncrypt).output.Success? + && var encryptionOutput := Seq.Last(crypto.History.AESEncrypt).output.value; + && var encryptionInput := Seq.Last(crypto.History.AESEncrypt).input; + + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# To construct a regular or final frame that represents the next frame + //# in the encrypted message's body, this operation MUST calculate the + //# encrypted content and an authentication tag using the authenticated + //# encryption algorithm (../framework/algorithm-suites.md#encryption- + //# algorithm) specified by the algorithm suite (../framework/algorithm- + //# suites.md), with the following inputs: + && encryptionInput.encAlg == header.suite.encrypt.AES_GCM + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * The AAD is the serialized message body AAD (../data-format/ + //# message-body-aad.md), constructed as follows: + && encryptionInput.aad == BodyAAD( + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# - The message ID (../data-format/message-body-aad.md#message-id) + //# is the same as the message ID (../data-frame/message- + //# header.md#message-id) serialized in the header of this message. + header.body.messageId, + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# - The Body AAD Content (../data-format/message-body-aad.md#body- + //# aad-content) depends on whether the thing being encrypted is a + //# regular frame or final frame. Refer to Message Body AAD + //# (../data-format/message-body-aad.md) specification for more + //# information. + AADRegularFrame, + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# - The sequence number (../data-format/message-body- + //# aad.md#sequence-number) is the sequence number of the frame + //# being encrypted. + sequenceNumber, + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# - The content length (../data-format/message-body-aad.md#content- + //# length) MUST have a value equal to the length of the plaintext + //# being encrypted. + |plaintext| as uint64 + ) + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * The IV is the sequence number (../data-format/message-body- + //# aad.md#sequence-number) used in the message body AAD above, padded + //# to the IV length (../data-format/message-header.md#iv-length). + && encryptionInput.iv == IVSeq(header.suite, sequenceNumber) + + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * The cipherkey is the derived data key + && encryptionInput.key == key + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * The plaintext is the next subsequence of consumable plaintext + //# bytes that have not yet been encrypted. + && encryptionInput.msg == plaintext + + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# This operation MUST serialize a regular frame or final frame with the + //# following specifics: + && frame.header == header + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * Sequence Number (../data-format/message-body.md#sequence-number): + //# MUST be the sequence number of this frame, as determined above. + && frame.seqNum == sequenceNumber + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * IV (../data-format/message-body.md#iv): MUST be the IV used when + //# calculating the encrypted content above + && frame.iv == encryptionInput.iv + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * Encrypted Content (../data-format/message-body.md#encrypted- + //# content): MUST be the encrypted content calculated above. + && frame.encContent == encryptionOutput.cipherText + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * Authentication Tag (../data-format/message-body.md#authentication- + //# tag): MUST be the authentication tag output when calculating the + //# encrypted content above. + && frame.authTag == encryptionOutput.authTag { var iv := IVSeq(header.suite, sequenceNumber); var aad := BodyAAD( @@ -478,7 +478,7 @@ module MessageBody { var maybeEncryptionOutput := crypto.AESEncrypt(aesEncryptInput); var encryptionOutput :- maybeEncryptionOutput - .MapFailure(e => Types.AwsCryptographyPrimitives(e)); + .MapFailure(e => Types.AwsCryptographyPrimitives(e)); var frame: Frames.RegularFrame := Frames.Frame.RegularFrame( header, @@ -524,96 +524,96 @@ module MessageBody { ensures crypto.History.AESEncrypt == old(crypto.History.AESEncrypt) + [Seq.Last(crypto.History.AESEncrypt)] ensures match res - case Failure(e) => true - case Success(frame) => - && Seq.Last(crypto.History.AESEncrypt).output.Success? - && var encryptionOutput := Seq.Last(crypto.History.AESEncrypt).output.value; - && var encryptionInput := Seq.Last(crypto.History.AESEncrypt).input; - - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# To construct a regular or final frame that represents the next frame - //# in the encrypted message's body, this operation MUST calculate the - //# encrypted content and an authentication tag using the authenticated - //# encryption algorithm (../framework/algorithm-suites.md#encryption- - //# algorithm) specified by the algorithm suite (../framework/algorithm- - //# suites.md), with the following inputs: - && encryptionInput.encAlg == header.suite.encrypt.AES_GCM - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * The AAD is the serialized message body AAD (../data-format/ - //# message-body-aad.md), constructed as follows: - && encryptionInput.aad == BodyAAD( - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# - The message ID (../data-format/message-body-aad.md#message-id) - //# is the same as the message ID (../data-frame/message- - //# header.md#message-id) serialized in the header of this message. - header.body.messageId, - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# - The Body AAD Content (../data-format/message-body-aad.md#body- - //# aad-content) depends on whether the thing being encrypted is a - //# regular frame or final frame. Refer to Message Body AAD - //# (../data-format/message-body-aad.md) specification for more - //# information. - AADFinalFrame, - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# - The sequence number (../data-format/message-body- - //# aad.md#sequence-number) is the sequence number of the frame - //# being encrypted. - sequenceNumber, - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# - The content length (../data-format/message-body-aad.md#content- - //# length) MUST have a value equal to the length of the plaintext - //# being encrypted. - |plaintext| as uint64 - ) - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * The IV is the sequence number (../data-format/message-body- - //# aad.md#sequence-number) used in the message body AAD above, padded - //# to the IV length (../data-format/message-header.md#iv-length). - && encryptionInput.iv == IVSeq(header.suite, sequenceNumber) - - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * The cipherkey is the derived data key - && encryptionInput.key == key - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * The plaintext is the next subsequence of consumable plaintext - //# bytes that have not yet been encrypted. - && encryptionInput.msg == plaintext - - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# This operation MUST serialize a regular frame or final frame with the - //# following specifics: - && frame.header == header - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * Sequence Number (../data-format/message-body.md#sequence-number): - //# MUST be the sequence number of this frame, as determined above. - && frame.seqNum == sequenceNumber - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * IV (../data-format/message-body.md#iv): MUST be the IV used when - //# calculating the encrypted content above - && frame.iv == encryptionInput.iv - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * Encrypted Content (../data-format/message-body.md#encrypted- - //# content): MUST be the encrypted content calculated above. - && frame.encContent == encryptionOutput.cipherText - //= compliance/client-apis/encrypt.txt#2.7.1 - //= type=implication - //# * Authentication Tag (../data-format/message-body.md#authentication- - //# tag): MUST be the authentication tag output when calculating the - //# encrypted content above. - && frame.authTag == encryptionOutput.authTag + case Failure(e) => true + case Success(frame) => + && Seq.Last(crypto.History.AESEncrypt).output.Success? + && var encryptionOutput := Seq.Last(crypto.History.AESEncrypt).output.value; + && var encryptionInput := Seq.Last(crypto.History.AESEncrypt).input; + + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# To construct a regular or final frame that represents the next frame + //# in the encrypted message's body, this operation MUST calculate the + //# encrypted content and an authentication tag using the authenticated + //# encryption algorithm (../framework/algorithm-suites.md#encryption- + //# algorithm) specified by the algorithm suite (../framework/algorithm- + //# suites.md), with the following inputs: + && encryptionInput.encAlg == header.suite.encrypt.AES_GCM + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * The AAD is the serialized message body AAD (../data-format/ + //# message-body-aad.md), constructed as follows: + && encryptionInput.aad == BodyAAD( + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# - The message ID (../data-format/message-body-aad.md#message-id) + //# is the same as the message ID (../data-frame/message- + //# header.md#message-id) serialized in the header of this message. + header.body.messageId, + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# - The Body AAD Content (../data-format/message-body-aad.md#body- + //# aad-content) depends on whether the thing being encrypted is a + //# regular frame or final frame. Refer to Message Body AAD + //# (../data-format/message-body-aad.md) specification for more + //# information. + AADFinalFrame, + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# - The sequence number (../data-format/message-body- + //# aad.md#sequence-number) is the sequence number of the frame + //# being encrypted. + sequenceNumber, + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# - The content length (../data-format/message-body-aad.md#content- + //# length) MUST have a value equal to the length of the plaintext + //# being encrypted. + |plaintext| as uint64 + ) + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * The IV is the sequence number (../data-format/message-body- + //# aad.md#sequence-number) used in the message body AAD above, padded + //# to the IV length (../data-format/message-header.md#iv-length). + && encryptionInput.iv == IVSeq(header.suite, sequenceNumber) + + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * The cipherkey is the derived data key + && encryptionInput.key == key + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * The plaintext is the next subsequence of consumable plaintext + //# bytes that have not yet been encrypted. + && encryptionInput.msg == plaintext + + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# This operation MUST serialize a regular frame or final frame with the + //# following specifics: + && frame.header == header + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * Sequence Number (../data-format/message-body.md#sequence-number): + //# MUST be the sequence number of this frame, as determined above. + && frame.seqNum == sequenceNumber + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * IV (../data-format/message-body.md#iv): MUST be the IV used when + //# calculating the encrypted content above + && frame.iv == encryptionInput.iv + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * Encrypted Content (../data-format/message-body.md#encrypted- + //# content): MUST be the encrypted content calculated above. + && frame.encContent == encryptionOutput.cipherText + //= compliance/client-apis/encrypt.txt#2.7.1 + //= type=implication + //# * Authentication Tag (../data-format/message-body.md#authentication- + //# tag): MUST be the authentication tag output when calculating the + //# encrypted content above. + && frame.authTag == encryptionOutput.authTag { var iv := IVSeq(header.suite, sequenceNumber); @@ -640,7 +640,7 @@ module MessageBody { var maybeEncryptionOutput := crypto.AESEncrypt(aesEncryptInput); var encryptionOutput :- maybeEncryptionOutput - .MapFailure(e => Types.AwsCryptographyPrimitives(e)); + .MapFailure(e => Types.AwsCryptographyPrimitives(e)); var finalFrame: Frames.FinalFrame := Frames.Frame.FinalFrame( header, @@ -667,18 +667,18 @@ module MessageBody { ensures old(crypto.History.AESDecrypt) < crypto.History.AESDecrypt ensures match res - case Failure(_) => true - case Success(plaintext) => //Exists a sequence of frames which encrypts the plaintext and is serialized in the read section of the stream - var decryptCalls := crypto.History.AESDecrypt[|old(crypto.History.AESDecrypt)|..]; - && (forall call <- decryptCalls :: call.output.Success?) - && SumDecryptCalls(decryptCalls) == plaintext - && (forall cryptoCall <- decryptCalls - :: - && cryptoCall.input.key == key - && exists frame <- body.regularFrames + [body.finalFrame] - :: - && frame.encContent == cryptoCall.input.cipherTxt - && frame.authTag == cryptoCall.input.authTag) + case Failure(_) => true + case Success(plaintext) => //Exists a sequence of frames which encrypts the plaintext and is serialized in the read section of the stream + var decryptCalls := crypto.History.AESDecrypt[|old(crypto.History.AESDecrypt)|..]; + && (forall call <- decryptCalls :: call.output.Success?) + && SumDecryptCalls(decryptCalls) == plaintext + && (forall cryptoCall <- decryptCalls + :: + && cryptoCall.input.key == key + && exists frame <- body.regularFrames + [body.finalFrame] + :: + && frame.encContent == cryptoCall.input.cipherTxt + && frame.authTag == cryptoCall.input.authTag) { var plaintext := []; @@ -697,14 +697,14 @@ module MessageBody { invariant crypto.History.AESDecrypt == old(crypto.History.AESDecrypt) + AESDecryptHistory // So far: All decrypted frames decrypt to the list of plaintext chunks invariant forall j - | 0 <= j < i - :: - && AESDecryptHistory[j].output.Success? - && AESDecryptHistory[j].input.key == key - && AESDecryptHistory[j].input.cipherTxt == body.regularFrames[j].encContent - && AESDecryptHistory[j].input.authTag == body.regularFrames[j].authTag - && AESDecryptHistory[j].input.iv == body.regularFrames[j].iv - // && AESDecryptHistory[j].input.aad == BodyAADByFrameType(body.regularFrames[j]) + | 0 <= j < i + :: + && AESDecryptHistory[j].output.Success? + && AESDecryptHistory[j].input.key == key + && AESDecryptHistory[j].input.cipherTxt == body.regularFrames[j].encContent + && AESDecryptHistory[j].input.authTag == body.regularFrames[j].authTag + && AESDecryptHistory[j].input.iv == body.regularFrames[j].iv + // && AESDecryptHistory[j].input.aad == BodyAADByFrameType(body.regularFrames[j]) invariant SumDecryptCalls(AESDecryptHistory) == plaintext { @@ -741,21 +741,21 @@ module MessageBody { ensures crypto.History.AESDecrypt == old(crypto.History.AESDecrypt) + [Seq.Last(crypto.History.AESDecrypt)] ensures match res - case Success(plaintextSegment) => ( // Decrypting the frame encoded in the stream is the returned ghost frame - && Seq.Last(crypto.History.AESDecrypt).output.Success? - && var decryptInput := Seq.Last(crypto.History.AESDecrypt).input; - && decryptInput.encAlg == frame.header.suite.encrypt.AES_GCM - && decryptInput.key == key - && decryptInput.cipherTxt == frame.encContent - && decryptInput.authTag == frame.authTag - && decryptInput.iv == frame.iv - && decryptInput.aad == BodyAADByFrameType(frame) - && res.value == Seq.Last(crypto.History.AESDecrypt).output.value - && |res.value| == |decryptInput.cipherTxt| - - && (frame.RegularFrame? || frame.FinalFrame? ==> |plaintextSegment| <= UINT32_LIMIT) - ) - case Failure(_) => true + case Success(plaintextSegment) => ( // Decrypting the frame encoded in the stream is the returned ghost frame + && Seq.Last(crypto.History.AESDecrypt).output.Success? + && var decryptInput := Seq.Last(crypto.History.AESDecrypt).input; + && decryptInput.encAlg == frame.header.suite.encrypt.AES_GCM + && decryptInput.key == key + && decryptInput.cipherTxt == frame.encContent + && decryptInput.authTag == frame.authTag + && decryptInput.iv == frame.iv + && decryptInput.aad == BodyAADByFrameType(frame) + && res.value == Seq.Last(crypto.History.AESDecrypt).output.value + && |res.value| == |decryptInput.cipherTxt| + + && (frame.RegularFrame? || frame.FinalFrame? ==> |plaintextSegment| <= UINT32_LIMIT) + ) + case Failure(_) => true { var aad := BodyAADByFrameType(frame); @@ -775,22 +775,22 @@ module MessageBody { crypto.AESDecrypt( Primitives.Types.AESDecryptInput( encAlg := frame.header.suite.encrypt.AES_GCM, - //#* The cipherkey is the derived data key + //#* The cipherkey is the derived data key key := key, - //#* The ciphertext is the encrypted content (../data-format/message- - //# body.md#encrypted-content). + //#* The ciphertext is the encrypted content (../data-format/message- + //# body.md#encrypted-content). cipherTxt := frame.encContent, - //#* the tag is the value serialized in the authentication tag field - //# (../data-format/message-body.md#authentication-tag) in the message - //# body or frame. + //#* the tag is the value serialized in the authentication tag field + //# (../data-format/message-body.md#authentication-tag) in the message + //# body or frame. authTag := frame.authTag, - //#* The IV is the sequence number (../data-format/message-body- - //# aad.md#sequence-number) used in the message body AAD above, padded - //# to the IV length (../data-format/message-header.md#iv-length) with - //# 0. + //#* The IV is the sequence number (../data-format/message-body- + //# aad.md#sequence-number) used in the message body AAD above, padded + //# to the IV length (../data-format/message-header.md#iv-length) with + //# 0. iv := frame.iv, - //#* The AAD is the serialized message body AAD (../data-format/ - //# message-body-aad.md) + //#* The AAD is the serialized message body AAD (../data-format/ + //# message-body-aad.md) aad := aad )); @@ -798,7 +798,7 @@ module MessageBody { //# If this decryption fails, this operation MUST immediately halt and //# fail. var plaintextSegment :- maybePlaintextSegment - .MapFailure(e => Types.AwsCryptographyPrimitives(e)); + .MapFailure(e => Types.AwsCryptographyPrimitives(e)); return Success(plaintextSegment); } @@ -871,7 +871,7 @@ module MessageBody { //# For non-framed data (message-body.md#non-framed-data), the //# value of this field MUST be "1". NONFRAMED_SEQUENCE_NUMBER, - + //= compliance/data-format/message-body-aad.txt#2.4.2 //# * Non-framed data (message-body.md#non-framed-data) MUST use the //# value "AWSKMSEncryptionClient Single Block". @@ -895,7 +895,7 @@ module MessageBody { bc: BodyAADContent, sequenceNumber: uint32, length: uint64 - ) + ) : (aad: seq) { var contentAAD := UTF8.Encode(BodyAADContentTypeString(bc)); @@ -903,26 +903,26 @@ module MessageBody { //#* The AAD is the serialized message body AAD (../data-format/ //# message-body-aad.md), constructed as follows: - //# - The message ID (../data-format/message-body-aad.md#message-id) - //# is the same as the message ID (../data-frame/message- - //# header.md#message-id) deserialized from the header of this - //# message. - messageID - //# - The Body AAD Content (../data-format/message-body-aad.md#body- - //# aad-content) depends on whether the thing being decrypted is a - //# regular frame, final frame, or un-framed data. Refer to - //# Message Body AAD (../data-format/message-body-aad.md) - //# specification for more information. - + contentAAD.value - //# - The sequence number (../data-format/message-body- - //# aad.md#sequence-number) is the sequence number deserialized - //# from the frame being decrypted. - + UInt32ToSeq(sequenceNumber) - //= compliance/client-apis/decrypt.txt#2.7.4 - //# - The content length (../data-format/message-body-aad.md#content- - //# length) MUST have a value equal to the length of the plaintext - //# that was encrypted. - + UInt64ToSeq(length) + //# - The message ID (../data-format/message-body-aad.md#message-id) + //# is the same as the message ID (../data-frame/message- + //# header.md#message-id) deserialized from the header of this + //# message. + messageID + //# - The Body AAD Content (../data-format/message-body-aad.md#body- + //# aad-content) depends on whether the thing being decrypted is a + //# regular frame, final frame, or un-framed data. Refer to + //# Message Body AAD (../data-format/message-body-aad.md) + //# specification for more information. + + contentAAD.value + //# - The sequence number (../data-format/message-body- + //# aad.md#sequence-number) is the sequence number deserialized + //# from the frame being decrypted. + + UInt32ToSeq(sequenceNumber) + //= compliance/client-apis/decrypt.txt#2.7.4 + //# - The content length (../data-format/message-body-aad.md#content- + //# length) MUST have a value equal to the length of the plaintext + //# that was encrypted. + + UInt64ToSeq(length) } function method WriteFramedMessageBody( @@ -934,7 +934,7 @@ module MessageBody { //# The final frame //# MUST be the last frame. ensures ret == WriteMessageRegularFrames(body.regularFrames) - + Frames.WriteFinalFrame(body.finalFrame) + + Frames.WriteFinalFrame(body.finalFrame) { WriteMessageRegularFrames(body.regularFrames) + Frames.WriteFinalFrame(body.finalFrame) } @@ -944,10 +944,10 @@ module MessageBody { ) :(ret: seq) ensures if |frames| == 0 then - ret == [] - else - ret == WriteMessageRegularFrames(Seq.DropLast(frames)) - + Frames.WriteRegularFrame(Seq.Last(frames)) + ret == [] + else + ret == WriteMessageRegularFrames(Seq.DropLast(frames)) + + Frames.WriteRegularFrame(Seq.Last(frames)) { if |frames| == 0 then [] else @@ -1022,10 +1022,10 @@ module MessageBody { //# the algorithm suite (../framework/algorithm-suites.md), with the //# following inputs: assert CorrectlyRead( - buffer, - Success(SuccessfulRead(nextRegularFrames, regularFrame.tail)), - WriteMessageRegularFrames - ) by { + buffer, + Success(SuccessfulRead(nextRegularFrames, regularFrame.tail)), + WriteMessageRegularFrames + ) by { calc { buffer.bytes[buffer.start..continuation.start] + Frames.WriteRegularFrame(regularFrame.data); == {CorrectlyReadByteRange(buffer, continuation, WriteMessageRegularFrames(regularFrames));} @@ -1098,8 +1098,8 @@ module MessageBody { :(res: ReadCorrect) ensures CorrectlyRead(buffer, res, WriteNonFramedMessageBody) ensures res.Success? - ==> - && res.value.data.header == header + ==> + && res.value.data.header == header { var block :- Frames.ReadNonFrame(buffer, header); Success(SuccessfulRead(block.data, block.tail)) diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/EncryptionContext.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/EncryptionContext.dfy index af70c4b8b..5d54b3c7d 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/EncryptionContext.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/EncryptionContext.dfy @@ -223,7 +223,7 @@ module {:options "/functionSyntax:4" } EncryptionContext { requires subEC.Keys <= ec.Keys requires forall k <- subEC.Keys :: ec[k] == subEC[k] ensures IsESDKEncryptionContext(subEC) - { + { var complement := Complement(ec, subEC); calc { @@ -233,34 +233,34 @@ module {:options "/functionSyntax:4" } EncryptionContext { == {LinearLengthIsDistributive(GetCanonicalLinearPairs(complement), GetCanonicalLinearPairs(subEC));} LinearLength(GetCanonicalLinearPairs(complement) + GetCanonicalLinearPairs(subEC)); == { - var pairs1 := GetCanonicalLinearPairs(complement + subEC); - var pairs2 := GetCanonicalLinearPairs(complement) + GetCanonicalLinearPairs(subEC); - - GetCanonicalLinearPairsIsBijective(complement + subEC, pairs1); - GetCanonicalLinearPairsIsBijective(complement, GetCanonicalLinearPairs(complement)); - GetCanonicalLinearPairsIsBijective(subEC, GetCanonicalLinearPairs(subEC)); - assert forall p <- pairs1 :: p in pairs2; - assert forall p <- pairs2 :: p in pairs1 by { - forall p <- pairs2 - ensures p in pairs1 - { - calc ==> - { - p in pairs2; - ==> - p in GetCanonicalLinearPairs(complement) + GetCanonicalLinearPairs(subEC); - ==> { - assert (forall p' <- GetCanonicalLinearPairs(complement) :: p' in GetCanonicalLinearPairs(complement + subEC)); - assert (forall p' <- GetCanonicalLinearPairs(subEC) :: p' in GetCanonicalLinearPairs(complement + subEC)); - } - p in GetCanonicalLinearPairs(complement + subEC); - ==> - p in pairs1; - } - } - } - LinearLengthOfUniquePairsIsOrderIndependent(pairs1, pairs2); - } + var pairs1 := GetCanonicalLinearPairs(complement + subEC); + var pairs2 := GetCanonicalLinearPairs(complement) + GetCanonicalLinearPairs(subEC); + + GetCanonicalLinearPairsIsBijective(complement + subEC, pairs1); + GetCanonicalLinearPairsIsBijective(complement, GetCanonicalLinearPairs(complement)); + GetCanonicalLinearPairsIsBijective(subEC, GetCanonicalLinearPairs(subEC)); + assert forall p <- pairs1 :: p in pairs2; + assert forall p <- pairs2 :: p in pairs1 by { + forall p <- pairs2 + ensures p in pairs1 + { + calc ==> + { + p in pairs2; + ==> + p in GetCanonicalLinearPairs(complement) + GetCanonicalLinearPairs(subEC); + ==> { + assert (forall p' <- GetCanonicalLinearPairs(complement) :: p' in GetCanonicalLinearPairs(complement + subEC)); + assert (forall p' <- GetCanonicalLinearPairs(subEC) :: p' in GetCanonicalLinearPairs(complement + subEC)); + } + p in GetCanonicalLinearPairs(complement + subEC); + ==> + p in pairs1; + } + } + } + LinearLengthOfUniquePairsIsOrderIndependent(pairs1, pairs2); + } LinearLength(GetCanonicalLinearPairs(complement + subEC)); == Length(complement + subEC); @@ -343,7 +343,7 @@ module {:options "/functionSyntax:4" } EncryptionContext { ensures HasUint16Len(ret) { // The Serialization of No Encryption Context is NOT `[0, [0, 0]]`, - // but `[]`. + // but `[]`. if |ec| == 0 then [] else @@ -378,7 +378,7 @@ module {:options "/functionSyntax:4" } EncryptionContext { // |ec| == 0 is encoded as 0 count. // However, // this |ec| == 0 behavior is never invoked, - // as this method is protected by + // as this method is protected by // WriteAADSection and WriteEmptyEcOrWriteAAD, // which both handle |ec| == 0 independently // of this method. diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/Frames.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/Frames.dfy index 91940cab3..c4bc1b93a 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/Frames.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/Frames.dfy @@ -29,44 +29,44 @@ module Frames { const NONFRAMED_SEQUENCE_NUMBER: uint32 := 1 type FramedHeader = h : Header.Header - | FramedHeader?(h) - witness * + | FramedHeader?(h) + witness * predicate FramedHeader?(h : Header.Header) { h.body.contentType.Framed? } type NonFramedHeader = h : Header.Header - | NonFramedHeader?(h) - witness * + | NonFramedHeader?(h) + witness * predicate NonFramedHeader?(h : Header.Header) { h.body.contentType.NonFramed? } datatype Frame = - | RegularFrame( - header: Header.Header, - seqNum: uint32, - iv: seq, - encContent: seq, - authTag: seq) - | FinalFrame ( - header: Header.Header, - seqNum: uint32, - iv: seq, - encContent: seq, - authTag: seq) - | NonFramed( - header: Header.Header, - //= compliance/data-format/message-body.txt#2.5.1.1 - //= type=implication - //# The - //# IV MUST be a unique IV within the message. - iv: seq, - encContent: seq, - authTag: seq - ) + | RegularFrame( + header: Header.Header, + seqNum: uint32, + iv: seq, + encContent: seq, + authTag: seq) + | FinalFrame ( + header: Header.Header, + seqNum: uint32, + iv: seq, + encContent: seq, + authTag: seq) + | NonFramed( + header: Header.Header, + //= compliance/data-format/message-body.txt#2.5.1.1 + //= type=implication + //# The + //# IV MUST be a unique IV within the message. + iv: seq, + encContent: seq, + authTag: seq + ) predicate IvTagLengths(frame: Frame){ && |frame.iv| == GetIvLength(frame.header.suite) as nat @@ -75,56 +75,56 @@ module Frames { predicate IsRegularFrame(frame: Frame){ && frame.RegularFrame? - //= compliance/data-format/message-body.txt#2.5.2.1.4 - //= type=implication - //# The authentication tag length MUST be equal to the authentication tag - //# length of the algorithm suite specified by the Algorithm Suite ID - //# (message-header.md#algorithm-suite-id) field. + //= compliance/data-format/message-body.txt#2.5.2.1.4 + //= type=implication + //# The authentication tag length MUST be equal to the authentication tag + //# length of the algorithm suite specified by the Algorithm Suite ID + //# (message-header.md#algorithm-suite-id) field. && IvTagLengths(frame) && frame.header.body.contentType.Framed? - //= compliance/data-format/message-body.txt#2.5.2.1.3 - //= type=implication - //# The length of the encrypted content of a Regular Frame MUST be equal - //# to the Frame Length. + //= compliance/data-format/message-body.txt#2.5.2.1.3 + //= type=implication + //# The length of the encrypted content of a Regular Frame MUST be equal + //# to the Frame Length. && |frame.encContent| == frame.header.body.frameLength as nat && frame.seqNum < ENDFRAME_SEQUENCE_NUMBER } type RegularFrame = frame: Frame - | IsRegularFrame(frame) - witness * + | IsRegularFrame(frame) + witness * predicate IsFinalFrame(frame: Frame) { && frame.FinalFrame? - //= compliance/data-format/message-body.txt#2.5.2.2.6 - //= type=implication - //# The authentication tag length MUST be equal to the authentication tag - //# length of the algorithm suite specified by the Algorithm Suite ID - //# (message-header.md#algorithm-suite-id) field. + //= compliance/data-format/message-body.txt#2.5.2.2.6 + //= type=implication + //# The authentication tag length MUST be equal to the authentication tag + //# length of the algorithm suite specified by the Algorithm Suite ID + //# (message-header.md#algorithm-suite-id) field. && IvTagLengths(frame) && frame.header.body.contentType.Framed? && |frame.encContent| <= frame.header.body.frameLength as nat } type FinalFrame = frame: Frame - | IsFinalFrame(frame) - witness * + | IsFinalFrame(frame) + witness * predicate NonFramed?(frame: Frame) { && frame.NonFramed? && IvTagLengths(frame) && frame.header.body.contentType.NonFramed? - //= compliance/data-format/message-body.txt#2.5.1.2 - //= type=implication - //# The length MUST NOT be greater than "2^36 - 32", or 64 gibibytes (64 - //# GiB), due to restrictions imposed by the implemented algorithms - //# (../framework/algorithm-suites.md). + //= compliance/data-format/message-body.txt#2.5.1.2 + //= type=implication + //# The length MUST NOT be greater than "2^36 - 32", or 64 gibibytes (64 + //# GiB), due to restrictions imposed by the implemented algorithms + //# (../framework/algorithm-suites.md). && |frame.encContent| < SAFE_MAX_ENCRYPT } type NonFramed = frame: Frame - | NonFramed?(frame) - witness * + | NonFramed?(frame) + witness * //= compliance/data-format/message-body.txt#2.5.2 //= type=implication @@ -132,7 +132,7 @@ module Frames { //# equal to "2^32 - 1". lemma LemmaRegularOrFinalFrameHasUint32ContentByteLength(frame: Frame) ensures IsRegularFrame(frame) || IsFinalFrame(frame) - ==> |frame.encContent| <= 0xFFFF_FFFF + ==> |frame.encContent| <= 0xFFFF_FFFF {} const SAFE_MAX_ENCRYPT := 0xFFFFFFFE0 // 2^36 - 32 @@ -147,7 +147,7 @@ module Frames { { reveal ReadUInt32(); reveal CorrectlyReadRange(); - + WriteUint32(regularFrame.seqNum) + Write(regularFrame.iv) + Write(regularFrame.encContent) @@ -160,7 +160,7 @@ module Frames { ) :(res: ReadCorrect) ensures res.Success? - ==> res.value.data.header == header && res.value.tail.start <= |buffer.bytes| + ==> res.value.data.header == header && res.value.tail.start <= |buffer.bytes| ensures CorrectlyRead(buffer, res, WriteRegularFrame) { @@ -173,21 +173,21 @@ module Frames { var iv :- Read(sequenceNumber.tail, GetIvLength(header.suite) as nat); var encContent :- Read(iv.tail, header.body.frameLength as nat); var authTag :- Read(encContent.tail, GetTagLength(header.suite) as nat); - assert + assert && authTag.tail.start <= |buffer.bytes| - && buffer.start <= authTag.tail.start + && buffer.start <= authTag.tail.start && authTag.tail.start == buffer.start + |buffer.bytes[buffer.start..authTag.tail.start]| by { reveal CorrectlyReadRange(); } - + var regularFrame: RegularFrame := Frame.RegularFrame( - header, - sequenceNumber.data, - iv.data, - encContent.data, - authTag.data - ); + header, + sequenceNumber.data, + iv.data, + encContent.data, + authTag.data + ); assert CorrectlyReadRange(buffer, authTag.tail, WriteRegularFrame(regularFrame)) by { CorrectlyReadByteRange(buffer, sequenceNumber.tail, WriteUint32(sequenceNumber.data)); @@ -204,10 +204,10 @@ module Frames { :(ret: seq) ensures && ReadUInt32(ReadableBuffer(ret, 0)).Success? - //= compliance/data-format/message-body.txt#2.5.2.2.1 - //= type=implication - //# The value MUST be encoded as the 4 bytes "FF FF FF FF" in hexadecimal - //# notation. + //= compliance/data-format/message-body.txt#2.5.2.2.1 + //= type=implication + //# The value MUST be encoded as the 4 bytes "FF FF FF FF" in hexadecimal + //# notation. && ReadUInt32(ReadableBuffer(ret, 0)).value.data == ENDFRAME_SEQUENCE_NUMBER { reveal ReadUInt32(); @@ -226,7 +226,7 @@ module Frames { ) :(res: ReadCorrect) ensures res.Success? - ==> res.value.data.header == header + ==> res.value.data.header == header ensures CorrectlyRead(buffer, res, WriteFinalFrame) //= compliance/client-apis/decrypt.txt#2.7.4 @@ -237,16 +237,16 @@ module Frames { //# in the message header. ensures res.Success? - ==> - && var finalFrameSignalRes := ReadUInt32(buffer); - && finalFrameSignalRes.Success? - && var sequenceNumberRes := ReadUInt32(finalFrameSignalRes.value.tail); - && sequenceNumberRes.Success? - && var ivRes := Read(sequenceNumberRes.value.tail, GetIvLength(header.suite) as nat); - && ivRes.Success? - && var encContentRes := ReadUint32Seq(ivRes.value.tail); - && encContentRes.Success? - && |encContentRes.value.data| as uint32 <= header.body.frameLength + ==> + && var finalFrameSignalRes := ReadUInt32(buffer); + && finalFrameSignalRes.Success? + && var sequenceNumberRes := ReadUInt32(finalFrameSignalRes.value.tail); + && sequenceNumberRes.Success? + && var ivRes := Read(sequenceNumberRes.value.tail, GetIvLength(header.suite) as nat); + && ivRes.Success? + && var encContentRes := ReadUint32Seq(ivRes.value.tail); + && encContentRes.Success? + && |encContentRes.value.data| as uint32 <= header.body.frameLength { reveal ReadUInt32(); @@ -267,22 +267,22 @@ module Frames { var encContent :- ReadUint32Seq(iv.tail); var authTag :- Read(encContent.tail, GetTagLength(header.suite) as nat); var finalFrame: FinalFrame := Frame.FinalFrame( - header, - sequenceNumber.data, - iv.data, - encContent.data, - authTag.data - ); + header, + sequenceNumber.data, + iv.data, + encContent.data, + authTag.data + ); assert CorrectlyReadRange(buffer, authTag.tail, WriteFinalFrame(finalFrame)) by { reveal CorrectlyReadRange(); - // It seems that Dafny can find a solution pretty fast. - // But I leave this here in case there is some problem later. - // CorrectlyReadByteRange(buffer, finalFrameSignal.tail, WriteUint32(finalFrameSignal.data)); - // AppendToCorrectlyReadByteRange(buffer, finalFrameSignal.tail, sequenceNumber.tail, WriteUint32(sequenceNumber.data)); - // AppendToCorrectlyReadByteRange(buffer, sequenceNumber.tail, iv.tail, Write(iv.data)); - // AppendToCorrectlyReadByteRange(buffer, iv.tail, encContent.tail, WriteUint32Seq(encContent.data)); - // AppendToCorrectlyReadByteRange(buffer, encContent.tail, authTag.tail, Write(authTag.data)); + // It seems that Dafny can find a solution pretty fast. + // But I leave this here in case there is some problem later. + // CorrectlyReadByteRange(buffer, finalFrameSignal.tail, WriteUint32(finalFrameSignal.data)); + // AppendToCorrectlyReadByteRange(buffer, finalFrameSignal.tail, sequenceNumber.tail, WriteUint32(sequenceNumber.data)); + // AppendToCorrectlyReadByteRange(buffer, sequenceNumber.tail, iv.tail, Write(iv.data)); + // AppendToCorrectlyReadByteRange(buffer, iv.tail, encContent.tail, WriteUint32Seq(encContent.data)); + // AppendToCorrectlyReadByteRange(buffer, encContent.tail, authTag.tail, Write(authTag.data)); } Success(SuccessfulRead(finalFrame, authTag.tail)) @@ -294,7 +294,7 @@ module Frames { ) :(res: ReadCorrect) ensures res.Success? - ==> res.value.data.header == header + ==> res.value.data.header == header ensures CorrectlyRead(buffer, res, WriteNonFramed) { var iv :- Read(buffer, GetIvLength(header.suite) as nat); @@ -306,11 +306,11 @@ module Frames { var authTag :- Read(encContent.tail, GetTagLength(header.suite) as nat); var nonFramed: NonFramed := Frame.NonFramed( - header, - iv.data, - encContent.data, - authTag.data - ); + header, + iv.data, + encContent.data, + authTag.data + ); assert CorrectlyReadRange(buffer, authTag.tail, WriteNonFramed(nonFramed)) by { reveal CorrectlyReadRange(); diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/Header.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/Header.dfy index 5c90c42d7..ffe528617 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/Header.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/Header.dfy @@ -43,9 +43,9 @@ module Header { { && h.suite.id.ESDK? && h.suite == h.body.algorithmSuite - // TODO: Even though we're not yet supporting non-framed content, - // this assertion about non-framed messages has ripple effects on - // other proofs + // TODO: Even though we're not yet supporting non-framed content, + // this assertion about non-framed messages has ripple effects on + // other proofs && (h.body.contentType.NonFramed? <==> 0 == h.body.frameLength) && (h.body.contentType.Framed? <==> 0 < h.body.frameLength) && HeaderAuth?(h.suite, h.headerAuth) @@ -72,10 +72,10 @@ module Header { headerAuth: HeaderTypes.HeaderAuth ) { - && (headerAuth.AESMac? - ==> - && |headerAuth.headerIv| == GetIvLength(suite) as nat - && |headerAuth.headerAuthTag| == GetTagLength(suite) as nat) + && (headerAuth.AESMac? + ==> + && |headerAuth.headerIv| == GetIvLength(suite) as nat + && |headerAuth.headerAuthTag| == GetTagLength(suite) as nat) } predicate method {:opaque} HeaderVersionSupportsCommitment?( @@ -84,17 +84,17 @@ module Header { ) { && (suite.commitment.HKDF? - ==> - && body.V2HeaderBody? - && |body.suiteData| == suite.commitment.HKDF.outputKeyLength as nat) + ==> + && body.V2HeaderBody? + && |body.suiteData| == suite.commitment.HKDF.outputKeyLength as nat) && (!suite.commitment.HKDF? - ==> - && body.V1HeaderBody?) + ==> + && body.V1HeaderBody?) } type Header = h: HeaderInfo - | IsHeader(h) - witness * + | IsHeader(h) + witness * // ReadHeaderBody does not support streaming at this time //= compliance/client-apis/decrypt.txt#2.7.1 @@ -109,9 +109,9 @@ module Header { //# message bytes until it has successfully deserialized a valid message //# header (../data-format/message-header.md). function method {:opaque} ReadHeaderBody( - buffer: ReadableBuffer, - maxEdks: Option, - mpl: MaterialProviders.MaterialProvidersClient + buffer: ReadableBuffer, + maxEdks: Option, + mpl: MaterialProviders.MaterialProvidersClient ) :(res: ReadCorrect) ensures CorrectlyReadHeaderBody(buffer, res) @@ -120,9 +120,9 @@ module Header { //# When the content type (Section 2.5.1.11) is non- //# framed, the value of this field MUST be 0. ensures res.Success? ==> - var h := res.value.data; - && (h.contentType.NonFramed? <==> 0 == h.frameLength) - && (h.contentType.Framed? <==> 0 < h.frameLength) + var h := res.value.data; + && (h.contentType.NonFramed? <==> 0 == h.frameLength) + && (h.contentType.Framed? <==> 0 < h.frameLength) { var version :- SharedHeaderFunctions.ReadMessageFormatVersion(buffer); @@ -138,9 +138,9 @@ module Header { }; :- Need(body.contentType.Framed? <==> body.frameLength > 0, - Error("Frame length must be positive if content is framed")); + Error("Frame length must be positive if content is framed")); :- Need(body.contentType.NonFramed? <==> body.frameLength == 0, - Error("Frame length must be zero if content is non-framed")); + Error("Frame length must be zero if content is non-framed")); Success(SuccessfulRead(body, tail)) } @@ -151,11 +151,11 @@ module Header { { res.Success? ==> - && match res.value.data - case V1HeaderBody(_,_,_,_,_,_,_,_) => - V1HeaderBody.CorrectlyReadV1HeaderBody(buffer, res) - case V2HeaderBody(_,_,_,_,_,_,_) => - V2HeaderBody.CorrectlyReadV2HeaderBody(buffer, res) + && match res.value.data + case V1HeaderBody(_,_,_,_,_,_,_,_) => + V1HeaderBody.CorrectlyReadV1HeaderBody(buffer, res) + case V2HeaderBody(_,_,_,_,_,_,_) => + V2HeaderBody.CorrectlyReadV2HeaderBody(buffer, res) } function method WriteHeaderBody( diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/HeaderAuth.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/HeaderAuth.dfy index c831f3130..d7f4993d9 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/HeaderAuth.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/HeaderAuth.dfy @@ -22,8 +22,8 @@ module HeaderAuth { import opened SerializeFunctions type AESMac = a: HeaderTypes.HeaderAuth - | a.AESMac? - witness * + | a.AESMac? + witness * function method WriteHeaderAuthTagV2( headerAuth: AESMac @@ -65,7 +65,7 @@ module HeaderAuth { //= compliance/client-apis/encrypt.txt#2.6.2 //# * Authentication Tag (../data-format/message- //# header.md#authentication-tag): MUST have the value of the - //# authentication tag calculated above. + //# authentication tag calculated above. + Write(headerAuth.headerAuthTag) } @@ -76,9 +76,9 @@ module HeaderAuth { :(ret: Result, Types.Error>) { match suite.messageVersion - case 1 => Success(WriteHeaderAuthTagV1(headerAuth)) - case 2 => Success(WriteHeaderAuthTagV2(headerAuth)) - case _ => Failure(Types.AwsEncryptionSdkException( message := "Unexpected message version")) + case 1 => Success(WriteHeaderAuthTagV1(headerAuth)) + case 2 => Success(WriteHeaderAuthTagV2(headerAuth)) + case _ => Failure(Types.AwsEncryptionSdkException( message := "Unexpected message version")) } function method ReadHeaderAuthTagV1( @@ -88,17 +88,17 @@ module HeaderAuth { :(res: ReadCorrect) ensures CorrectlyRead(buffer, res, WriteHeaderAuthTagV1) ensures res.Success? - ==> - && |res.value.data.headerIv| == GetIvLength(suite) as nat - && |res.value.data.headerAuthTag| == GetTagLength(suite) as nat + ==> + && |res.value.data.headerIv| == GetIvLength(suite) as nat + && |res.value.data.headerAuthTag| == GetTagLength(suite) as nat { var headerIv :- Read(buffer, GetIvLength(suite) as nat); var headerAuthTag :- Read(headerIv.tail, GetTagLength(suite) as nat); var auth: AESMac := HeaderTypes.HeaderAuth.AESMac( - headerIv := headerIv.data, - headerAuthTag := headerAuthTag.data - ); + headerIv := headerIv.data, + headerAuthTag := headerAuthTag.data + ); assert CorrectlyReadRange(buffer, headerAuthTag.tail, WriteHeaderAuthTagV1(auth)) by { reveal CorrectlyReadRange(); @@ -114,18 +114,18 @@ module HeaderAuth { :(res: ReadCorrect) ensures CorrectlyRead(buffer, res, WriteHeaderAuthTagV2) ensures res.Success? - ==> - && |res.value.data.headerIv| == GetIvLength(suite) as nat - && |res.value.data.headerAuthTag| == GetTagLength(suite) as nat + ==> + && |res.value.data.headerIv| == GetIvLength(suite) as nat + && |res.value.data.headerAuthTag| == GetTagLength(suite) as nat { // TODO: probably this hardcoded iv of all 0s will go into alg suite var headerIv := seq(GetIvLength(suite) as int, _ => 0); var headerAuthTag :- Read(buffer, GetTagLength(suite) as nat); var auth: AESMac := HeaderTypes.HeaderAuth.AESMac( - headerIv := headerIv, - headerAuthTag := headerAuthTag.data - ); + headerIv := headerIv, + headerAuthTag := headerAuthTag.data + ); Success(SuccessfulRead(auth, headerAuthTag.tail)) } @@ -139,14 +139,14 @@ module HeaderAuth { ensures suite.messageVersion == 1 ==> CorrectlyRead(buffer, res, WriteHeaderAuthTagV1) ensures suite.messageVersion == 2 ==> CorrectlyRead(buffer, res, WriteHeaderAuthTagV2) ensures res.Success? - ==> - && |res.value.data.headerIv| == GetIvLength(suite) as nat - && |res.value.data.headerAuthTag| == GetTagLength(suite) as nat + ==> + && |res.value.data.headerIv| == GetIvLength(suite) as nat + && |res.value.data.headerAuthTag| == GetTagLength(suite) as nat ensures suite.messageVersion != 1 && suite.messageVersion != 2 ==> res.Failure? { match suite.messageVersion - case 1 => ReadHeaderAuthTagV1(buffer, suite) - case 2 => ReadHeaderAuthTagV2(buffer, suite) - case _ => Failure(Error("Unexpected message version")) + case 1 => ReadHeaderAuthTagV1(buffer, suite) + case 2 => ReadHeaderAuthTagV2(buffer, suite) + case _ => Failure(Error("Unexpected message version")) } } diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/HeaderTypes.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/HeaderTypes.dfy index 01d5f17f1..ea919360c 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/HeaderTypes.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/HeaderTypes.dfy @@ -17,13 +17,13 @@ module HeaderTypes { import opened SerializeFunctions datatype MessageFormatVersion = - | V1 - | V2 - { + | V1 + | V2 + { function method Serialize(): (bytes: seq) { match this - case V1 => [0x01] - case V2 => [0x02] + case V1 => [0x01] + case V2 => [0x02] } lemma LemmaSerializeCorrectValue() @@ -32,16 +32,16 @@ module HeaderTypes { //# The version (hex) of this field //# MUST be a value that exists in the following table: ensures match this - //= compliance/data-format/message-header.txt#2.5.1.1 - //= type=implication - //# The value of the "Version" field MUST be "01" in the - //# Version 1.0 header body. - case V1 => this.Serialize() == [0x01] - //= compliance/data-format/message-header.txt#2.5.1.2 - //= type=implication - //# The value of the "Version" field MUST be "02" in the - //# Version 2.0 header body. - case V2 => this.Serialize() == [0x02] + //= compliance/data-format/message-header.txt#2.5.1.1 + //= type=implication + //# The value of the "Version" field MUST be "01" in the + //# Version 1.0 header body. + case V1 => this.Serialize() == [0x01] + //= compliance/data-format/message-header.txt#2.5.1.2 + //= type=implication + //# The value of the "Version" field MUST be "02" in the + //# Version 2.0 header body. + case V2 => this.Serialize() == [0x02] {} static function method Get( @@ -64,38 +64,38 @@ module HeaderTypes { } type ESDKAlgorithmSuite = a: MPL.AlgorithmSuiteInfo | ESDKAlgorithmSuite?(a) - witness * + witness * datatype HeaderBody = | V1HeaderBody( - nameonly messageType: MessageType, - nameonly algorithmSuite: ESDKAlgorithmSuite, // TODO add MUST to spec to ensure this stays true - nameonly messageId: MessageId, - nameonly encryptionContext: EncryptionContext.ESDKCanonicalEncryptionContext, - nameonly encryptedDataKeys: ESDKEncryptedDataKeys, - nameonly contentType: ContentType, - nameonly headerIvLength: nat, - nameonly frameLength: uint32 - ) + nameonly messageType: MessageType, + nameonly algorithmSuite: ESDKAlgorithmSuite, // TODO add MUST to spec to ensure this stays true + nameonly messageId: MessageId, + nameonly encryptionContext: EncryptionContext.ESDKCanonicalEncryptionContext, + nameonly encryptedDataKeys: ESDKEncryptedDataKeys, + nameonly contentType: ContentType, + nameonly headerIvLength: nat, + nameonly frameLength: uint32 + ) | V2HeaderBody( - nameonly algorithmSuite: ESDKAlgorithmSuite, - nameonly messageId: MessageId, - nameonly encryptionContext: EncryptionContext.ESDKCanonicalEncryptionContext, - nameonly encryptedDataKeys: ESDKEncryptedDataKeys, - nameonly contentType: ContentType, - nameonly frameLength: uint32, - nameonly suiteData: seq - ) + nameonly algorithmSuite: ESDKAlgorithmSuite, + nameonly messageId: MessageId, + nameonly encryptionContext: EncryptionContext.ESDKCanonicalEncryptionContext, + nameonly encryptedDataKeys: ESDKEncryptedDataKeys, + nameonly contentType: ContentType, + nameonly frameLength: uint32, + nameonly suiteData: seq + ) datatype HeaderAuth = - | AESMac( - nameonly headerIv: seq, - nameonly headerAuthTag: seq - ) + | AESMac( + nameonly headerIv: seq, + nameonly headerAuthTag: seq + ) datatype MessageType = - | TYPE_CUSTOMER_AED - { + | TYPE_CUSTOMER_AED + { function method Serialize(): (val: uint8) { match this case TYPE_CUSTOMER_AED => 0x80 @@ -124,8 +124,8 @@ module HeaderTypes { } datatype ContentType = - | NonFramed - | Framed + | NonFramed + | Framed { function method Serialize(): (val: uint8) { match this @@ -161,7 +161,7 @@ module HeaderTypes { const MESSAGE_ID_LEN_V1 := 16 const MESSAGE_ID_LEN_V2 := 32 type MessageId = x: seq | - || |x| == MESSAGE_ID_LEN_V1 - || |x| == MESSAGE_ID_LEN_V2 - witness * + || |x| == MESSAGE_ID_LEN_V1 + || |x| == MESSAGE_ID_LEN_V2 + witness * } diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/SerializableTypes.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/SerializableTypes.dfy index 67b90bd3b..6816c077f 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/SerializableTypes.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/SerializableTypes.dfy @@ -36,28 +36,28 @@ module SerializableTypes { && |ec| < UINT16_LIMIT && Length(ec) < ESDK_CANONICAL_ENCRYPTION_CONTEXT_MAX_LENGTH && forall element - | element in (multiset(ec.Keys) + multiset(ec.Values)) - :: - && HasUint16Len(element) - && ValidUTF8Seq(element) + | element in (multiset(ec.Keys) + multiset(ec.Values)) + :: + && HasUint16Len(element) + && ValidUTF8Seq(element) } type ESDKEncryptionContext = ec: MPL.EncryptionContext - | IsESDKEncryptionContext(ec) - witness * + | IsESDKEncryptionContext(ec) + witness * function method GetIvLength(a: MPL.AlgorithmSuiteInfo) : (output: uint8) { match a.encrypt - case AES_GCM(e) => e.ivLength as uint8 + case AES_GCM(e) => e.ivLength as uint8 } function method GetTagLength(a: MPL.AlgorithmSuiteInfo) : (output: uint8) { match a.encrypt - case AES_GCM(e) => e.tagLength as uint8 + case AES_GCM(e) => e.tagLength as uint8 } function method GetEncryptKeyLength(a: MPL.AlgorithmSuiteInfo) @@ -67,7 +67,7 @@ module SerializableTypes { && AwsCryptographyPrimitivesTypes.IsValid_SymmetricKeyLength(output) { match a.encrypt - case AES_GCM(e) => e.keyLength + case AES_GCM(e) => e.keyLength } /* @@ -92,8 +92,8 @@ module SerializableTypes { && ret == LinearLength(pairs) { if |encryptionContext| == 0 then 0 else - var pairs := GetCanonicalLinearPairs(encryptionContext); - LinearLength(pairs) + var pairs := GetCanonicalLinearPairs(encryptionContext); + LinearLength(pairs) } // Defining and reasoning about order with maps @@ -110,14 +110,14 @@ module SerializableTypes { //# These entries MUST have entries sorted, by key, in ascending order //# according to the UTF-8 encoded binary value. var keys: seq := SortedSets.ComputeSetToOrderedSequence2( - encryptionContext.Keys, - UInt.UInt8Less - ); + encryptionContext.Keys, + UInt.UInt8Less + ); seq( - |keys|, - i - requires 0 <= i < |keys| - => Pair( + |keys|, + i + requires 0 <= i < |keys| + => Pair( keys[i], encryptionContext[keys[i]])) } @@ -154,9 +154,9 @@ module SerializableTypes { ): (ret: nat) ensures |pairs| == 0 - ==> ret == 0 + ==> ret == 0 ensures |pairs| != 0 - ==> ret == LinearLength(Seq.DropLast(pairs)) + PairLength(Seq.Last(pairs)) + ==> ret == LinearLength(Seq.DropLast(pairs)) + PairLength(Seq.Last(pairs)) { if |pairs| == 0 then 0 else diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/SerializeFunctions.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/SerializeFunctions.dfy index e9a5beefc..5608d024e 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/SerializeFunctions.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/SerializeFunctions.dfy @@ -81,7 +81,7 @@ module {:options "/functionSyntax:4" } SerializeFunctions { readRange: seq ) { - // This predicate defines what it means to correctly read a buffer. + // This predicate defines what it means to correctly read a buffer. // `buffer` represents the state of a buffer before a read, // `tail` represents the returned buffer after a read, // and `readRange` represents the bytes read from that buffer. @@ -89,17 +89,17 @@ module {:options "/functionSyntax:4" } SerializeFunctions { // and in order to have read `readRange` we need // the following to be true: && buffer.bytes == tail.bytes - // buffer and tail can start at the same place (i.e the beginning) - // as you read more, tail will grow but not larger than the size of the buffer. + // buffer and tail can start at the same place (i.e the beginning) + // as you read more, tail will grow but not larger than the size of the buffer. && buffer.start <= tail.start <= |buffer.bytes| - // buffer and tail bytes are the same because when we splice them using buffer.start - // as the start all the way to end we have the same sequence + // buffer and tail bytes are the same because when we splice them using buffer.start + // as the start all the way to end we have the same sequence && buffer.bytes[buffer.start..] == tail.bytes[buffer.start..] - // the bytes read i.e. the readRange MUST be a subset of the bytes in the buffer. - // further it MUST be the the prefix of the bytes sliced from the buffer's start. + // the bytes read i.e. the readRange MUST be a subset of the bytes in the buffer. + // further it MUST be the the prefix of the bytes sliced from the buffer's start. && readRange <= buffer.bytes[buffer.start..] - // the start of where we have read up to so far must be equal to where the buffer starts - // and the length of the sequence of what we have read. + // the start of where we have read up to so far must be equal to where the buffer starts + // and the length of the sequence of what we have read. && tail.start == buffer.start + |readRange| } @@ -140,7 +140,7 @@ module {:options "/functionSyntax:4" } SerializeFunctions { readRange: seq ) requires buffer.start <= verifiedTail.start <= |buffer.bytes| - // We require that we have correctly read up to the point where we have verified we have read to + // We require that we have correctly read up to the point where we have verified we have read to requires CorrectlyReadRange(buffer, verifiedTail, buffer.bytes[buffer.start..verifiedTail.start]) // By moving the pointer to now start at verifiedTail we want to require that packing on the size of // readRange we stay within the bounds of the buffer. @@ -159,7 +159,7 @@ module {:options "/functionSyntax:4" } SerializeFunctions { reveal CorrectlyReadRange(); CorrectlyReadByteRange(verifiedTail, tail, readRange); } - + // This function is trivial, // but it lets `Read` have a `Write` function // for its `CorrectlyRead` ensures clause. @@ -357,9 +357,9 @@ module {:options "/functionSyntax:4" } SerializeFunctions { bytes: seq ) ensures CorrectlyReadableByteRange?(buffer, bytes) - ==> - && buffer.start <= buffer.start + |bytes| <= |buffer.bytes| - && CorrectlyReadRange(buffer, buffer, buffer.bytes[buffer.start..buffer.start]) + ==> + && buffer.start <= buffer.start + |bytes| <= |buffer.bytes| + && CorrectlyReadRange(buffer, buffer, buffer.bytes[buffer.start..buffer.start]) { reveal CorrectlyReadRange(); CorrectlyReadRange(buffer, MoveStart(buffer, |bytes|), bytes) @@ -386,7 +386,7 @@ module {:options "/functionSyntax:4" } SerializeFunctions { // verfified tail is what we have read and verified we have correctly read // require that it is not longer than the length of bytes available requires buffer.start <= verifiedTail.start <= |buffer.bytes| - // In order to pack on readRange? we MUST require that we have correctly read up to + // In order to pack on readRange? we MUST require that we have correctly read up to // verifiedTail. We could get the completeness that packing on verifiedTail succeeded from another // lemma, but in order to pack on we MUST be able to read up until the verifiedTail. requires CorrectlyReadRange(buffer, verifiedTail, buffer.bytes[buffer.start..verifiedTail.start]) @@ -412,19 +412,19 @@ module {:options "/functionSyntax:4" } SerializeFunctions { requires // Links data to the buffer so we know these bytes are the same && Write(data) == bytes - // Here we have the buffer and we require that we can correctly read - // up to the length of bytes or what we have written, + // Here we have the buffer and we require that we can correctly read + // up to the length of bytes or what we have written, && CorrectlyReadableByteRange?(buffer, bytes) ensures && ret.data == data && Success(ret) == Read(buffer, |bytes|) { reveal CorrectlyReadRange(); - // After we have written data and gotten its length we can read its length from - // the buffer and we know we can do this from our precondition. + // After we have written data and gotten its length we can read its length from + // the buffer and we know we can do this from our precondition. ret := Read(buffer, |Write(data)|).value; // After we have read what we have writen we need to prove - // that we can read the length of the what we wrote + // that we can read the length of the what we wrote // In order to satisfy the postcondition CorrectlyReadByteRange(buffer, ret.tail, bytes); } diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/V1HeaderBody.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/V1HeaderBody.dfy index 39e8e5f45..abad47979 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/V1HeaderBody.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/src/Serialize/V1HeaderBody.dfy @@ -155,7 +155,7 @@ module {:options "/functionSyntax:4" } V1HeaderBody { assert RESERVED_BYTES == reservedBytes.data; assert body.algorithmSuite == suite.data; assert GetIvLength(body.algorithmSuite) == headerIvLength.data; - // Messages are different if there is an expanded AAD Section + // Messages are different if there is an expanded AAD Section if IsV1ExpandedAADSection(buffer) { // In order to prove we have the correct construction we throw in the inverse of what we read; which // is the write. In the following asserts we are basically saying, "to prove I can read this part of diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/Fixtures.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/Fixtures.dfy index a7d7d5652..b0764eb7e 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/Fixtures.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/Fixtures.dfy @@ -10,18 +10,18 @@ module Fixtures { import mplTypes = AwsCryptographyMaterialProvidersTypes import opened UInt = StandardLibrary.UInt import Primitives = AtomicPrimitives - + // The following are test resources that exist in tests accounts: // THESE ARE TESTING RESOURCES DO NOT USE IN A PRODUCTION ENVIRONMENT const keyArn := "arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f" const hierarchyKeyArn := "arn:aws:kms:us-west-2:370957321024:key/9d989aa2-2f9c-438c-a745-cc57d3ad0126" const mkrKeyArn := "arn:aws:kms:us-west-2:370957321024:key/mrk-63d386cb70614ea59b32ad65c9315297" - + const branchKeyStoreName := "KeyStoreDdbTable" const logicalKeyStoreName := branchKeyStoreName const branchKeyId := "75789115-1deb-4fe3-a2ec-be9e885d1945" - + // UTF-8 encoded "aws-crypto-" const RESERVED_ENCRYPTION_CONTEXT: UTF8.ValidUTF8Bytes := var s := [ 0x61, 0x77, 0x73, 0x2D, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6F, 0x2D ]; @@ -41,7 +41,7 @@ module Fixtures { var valC :- expect UTF8.Encode("valC"); var keyD :- expect UTF8.Encode("keyD"); var valD :- expect UTF8.Encode("valD"); - + match v { case Empty => encryptionContext := map[]; @@ -66,7 +66,7 @@ module Fixtures { { var reservedKey :- expect UTF8.Encode("aws-crypto-public-key"); var val :- expect UTF8.Encode("not a real public key"); - + encryptionContext := map[reservedKey := val]; } @@ -126,7 +126,7 @@ module Fixtures { } - + method NamespaceAndName(n: nat) returns (namespace: string, name: string) requires 0 <= n < 10 ensures |namespace| < UINT16_LIMIT @@ -136,19 +136,19 @@ module Fixtures { namespace := s + " Namespace"; name := s + " Name"; } - + method GenerateKeyPair( keyModulusLength: primitivesTypes.RSAModulusLengthBitsToGenerate ) returns (keys: primitivesTypes.GenerateRSAKeyPairOutput) { - var cryptoX: primitivesTypes.IAwsCryptographicPrimitivesClient :- expect Primitives.AtomicPrimitives(); - assert cryptoX is Primitives.AtomicPrimitivesClient; - var crypto := cryptoX as Primitives.AtomicPrimitivesClient; + var cryptoX: primitivesTypes.IAwsCryptographicPrimitivesClient :- expect Primitives.AtomicPrimitives(); + assert cryptoX is Primitives.AtomicPrimitivesClient; + var crypto := cryptoX as Primitives.AtomicPrimitivesClient; - keys :- expect crypto.GenerateRSAKeyPair( + keys :- expect crypto.GenerateRSAKeyPair( primitivesTypes.GenerateRSAKeyPairInput( - lengthBits := keyModulusLength + lengthBits := keyModulusLength ) - ); + ); } - + } diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestCreateEsdkClient.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestCreateEsdkClient.dfy index dbd9bc181..6dbe5b0df 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestCreateEsdkClient.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestCreateEsdkClient.dfy @@ -4,109 +4,109 @@ include "../src/Index.dfy" module TestCreateEsdkClient { - import Types = AwsCryptographyEncryptionSdkTypes - import mplTypes = AwsCryptographyMaterialProvidersTypes - import ESDK - import MaterialProviders - import opened Wrappers - import opened UInt = StandardLibrary.UInt - - - // THIS IS AN INCORRECTLY SERIALIZED CIPHERTEXT PRODUCED BY - // THE ESDK .NET V4.0.0 - // This message was constructucted with a zeroed 32 byte AES Key - // using v4.0.0 of the Encryption SDK for .NET which incorrectly - // serializes the message header making messages unreadble in - // other implementations and making this version unable to - // read other implementation's messages. - const ESDK_NET_V400_MESSAGE: seq := [ - 2, 5, 120, 238, 5, 239, 107, 129, 136, 211, 103, 75, 18, 140, - 11, 74, 26, 191, 92, 27, 202, 170, 33, 28, 9, 117, 252, 29, 29, - 92, 213, 21, 231, 172, 234, 0, 95, 0, 1, 0, 21, 97, 119, 115, 45, - 99, 114, 121, 112, 116, 111, 45, 112, 117, 98, 108, 105, 99, 45, 107, - 101, 121, 0, 68, 65, 119, 102, 117, 103, 90, 99, 107, 57, 116, 100, 53, - 104, 78, 108, 49, 78, 108, 75, 111, 47, 104, 105, 114, 53, 85, 47, 48, 81, - 109, 98, 73, 111, 107, 79, 72, 81, 87, 97, 72, 83, 43, 115, 117, 119, 75, - 73, 77, 82, 76, 99, 67, 80, 49, 54, 55, 56, 43, 49, 82, 75, 49, 48, 82, - 101, 119, 61, 61, 0, 1, 0, 21, 83, 111, 109, 101, 32, 109, 97, 110, 97, - 103, 101, 100, 32, 114, 97, 119, 32, 107, 101, 121, 115, 0, 47, 77, 121, - 32, 50, 53, 54, 45, 98, 105, 116, 32, 65, 69, 83, 32, 119, 114, 97, 112, - 112, 105, 110, 103, 32, 107, 101, 121, 0, 0, 0, 128, 0, 0, 0, 12, 229, 254, - 197, 205, 110, 124, 222, 48, 217, 121, 252, 11, 0, 48, 64, 60, 232, 232, 76, - 229, 15, 118, 224, 152, 79, 93, 113, 166, 255, 172, 255, 148, 185, 150, 195, 179, - 78, 52, 186, 38, 216, 48, 118, 45, 113, 204, 71, 102, 116, 148, 199, 109, 178, - 19, 2, 203, 150, 201, 65, 32, 199, 180, 2, 0, 0, 16, 0, 67, 72, 208, 112, 230, - 137, 188, 187, 0, 28, 183, 198, 192, 45, 248, 108, 2, 129, 34, 42, 59, 155, 70, - 117, 182, 216, 239, 27, 210, 78, 62, 104, 181, 247, 141, 50, 133, 42, 72, 200, - 185, 57, 20, 49, 193, 240, 171, 140, 255, 255, 255, 255, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 15, 67, 37, 106, 11, 15, 23, 78, 239, 208, - 185, 4, 36, 182, 9, 63, 62, 83, 97, 42, 250, 252, 185, 165, 14, 182, 231, 83, - 176, 227, 191, 92, 0, 103, 48, 101, 2, 49, 0, 193, 152, 7, 169, 197, 137, 244, - 88, 9, 1, 6, 56, 96, 13, 220, 201, 56, 16, 50, 68, 70, 36, 174, 38, 14, 241, 207, - 11, 139, 154, 166, 224, 191, 20, 12, 175, 56, 117, 183, 120, 119, 228, 173, 130, - 71, 110, 211, 189, 2, 48, 99, 98, 250, 36, 53, 182, 2, 204, 198, 55, 150, 51, - 159, 101, 231, 34, 42, 30, 57, 204, 88, 114, 138, 94, 12, 79, 52, 71, 178, - 34, 61, 246, 55, 163, 145, 95, 80, 61, 85, 143, 32, 0, 98, 20, 88, 251, 204, 5 - ]; - - method {:test} TestClientCreation() { - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - - var esdk: Types.IAwsEncryptionSdkClient :- expect ESDK.ESDK(config := defaultConfig); - expect esdk is ESDK.ESDKClient; - var esdkClient := esdk as ESDK.ESDKClient; - - expect esdkClient.config.commitmentPolicy == defaultConfig.commitmentPolicy.value; - expect esdkClient.config.maxEncryptedDataKeys == defaultConfig.maxEncryptedDataKeys; - expect esdkClient.config.netV4_0_0_RetryPolicy == Types.NetV4_0_0_RetryPolicy.ALLOW_RETRY; - } - - method {:test} TestNetRetryFlag() { - var mpl :- expect MaterialProviders.MaterialProviders(); - var keyNamespace := "Some managed raw keys"; - var keyName := "My 256-bit AES wrapping key"; - var expectedMessage : seq := [84,104,105,115,32,105,115,32,97,32,116,101,115,116,46]; - - var rawAesKeyring :- expect mpl.CreateRawAesKeyring(mplTypes.CreateRawAesKeyringInput( - keyNamespace := keyNamespace, - keyName := keyName, - wrappingKey := seq(32, i => 0), - wrappingAlg := mplTypes.ALG_AES256_GCM_IV12_TAG16 - )); - - // Attempt to decrypt the v4.0.0 message without the retry flag and expect - // decryption to fail - var esdkConfig := Types.AwsEncryptionSdkConfig( - commitmentPolicy := Some(mplTypes.ESDKCommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT), - maxEncryptedDataKeys := None, - netV4_0_0_RetryPolicy := Some(Types.NetV4_0_0_RetryPolicy.FORBID_RETRY) - ); - - var noRetryEsdk :- expect ESDK.ESDK(config := esdkConfig); - - var expectFailureDecryptOutput := noRetryEsdk.Decrypt(Types.DecryptInput( - ciphertext := ESDK_NET_V400_MESSAGE, - materialsManager := None, - keyring := Some(rawAesKeyring), - encryptionContext := None - )); - - expect expectFailureDecryptOutput.Failure?; - - // Decrypt v4.0.0 message with the default configuration which is to retry - // and expect decryption to pass - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - - var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := ESDK_NET_V400_MESSAGE, - materialsManager := None, - keyring := Some(rawAesKeyring), - encryptionContext := None - )); - - expect decryptOutput.Success?; - expect decryptOutput.value.plaintext == expectedMessage; - } + import Types = AwsCryptographyEncryptionSdkTypes + import mplTypes = AwsCryptographyMaterialProvidersTypes + import ESDK + import MaterialProviders + import opened Wrappers + import opened UInt = StandardLibrary.UInt + + + // THIS IS AN INCORRECTLY SERIALIZED CIPHERTEXT PRODUCED BY + // THE ESDK .NET V4.0.0 + // This message was constructucted with a zeroed 32 byte AES Key + // using v4.0.0 of the Encryption SDK for .NET which incorrectly + // serializes the message header making messages unreadble in + // other implementations and making this version unable to + // read other implementation's messages. + const ESDK_NET_V400_MESSAGE: seq := [ + 2, 5, 120, 238, 5, 239, 107, 129, 136, 211, 103, 75, 18, 140, + 11, 74, 26, 191, 92, 27, 202, 170, 33, 28, 9, 117, 252, 29, 29, + 92, 213, 21, 231, 172, 234, 0, 95, 0, 1, 0, 21, 97, 119, 115, 45, + 99, 114, 121, 112, 116, 111, 45, 112, 117, 98, 108, 105, 99, 45, 107, + 101, 121, 0, 68, 65, 119, 102, 117, 103, 90, 99, 107, 57, 116, 100, 53, + 104, 78, 108, 49, 78, 108, 75, 111, 47, 104, 105, 114, 53, 85, 47, 48, 81, + 109, 98, 73, 111, 107, 79, 72, 81, 87, 97, 72, 83, 43, 115, 117, 119, 75, + 73, 77, 82, 76, 99, 67, 80, 49, 54, 55, 56, 43, 49, 82, 75, 49, 48, 82, + 101, 119, 61, 61, 0, 1, 0, 21, 83, 111, 109, 101, 32, 109, 97, 110, 97, + 103, 101, 100, 32, 114, 97, 119, 32, 107, 101, 121, 115, 0, 47, 77, 121, + 32, 50, 53, 54, 45, 98, 105, 116, 32, 65, 69, 83, 32, 119, 114, 97, 112, + 112, 105, 110, 103, 32, 107, 101, 121, 0, 0, 0, 128, 0, 0, 0, 12, 229, 254, + 197, 205, 110, 124, 222, 48, 217, 121, 252, 11, 0, 48, 64, 60, 232, 232, 76, + 229, 15, 118, 224, 152, 79, 93, 113, 166, 255, 172, 255, 148, 185, 150, 195, 179, + 78, 52, 186, 38, 216, 48, 118, 45, 113, 204, 71, 102, 116, 148, 199, 109, 178, + 19, 2, 203, 150, 201, 65, 32, 199, 180, 2, 0, 0, 16, 0, 67, 72, 208, 112, 230, + 137, 188, 187, 0, 28, 183, 198, 192, 45, 248, 108, 2, 129, 34, 42, 59, 155, 70, + 117, 182, 216, 239, 27, 210, 78, 62, 104, 181, 247, 141, 50, 133, 42, 72, 200, + 185, 57, 20, 49, 193, 240, 171, 140, 255, 255, 255, 255, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 15, 67, 37, 106, 11, 15, 23, 78, 239, 208, + 185, 4, 36, 182, 9, 63, 62, 83, 97, 42, 250, 252, 185, 165, 14, 182, 231, 83, + 176, 227, 191, 92, 0, 103, 48, 101, 2, 49, 0, 193, 152, 7, 169, 197, 137, 244, + 88, 9, 1, 6, 56, 96, 13, 220, 201, 56, 16, 50, 68, 70, 36, 174, 38, 14, 241, 207, + 11, 139, 154, 166, 224, 191, 20, 12, 175, 56, 117, 183, 120, 119, 228, 173, 130, + 71, 110, 211, 189, 2, 48, 99, 98, 250, 36, 53, 182, 2, 204, 198, 55, 150, 51, + 159, 101, 231, 34, 42, 30, 57, 204, 88, 114, 138, 94, 12, 79, 52, 71, 178, + 34, 61, 246, 55, 163, 145, 95, 80, 61, 85, 143, 32, 0, 98, 20, 88, 251, 204, 5 + ]; + + method {:test} TestClientCreation() { + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + + var esdk: Types.IAwsEncryptionSdkClient :- expect ESDK.ESDK(config := defaultConfig); + expect esdk is ESDK.ESDKClient; + var esdkClient := esdk as ESDK.ESDKClient; + + expect esdkClient.config.commitmentPolicy == defaultConfig.commitmentPolicy.value; + expect esdkClient.config.maxEncryptedDataKeys == defaultConfig.maxEncryptedDataKeys; + expect esdkClient.config.netV4_0_0_RetryPolicy == Types.NetV4_0_0_RetryPolicy.ALLOW_RETRY; + } + + method {:test} TestNetRetryFlag() { + var mpl :- expect MaterialProviders.MaterialProviders(); + var keyNamespace := "Some managed raw keys"; + var keyName := "My 256-bit AES wrapping key"; + var expectedMessage : seq := [84,104,105,115,32,105,115,32,97,32,116,101,115,116,46]; + + var rawAesKeyring :- expect mpl.CreateRawAesKeyring(mplTypes.CreateRawAesKeyringInput( + keyNamespace := keyNamespace, + keyName := keyName, + wrappingKey := seq(32, i => 0), + wrappingAlg := mplTypes.ALG_AES256_GCM_IV12_TAG16 + )); + + // Attempt to decrypt the v4.0.0 message without the retry flag and expect + // decryption to fail + var esdkConfig := Types.AwsEncryptionSdkConfig( + commitmentPolicy := Some(mplTypes.ESDKCommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT), + maxEncryptedDataKeys := None, + netV4_0_0_RetryPolicy := Some(Types.NetV4_0_0_RetryPolicy.FORBID_RETRY) + ); + + var noRetryEsdk :- expect ESDK.ESDK(config := esdkConfig); + + var expectFailureDecryptOutput := noRetryEsdk.Decrypt(Types.DecryptInput( + ciphertext := ESDK_NET_V400_MESSAGE, + materialsManager := None, + keyring := Some(rawAesKeyring), + encryptionContext := None + )); + + expect expectFailureDecryptOutput.Failure?; + + // Decrypt v4.0.0 message with the default configuration which is to retry + // and expect decryption to pass + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + + var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := ESDK_NET_V400_MESSAGE, + materialsManager := None, + keyring := Some(rawAesKeyring), + encryptionContext := None + )); + + expect decryptOutput.Success?; + expect decryptOutput.value.plaintext == expectedMessage; + } } diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestEncryptDecrypt.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestEncryptDecrypt.dfy index e195f96e8..767292d45 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestEncryptDecrypt.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestEncryptDecrypt.dfy @@ -6,56 +6,56 @@ include "../src/Index.dfy" include "Fixtures.dfy" module TestEncryptDecrypt { - import Types = AwsCryptographyEncryptionSdkTypes - import mplTypes = AwsCryptographyMaterialProvidersTypes - import MaterialProviders - import ESDK - import opened Wrappers - - import Fixtures - - method {:test} TestEncryptDecrypt() - { - var kmsKey := Fixtures.keyArn; - // The string "asdf" as bytes - var asdf := [ 97, 115, 100, 102 ]; - - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - var mpl :- expect MaterialProviders.MaterialProviders(); - var clientSupplier :- expect mpl.CreateDefaultClientSupplier(mplTypes.CreateDefaultClientSupplierInput); - var kmsClient :- expect clientSupplier.GetClient(mplTypes.GetClientInput(region := "us-west-2")); - - var kmsKeyring :- expect mpl.CreateAwsKmsKeyring( - mplTypes.CreateAwsKmsKeyringInput( - kmsKeyId := kmsKey, - kmsClient := kmsClient, - grantTokens := None - ) - ); - - var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := None, - materialsManager := None, - keyring := Some(kmsKeyring), - algorithmSuiteId := None, - frameLength := None - )); - - expect encryptOutput.Success?; - var esdkCiphertext := encryptOutput.value.ciphertext; - - var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(kmsKeyring), - encryptionContext := None - )); - - expect decryptOutput.Success?; - var cycledPlaintext := decryptOutput.value.plaintext; - - expect cycledPlaintext == asdf; - } + import Types = AwsCryptographyEncryptionSdkTypes + import mplTypes = AwsCryptographyMaterialProvidersTypes + import MaterialProviders + import ESDK + import opened Wrappers + + import Fixtures + + method {:test} TestEncryptDecrypt() + { + var kmsKey := Fixtures.keyArn; + // The string "asdf" as bytes + var asdf := [ 97, 115, 100, 102 ]; + + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + var mpl :- expect MaterialProviders.MaterialProviders(); + var clientSupplier :- expect mpl.CreateDefaultClientSupplier(mplTypes.CreateDefaultClientSupplierInput); + var kmsClient :- expect clientSupplier.GetClient(mplTypes.GetClientInput(region := "us-west-2")); + + var kmsKeyring :- expect mpl.CreateAwsKmsKeyring( + mplTypes.CreateAwsKmsKeyringInput( + kmsKeyId := kmsKey, + kmsClient := kmsClient, + grantTokens := None + ) + ); + + var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := None, + materialsManager := None, + keyring := Some(kmsKeyring), + algorithmSuiteId := None, + frameLength := None + )); + + expect encryptOutput.Success?; + var esdkCiphertext := encryptOutput.value.ciphertext; + + var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(kmsKeyring), + encryptionContext := None + )); + + expect decryptOutput.Success?; + var cycledPlaintext := decryptOutput.value.plaintext; + + expect cycledPlaintext == asdf; + } } diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestReproducedEncContext.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestReproducedEncContext.dfy index c27eaa1db..c97263faf 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestReproducedEncContext.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestReproducedEncContext.dfy @@ -6,168 +6,168 @@ include "../src/Index.dfy" include "Fixtures.dfy" module TestReproducedEncryptionContext { - import Types = AwsCryptographyEncryptionSdkTypes - import mplTypes = AwsCryptographyMaterialProvidersTypes - import MaterialProviders - import ESDK - import opened Wrappers - - import Fixtures - - method {:test} TestEncryptionContextOnDecrypt() - { - var kmsKey := Fixtures.keyArn; - // The string "asdf" as bytes - var asdf := [ 97, 115, 100, 102 ]; - - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - var mpl :- expect MaterialProviders.MaterialProviders(); - var clientSupplier :- expect mpl.CreateDefaultClientSupplier(mplTypes.CreateDefaultClientSupplierInput); - var kmsClient :- expect clientSupplier.GetClient(mplTypes.GetClientInput(region := "us-west-2")); - - var kmsKeyring :- expect mpl.CreateAwsKmsKeyring( - mplTypes.CreateAwsKmsKeyringInput( - kmsKeyId := kmsKey, - kmsClient := kmsClient, - grantTokens := None - ) - ); - - var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); - - var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := None, - keyring := Some(kmsKeyring), - algorithmSuiteId := None, - frameLength := None - )); - - expect encryptOutput.Success?; - var esdkCiphertext := encryptOutput.value.ciphertext; - - var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(kmsKeyring), - encryptionContext := Some(encryptionContext) - )); - - expect decryptOutput.Success?; - var cycledPlaintext := decryptOutput.value.plaintext; - - expect cycledPlaintext == asdf; - } - - method {:test} TestEncryptionContextOnDecryptFailure() - { - var kmsKey := Fixtures.keyArn; - // The string "asdf" as bytes - var asdf := [ 97, 115, 100, 102 ]; - - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - var mpl :- expect MaterialProviders.MaterialProviders(); - var clientSupplier :- expect mpl.CreateDefaultClientSupplier(mplTypes.CreateDefaultClientSupplierInput); - var kmsClient :- expect clientSupplier.GetClient(mplTypes.GetClientInput(region := "us-west-2")); - - var kmsKeyring :- expect mpl.CreateAwsKmsKeyring( - mplTypes.CreateAwsKmsKeyringInput( - kmsKeyId := kmsKey, - kmsClient := kmsClient, - grantTokens := None - ) - ); - - var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.A); - var incorrectReproducedEncryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); - - var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := None, - keyring := Some(kmsKeyring), - algorithmSuiteId := None, - frameLength := None - )); - - expect encryptOutput.Success?; - var esdkCiphertext := encryptOutput.value.ciphertext; - - var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(kmsKeyring), - encryptionContext := Some(incorrectReproducedEncryptionContext) - )); - - // We expect to fail because we pass more encryption context than was used on encrypt - expect decryptOutput.Failure?; - } - - method {:test} TestMismatchedEncryptionContextOnDecrypt() - { - // The string "asdf" as bytes - var asdf := [ 97, 115, 100, 102 ]; - - var namespace, name := Fixtures.NamespaceAndName(0); - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - var mpl :- expect MaterialProviders.MaterialProviders(); - var rawAESKeyring :- expect mpl.CreateRawAesKeyring(mplTypes.CreateRawAesKeyringInput( - keyNamespace := namespace, - keyName := name, - wrappingKey := seq(32, i => 0), - wrappingAlg := mplTypes.ALG_AES256_GCM_IV12_TAG16 - )); - - var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.A); - var mismatchedEncryptionContext := Fixtures.SmallMismatchedEncryptionContex(Fixtures.SmallEncryptionContextVariation.A); - - var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := None, - keyring := Some(rawAESKeyring), - algorithmSuiteId := None, - frameLength := None - )); - - expect encryptOutput.Success?; - var esdkCiphertext := encryptOutput.value.ciphertext; - - var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(rawAESKeyring), - encryptionContext := Some(mismatchedEncryptionContext) - )); - - // We expect to fail because although the same key is present on the ec - // their value is different. - expect decryptOutput.Failure?; - - // test that if we supply the right ec we will succeed - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(rawAESKeyring), - encryptionContext := Some(encryptionContext) - )); - - expect decryptOutput.Success?; - - // Since we store all encryption context we MST succeed if no encryption context is - // supplied on decrypt - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(rawAESKeyring), - encryptionContext := None - )); - - expect decryptOutput.Success?; - } + import Types = AwsCryptographyEncryptionSdkTypes + import mplTypes = AwsCryptographyMaterialProvidersTypes + import MaterialProviders + import ESDK + import opened Wrappers + + import Fixtures + + method {:test} TestEncryptionContextOnDecrypt() + { + var kmsKey := Fixtures.keyArn; + // The string "asdf" as bytes + var asdf := [ 97, 115, 100, 102 ]; + + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + var mpl :- expect MaterialProviders.MaterialProviders(); + var clientSupplier :- expect mpl.CreateDefaultClientSupplier(mplTypes.CreateDefaultClientSupplierInput); + var kmsClient :- expect clientSupplier.GetClient(mplTypes.GetClientInput(region := "us-west-2")); + + var kmsKeyring :- expect mpl.CreateAwsKmsKeyring( + mplTypes.CreateAwsKmsKeyringInput( + kmsKeyId := kmsKey, + kmsClient := kmsClient, + grantTokens := None + ) + ); + + var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); + + var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := None, + keyring := Some(kmsKeyring), + algorithmSuiteId := None, + frameLength := None + )); + + expect encryptOutput.Success?; + var esdkCiphertext := encryptOutput.value.ciphertext; + + var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(kmsKeyring), + encryptionContext := Some(encryptionContext) + )); + + expect decryptOutput.Success?; + var cycledPlaintext := decryptOutput.value.plaintext; + + expect cycledPlaintext == asdf; + } + + method {:test} TestEncryptionContextOnDecryptFailure() + { + var kmsKey := Fixtures.keyArn; + // The string "asdf" as bytes + var asdf := [ 97, 115, 100, 102 ]; + + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + var mpl :- expect MaterialProviders.MaterialProviders(); + var clientSupplier :- expect mpl.CreateDefaultClientSupplier(mplTypes.CreateDefaultClientSupplierInput); + var kmsClient :- expect clientSupplier.GetClient(mplTypes.GetClientInput(region := "us-west-2")); + + var kmsKeyring :- expect mpl.CreateAwsKmsKeyring( + mplTypes.CreateAwsKmsKeyringInput( + kmsKeyId := kmsKey, + kmsClient := kmsClient, + grantTokens := None + ) + ); + + var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.A); + var incorrectReproducedEncryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); + + var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := None, + keyring := Some(kmsKeyring), + algorithmSuiteId := None, + frameLength := None + )); + + expect encryptOutput.Success?; + var esdkCiphertext := encryptOutput.value.ciphertext; + + var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(kmsKeyring), + encryptionContext := Some(incorrectReproducedEncryptionContext) + )); + + // We expect to fail because we pass more encryption context than was used on encrypt + expect decryptOutput.Failure?; + } + + method {:test} TestMismatchedEncryptionContextOnDecrypt() + { + // The string "asdf" as bytes + var asdf := [ 97, 115, 100, 102 ]; + + var namespace, name := Fixtures.NamespaceAndName(0); + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + var mpl :- expect MaterialProviders.MaterialProviders(); + var rawAESKeyring :- expect mpl.CreateRawAesKeyring(mplTypes.CreateRawAesKeyringInput( + keyNamespace := namespace, + keyName := name, + wrappingKey := seq(32, i => 0), + wrappingAlg := mplTypes.ALG_AES256_GCM_IV12_TAG16 + )); + + var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.A); + var mismatchedEncryptionContext := Fixtures.SmallMismatchedEncryptionContex(Fixtures.SmallEncryptionContextVariation.A); + + var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := None, + keyring := Some(rawAESKeyring), + algorithmSuiteId := None, + frameLength := None + )); + + expect encryptOutput.Success?; + var esdkCiphertext := encryptOutput.value.ciphertext; + + var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(rawAESKeyring), + encryptionContext := Some(mismatchedEncryptionContext) + )); + + // We expect to fail because although the same key is present on the ec + // their value is different. + expect decryptOutput.Failure?; + + // test that if we supply the right ec we will succeed + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(rawAESKeyring), + encryptionContext := Some(encryptionContext) + )); + + expect decryptOutput.Success?; + + // Since we store all encryption context we MST succeed if no encryption context is + // supplied on decrypt + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(rawAESKeyring), + encryptionContext := None + )); + + expect decryptOutput.Success?; + } } \ No newline at end of file diff --git a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestRequiredEncryptionContext.dfy b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestRequiredEncryptionContext.dfy index 8c78050a2..77d9ac2c3 100644 --- a/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestRequiredEncryptionContext.dfy +++ b/AwsEncryptionSDK/dafny/AwsEncryptionSdk/test/TestRequiredEncryptionContext.dfy @@ -6,1147 +6,1147 @@ include "../src/Index.dfy" include "Fixtures.dfy" module TestRequiredEncryptionContext { - import Types = AwsCryptographyEncryptionSdkTypes - import mplTypes = AwsCryptographyMaterialProvidersTypes - import primitivesTypes = AwsCryptographyPrimitivesTypes - import KeyStoreTypes = AwsCryptographyKeyStoreTypes - import MaterialProviders - import KeyStore - import ComAmazonawsKmsTypes - import KMS = Com.Amazonaws.Kms - import DDB = Com.Amazonaws.Dynamodb - import DDBTypes = ComAmazonawsDynamodbTypes - import ESDK - import opened Wrappers - import UTF8 - - import Fixtures - - // THIS IS A TESTING RESOURCE DO NOT USE IN A PRODUCTION ENVIRONMENT - const keyArn := Fixtures.keyArn - const hierarchyKeyArn := Fixtures.hierarchyKeyArn; - const branchKeyStoreName: DDBTypes.TableName := Fixtures.branchKeyStoreName - const logicalKeyStoreName := branchKeyStoreName - // These tests require a keystore populated with these keys - const BRANCH_KEY_ID := Fixtures.branchKeyId - - method {:test} TestReprEncryptionContextWithSameECHappyCase() - { - // The string "asdf" as bytes - var asdf := [ 97, 115, 100, 102 ]; - - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - var mpl :- expect MaterialProviders.MaterialProviders(); - - // get keyrings - var rsaKeyring := GetRsaKeyring(); - var kmsKeyring := GetKmsKeyring(); - var aesKeyring := GetAesKeyring(); - var hKeyring := GetHierarchicalKeyring(); - - var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( - generator := Some(aesKeyring), - childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] - )); - - // HAPPY CASE 1 - // Test supply same encryption context on encrypt and decrypt NO filtering - var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); - - var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := None, - keyring := Some(multiKeyring), - algorithmSuiteId := None, - frameLength := None - )); - - expect encryptOutput.Success?; - var esdkCiphertext := encryptOutput.value.ciphertext; - - // Test RSA - var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(rsaKeyring), - encryptionContext := Some(encryptionContext) - )); - - expect decryptOutput.Success?; - var cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - - // Test KMS - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(kmsKeyring), - encryptionContext := Some(encryptionContext) - )); - - expect decryptOutput.Success?; - cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - - // Test AES - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(aesKeyring), - encryptionContext := Some(encryptionContext) - )); - - expect decryptOutput.Success?; - cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - - // Test Hierarchy Keyring - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(hKeyring), - encryptionContext := Some(encryptionContext) - )); - - expect decryptOutput.Success?; - cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - } - - method {:test} TestRemoveOnEncryptAndSupplyOnDecryptHappyCase() - { - // The string "asdf" as bytes - var asdf := [ 97, 115, 100, 102 ]; - - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - var mpl :- expect MaterialProviders.MaterialProviders(); - - // get keyrings - var rsaKeyring := GetRsaKeyring(); - var kmsKeyring := GetKmsKeyring(); - var aesKeyring := GetAesKeyring(); - var hKeyring := GetHierarchicalKeyring(); - - var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( - generator := Some(aesKeyring), - childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] - )); - - // Happy Test Case 2 - // On Encrypt we will only write one encryption context key value to the header - // we will then supply only what we didn't write wth no required ec cmm, - // This test case is checking that the default cmm is doing the correct filtering by using - var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); - var reproducedEncryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.A); - // These keys mean that we will not write these on the message but are required for message authentication on decrypt. - var requiredEncryptionContextKeys := Fixtures.SmallEncryptionContextKeys(Fixtures.SmallEncryptionContextVariation.A); - - // TEST RSA - var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := multiKeyring - ) - ); - - // Create Required EC CMM with the required EC Keys we want - var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - // At the moment reqCMM can only be created with a CMM, you cannot - // create one by only passing in a keyring. - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) - ); - - var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(reqCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None - )); - - expect encryptOutput.Success?; - var esdkCiphertext := encryptOutput.value.ciphertext; - - // Switch to only RSA keyring - var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(rsaKeyring), - encryptionContext := Some(reproducedEncryptionContext) - )); - - expect decryptOutput.Success?; - var cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - - // Switch to only KMS keyring - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(kmsKeyring), - encryptionContext := Some(reproducedEncryptionContext) - )); - - expect decryptOutput.Success?; - cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - - // Switch to only AES keyring - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(aesKeyring), - encryptionContext := Some(reproducedEncryptionContext) - )); - - expect decryptOutput.Success?; - cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - - // Switch to only Hierarchical keyring - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(hKeyring), - encryptionContext := Some(reproducedEncryptionContext) - )); - - expect decryptOutput.Success?; - cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - - } - - method {:test} TestRemoveOnEncryptRemoveAndSupplyOnDecryptHappyCase() - { - // The string "asdf" as bytes - var asdf := [ 97, 115, 100, 102 ]; - - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - var mpl :- expect MaterialProviders.MaterialProviders(); - - // get keyrings - var rsaKeyring := GetRsaKeyring(); - var kmsKeyring := GetKmsKeyring(); - var aesKeyring := GetAesKeyring(); - var hKeyring := GetHierarchicalKeyring(); - - var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( - generator := Some(aesKeyring), - childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] - )); - - // HAPPY CASE 3 - // On Encrypt we will only write one encryption context key value to the header - // we will then supply only what we didn't write but included in the signature while we - // are configured with the required encryption context cmm - var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); - var reproducedEncryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.A); - // These keys mean that we will not write these on the message but are required for message authentication on decrypt. - var requiredEncryptionContextKeys := Fixtures.SmallEncryptionContextKeys(Fixtures.SmallEncryptionContextVariation.A); - - // TEST RSA - var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := multiKeyring - ) - ); - - // Create Required EC CMM with the required EC Keys we want - var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - // At the moment reqCMM can only be created with a CMM, you cannot - // create one by only passing in a keyring. - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) - ); - - var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(reqCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None - )); - - expect encryptOutput.Success?; - var esdkCiphertext := encryptOutput.value.ciphertext; - - // Switch to only RSA keyring - defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := rsaKeyring - ) - ); - - // Create Required EC CMM with the required EC Keys we want - reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - // At the moment reqCMM can only be created with a CMM, you cannot - // create one by only passing in a keyring. - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) - ); - // Since we are passing in the correct reproduced encryption context this - // decrypt SHOULD succeed - var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := Some(reqCMM), - keyring := None, - encryptionContext := Some(reproducedEncryptionContext) - )); - - expect decryptOutput.Success?; - var cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - - // TEST KMS - // Switch to only KMS keyring - defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := kmsKeyring - ) - ); - - // Create Required EC CMM with the required EC Keys we want - reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - // At the moment reqCMM can only be created with a CMM, you cannot - // create one by only passing in a keyring. - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) - ); - // Since we are passing in the correct reproduced encryption context this - // decrypt SHOULD succeed - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := Some(reqCMM), - keyring := None, - encryptionContext := Some(reproducedEncryptionContext) - )); - - expect decryptOutput.Success?; - cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - - // TEST AES - // switch to only aes - defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := aesKeyring - ) - ); - - // Create Required EC CMM with the required EC Keys we want - reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - // At the moment reqCMM can only be created with a CMM, you cannot - // create one by only passing in a keyring. - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) - ); - // Since we are passing in the correct reproduced encryption context this - // decrypt SHOULD succeed - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := Some(reqCMM), - keyring := None, - encryptionContext := Some(reproducedEncryptionContext) - )); - - expect decryptOutput.Success?; - cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - - // TEST HIERARCHY - defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := hKeyring - ) - ); - - // Create Required EC CMM with the required EC Keys we want - reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - // At the moment reqCMM can only be created with a CMM, you cannot - // create one by only passing in a keyring. - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) - ); - // Since we are passing in the correct reproduced encryption context this - // decrypt SHOULD succeed - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := Some(reqCMM), - keyring := None, - encryptionContext := Some(reproducedEncryptionContext) - )); - - expect decryptOutput.Success?; - cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - } - - method {:test} TestRemoveOnDecryptIsBackwardsCompatibleHappyCase() - { - // The string "asdf" as bytes - var asdf := [ 97, 115, 100, 102 ]; - - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - var mpl :- expect MaterialProviders.MaterialProviders(); - - // get keyrings - var rsaKeyring := GetRsaKeyring(); - var kmsKeyring := GetKmsKeyring(); - var aesKeyring := GetAesKeyring(); - var hKeyring := GetHierarchicalKeyring(); - - var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( - generator := Some(aesKeyring), - childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] - )); - - // HAPPY CASE 4 - // On Encrypt we write all encryption context - // as if the message was encrypted before the feature existed. - // We will then have a required encryption context cmm - // that will require us to supply the encryption context on decrypt. - var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); - var reproducedEncryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.A); - // These keys mean that we will not write these on the message but are required for message authentication on decrypt. - var requiredEncryptionContextKeys := Fixtures.SmallEncryptionContextKeys(Fixtures.SmallEncryptionContextVariation.A); - - var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := multiKeyring - ) - ); - - // All encryption context is stored in the message - var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(defaultCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None - )); - - expect encryptOutput.Success?; - var esdkCiphertext := encryptOutput.value.ciphertext; - - // Switch to only RSA keyring - defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := rsaKeyring - ) - ); - - // Create Required EC CMM with the required EC Keys we want - var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - // At the moment reqCMM can only be created with a CMM, you cannot - // create one by only passing in a keyring. - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) - ); - // Since we are passing in the correct reproduced encryption context this - // decrypt SHOULD succeed - var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := Some(reqCMM), - keyring := None, - encryptionContext := Some(reproducedEncryptionContext) - )); - - expect decryptOutput.Success?; - var cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - - // TEST KMS - // Switch to only KMS keyring - defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := kmsKeyring - ) - ); - - // Create Required EC CMM with the required EC Keys we want - reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - // At the moment reqCMM can only be created with a CMM, you cannot - // create one by only passing in a keyring. - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) - ); - // Since we are passing in the correct reproduced encryption context this - // decrypt SHOULD succeed - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := Some(reqCMM), - keyring := None, - encryptionContext := Some(reproducedEncryptionContext) - )); - - expect decryptOutput.Success?; - cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - - // TEST AES - // switch to only aes - defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := aesKeyring - ) - ); - - // Create Required EC CMM with the required EC Keys we want - reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - // At the moment reqCMM can only be created with a CMM, you cannot - // create one by only passing in a keyring. - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) - ); - // Since we are passing in the correct reproduced encryption context this - // decrypt SHOULD succeed - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := Some(reqCMM), - keyring := None, - encryptionContext := Some(reproducedEncryptionContext) - )); - - expect decryptOutput.Success?; - cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - - // TEST HIERARCHY - defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := hKeyring - ) - ); - - // Create Required EC CMM with the required EC Keys we want - reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - // At the moment reqCMM can only be created with a CMM, you cannot - // create one by only passing in a keyring. - keyring := None, - requiredEncryptionContextKeys := requiredEncryptionContextKeys - ) - ); - // Since we are passing in the correct reproduced encryption context this - // decrypt SHOULD succeed - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := Some(reqCMM), - keyring := None, - encryptionContext := Some(reproducedEncryptionContext) - )); - - expect decryptOutput.Success?; - cycledPlaintext := decryptOutput.value.plaintext; - expect cycledPlaintext == asdf; - } - - method {:test} TestDifferentECOnDecryptFailure() - { - // encrypt {a, b} => decrypt {b:c} => fail - // encrypt {a, b} => decrypt {d} => fail - - // The string "asdf" as bytes - var asdf := [ 97, 115, 100, 102 ]; - - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - var mpl :- expect MaterialProviders.MaterialProviders(); - - // get keyrings - var rsaKeyring := GetRsaKeyring(); - var kmsKeyring := GetKmsKeyring(); - var aesKeyring := GetAesKeyring(); - var hKeyring := GetHierarchicalKeyring(); - - var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( - generator := Some(aesKeyring), - childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] - )); - - // FAILURE CASE 1 - // Encrypt with and store all encryption context in header - // On Decrypt supply additional encryption context not stored in the header; this MUST fail - // On Decrypt supply mismatched encryption context key values; this MUST fail - var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); - // Additional EC - var reproducedAdditionalEncryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.C); - // Mismatched EncryptionContext - var reproducedMismatchedEncryptionContext := Fixtures.SmallMismatchedEncryptionContex(Fixtures.SmallEncryptionContextVariation.AB); - - var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := None, - keyring := Some(multiKeyring), - algorithmSuiteId := None, - frameLength := None - )); - - expect encryptOutput.Success?; - var esdkCiphertext := encryptOutput.value.ciphertext; - - // Test RSA Failures - var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(rsaKeyring), - encryptionContext := Some(reproducedAdditionalEncryptionContext) - )); - - expect decryptOutput.Failure?; - - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(rsaKeyring), - encryptionContext := Some(reproducedMismatchedEncryptionContext) - )); - - expect decryptOutput.Failure?; - - // Test KMS Failures - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(kmsKeyring), - encryptionContext := Some(reproducedAdditionalEncryptionContext) - )); - - expect decryptOutput.Failure?; - - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(kmsKeyring), - encryptionContext := Some(reproducedMismatchedEncryptionContext) - )); - - expect decryptOutput.Failure?; - - // Test AES Failures - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(aesKeyring), - encryptionContext := Some(reproducedAdditionalEncryptionContext) - )); - - expect decryptOutput.Failure?; - - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(aesKeyring), - encryptionContext := Some(reproducedMismatchedEncryptionContext) - )); - - expect decryptOutput.Failure?; - - // Test Hierarchical Failures - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(hKeyring), - encryptionContext := Some(reproducedAdditionalEncryptionContext) - )); - - expect decryptOutput.Failure?; - - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(hKeyring), - encryptionContext := Some(reproducedMismatchedEncryptionContext) - )); - - expect decryptOutput.Failure?; - } - - method {:test} TestRemoveECAndNotSupplyOnDecryptFailure() - { - - // encrypt remove(a) RSA {a, b} => decrypt => fail - // encrypt remove(a) KMS {a, b} => decrypt => fail - // encrypt remove(a) AES {a, b} => decrypt => fail - // encrypt remove(a) Hie {a, b} => decrypt => fail - - // The string "asdf" as bytes - var asdf := [ 97, 115, 100, 102 ]; - - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - var mpl :- expect MaterialProviders.MaterialProviders(); - - // get keyrings - var rsaKeyring := GetRsaKeyring(); - var kmsKeyring := GetKmsKeyring(); - var aesKeyring := GetAesKeyring(); - var hKeyring := GetHierarchicalKeyring(); - - var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( - generator := Some(aesKeyring), - childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] - )); - - // FAILURE CASE 2 - // Encrypt will not store all Encryption Context, we will drop one entry but it will still get included in the - // header signture. - // Decrypt will not supply any reproduced Encryption Context; this MUST fail. - var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); - var requiredECKeys := Fixtures.SmallEncryptionContextKeys(Fixtures.SmallEncryptionContextVariation.A); - - var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := multiKeyring - ) - ); - - // Create Required EC CMM with the required EC Keys we want - var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - // At the moment reqCMM can only be created with a CMM, you cannot - // create one by only passing in a keyring. - keyring := None, - requiredEncryptionContextKeys := requiredECKeys - ) - ); - - var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(reqCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None - )); - - expect encryptOutput.Success?; - var esdkCiphertext := encryptOutput.value.ciphertext; - - // Test RSA Failure - var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(rsaKeyring), - encryptionContext := None - )); - - expect decryptOutput.Failure?; - - // Test KMS Failures - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(kmsKeyring), - encryptionContext := None - )); - - expect decryptOutput.Failure?; - - // Test AES Failures - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(aesKeyring), - encryptionContext := None - )); - - expect decryptOutput.Failure?; - - // Test Hierarchical Failures - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(hKeyring), - encryptionContext := None - )); - - expect decryptOutput.Failure?; - } - - method {:test} TestRemoveECAndSupplyMismatchedReprECFailure() - { - - // encrypt remove(a) RSA {a, b} => decrypt {b:c} => fail - // encrypt remove(a) KMS {a, b} => decrypt {b:c} => fail - // encrypt remove(a) AES {a, b} => decrypt {b:c} => fail - // encrypt remove(a) Hie {a, b} => decrypt {b:c} => fail - - // The string "asdf" as bytes - var asdf := [ 97, 115, 100, 102 ]; - - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - var mpl :- expect MaterialProviders.MaterialProviders(); - - // get keyrings - var rsaKeyring := GetRsaKeyring(); - var kmsKeyring := GetKmsKeyring(); - var aesKeyring := GetAesKeyring(); - var hKeyring := GetHierarchicalKeyring(); - - var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( - generator := Some(aesKeyring), - childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] - )); - - // FAILURE CASE 3 - // Encrypt will not store all Encryption Context, we will drop one entry but it will still get included in the - // header signture. - // Decrypt will supply the correct key but incorrect value; this MUST fail. - var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); - var requiredECKeys := Fixtures.SmallEncryptionContextKeys(Fixtures.SmallEncryptionContextVariation.A); - // this reproduced encryption context contains the key we didn't store, but it has the wrong value - var mismatchedReproducedEncryptionContext := Fixtures.SmallMismatchedEncryptionContex(Fixtures.SmallEncryptionContextVariation.A); - - var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := multiKeyring - ) - ); - - // Create Required EC CMM with the required EC Keys we want - var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - // At the moment reqCMM can only be created with a CMM, you cannot - // create one by only passing in a keyring. - keyring := None, - requiredEncryptionContextKeys := requiredECKeys - ) - ); - - var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(reqCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None - )); - - expect encryptOutput.Success?; - var esdkCiphertext := encryptOutput.value.ciphertext; - - // Test RSA Failure - var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(rsaKeyring), - encryptionContext := Some(mismatchedReproducedEncryptionContext) - )); - - expect decryptOutput.Failure?; - - // Test KMS Failures - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(kmsKeyring), - encryptionContext := Some(mismatchedReproducedEncryptionContext) - )); - - expect decryptOutput.Failure?; - - // Test AES Failures - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(aesKeyring), - encryptionContext := Some(mismatchedReproducedEncryptionContext) - )); - - expect decryptOutput.Failure?; - - // Test Hierarchical Failures - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(hKeyring), - encryptionContext := Some(mismatchedReproducedEncryptionContext) - )); - - expect decryptOutput.Failure?; - } - - method {:test} TestRemoveECAndSupplyWithMissingRequiredValueDecryptFailure() - { - // encrypt remove(a) RSA {a, b} => decrypt remove(a) => fail - // encrypt remove(a) KMS {a, b} => decrypt remove(a) => fail - // encrypt remove(a) AES {a, b} => decrypt remove(a) => fail - // encrypt remove(a) Hie {a, b} => decrypt remove(a) => fail - - // The string "asdf" as bytes - var asdf := [ 97, 115, 100, 102 ]; - - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - var mpl :- expect MaterialProviders.MaterialProviders(); - - // get keyrings - var rsaKeyring := GetRsaKeyring(); - var kmsKeyring := GetKmsKeyring(); - var aesKeyring := GetAesKeyring(); - var hKeyring := GetHierarchicalKeyring(); - - var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( - generator := Some(aesKeyring), - childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] - )); - - // FAILURE CASE 4 - // Encrypt will not store all Encryption Context, we will drop one entry but it will still get included in the - // header signture. - // Decrypt will supply the correct key but incorrect value; this MUST fail. - var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); - var requiredECKeys := Fixtures.SmallEncryptionContextKeys(Fixtures.SmallEncryptionContextVariation.A); - // this reproduced encryption context does not contain the key that was dropped - var droppedRequiredKeyEncryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.B); - - var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := multiKeyring - ) - ); - - // Create Required EC CMM with the required EC Keys we want - var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - // At the moment reqCMM can only be created with a CMM, you cannot - // create one by only passing in a keyring. - keyring := None, - requiredEncryptionContextKeys := requiredECKeys - ) - ); - - var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(reqCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None - )); - - expect encryptOutput.Success?; - var esdkCiphertext := encryptOutput.value.ciphertext; - - // Test RSA Failure - var decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(rsaKeyring), - encryptionContext := Some(droppedRequiredKeyEncryptionContext) - )); - - expect decryptOutput.Failure?; - - // Test KMS Failure - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(kmsKeyring), - encryptionContext := Some(droppedRequiredKeyEncryptionContext) - )); - - expect decryptOutput.Failure?; - - // Test AES Failure - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(aesKeyring), - encryptionContext := Some(droppedRequiredKeyEncryptionContext) - )); - - expect decryptOutput.Failure?; - - // Test Hierarchical Failure - decryptOutput := esdk.Decrypt(Types.DecryptInput( - ciphertext := esdkCiphertext, - materialsManager := None, - keyring := Some(hKeyring), - encryptionContext := Some(droppedRequiredKeyEncryptionContext) - )); - - expect decryptOutput.Failure?; - - } - - method {:test} TestReservedEncryptionContextKeyFailure() - { - // The string "asdf" as bytes - var asdf := [ 97, 115, 100, 102 ]; - - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - var mpl :- expect MaterialProviders.MaterialProviders(); - - // get keyrings - var rsaKeyring := GetRsaKeyring(); - - var encryptionContext := Fixtures.GetResrvedECMap(); - var requiredECKeys := [Fixtures.RESERVED_ENCRYPTION_CONTEXT]; - - var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( - mplTypes.CreateDefaultCryptographicMaterialsManagerInput( - keyring := rsaKeyring - ) - ); - - // Create Required EC CMM with the required EC Keys we want - // Although we are requesting that we remove a RESERVED key word from the encryption context - // The CMM instantiation will still succeed because the CMM is meant to work with different higher level - // encryption libraries who may have different reserved keys. Encryption will ultimately fail. - var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( - mplTypes.CreateRequiredEncryptionContextCMMInput( - underlyingCMM := Some(defaultCMM), - // At the moment reqCMM can only be created with a CMM, you cannot - // create one by only passing in a keyring. - keyring := None, - requiredEncryptionContextKeys := requiredECKeys - ) - ); - - var encryptOutput := esdk.Encrypt(Types.EncryptInput( - plaintext := asdf, - encryptionContext := Some(encryptionContext), - materialsManager := Some(reqCMM), - keyring := None, - algorithmSuiteId := None, - frameLength := None - )); - - expect encryptOutput.Failure?; - - } - - method GetHierarchicalKeyring() - returns (output: mplTypes.IKeyring) - ensures output.ValidState() && fresh(output) && fresh(output.History) && fresh(output.Modifies) - { - var branchKeyId := BRANCH_KEY_ID; - var ttl : mplTypes.PositiveLong := (1 * 60000) * 10; - var mpl :- expect MaterialProviders.MaterialProviders(); - - var kmsClient :- expect KMS.KMSClient(); - var ddbClient :- expect DDB.DynamoDBClient(); - var kmsConfig := KeyStoreTypes.KMSConfiguration.kmsKeyArn(hierarchyKeyArn); - - var keyStoreConfig := KeyStoreTypes.KeyStoreConfig( - id := None, - kmsConfiguration := kmsConfig, - logicalKeyStoreName := logicalKeyStoreName, - grantTokens := None, - ddbTableName := branchKeyStoreName, - ddbClient := Some(ddbClient), - kmsClient := Some(kmsClient) - ); - - var keyStore :- expect KeyStore.KeyStore(keyStoreConfig); - - output :- expect mpl.CreateAwsKmsHierarchicalKeyring( - mplTypes.CreateAwsKmsHierarchicalKeyringInput( - branchKeyId := Some(branchKeyId), - branchKeyIdSupplier := None, - keyStore := keyStore, - ttlSeconds := ttl, - cache := None - )); - } - - method GetRsaKeyring() - returns (output: mplTypes.IKeyring) - ensures output.ValidState() && fresh(output) && fresh(output.History) && fresh(output.Modifies) - { - var mpl :- expect MaterialProviders.MaterialProviders(); - - var namespace, name := Fixtures.NamespaceAndName(0); - var keys := Fixtures.GenerateKeyPair(2048 as primitivesTypes.RSAModulusLengthBits); - output :- expect mpl.CreateRawRsaKeyring(mplTypes.CreateRawRsaKeyringInput( - keyNamespace := namespace, - keyName := name, - paddingScheme := mplTypes.PaddingScheme.OAEP_SHA1_MGF1, - publicKey := Option.Some(keys.publicKey.pem), - privateKey := Option.Some(keys.privateKey.pem) - )); - - } - - method GetAesKeyring() - returns (output: mplTypes.IKeyring) - ensures output.ValidState() && fresh(output) && fresh(output.History) && fresh(output.Modifies) - { - var mpl :- expect MaterialProviders.MaterialProviders(); - - var namespace, name := Fixtures.NamespaceAndName(0); - output :- expect mpl.CreateRawAesKeyring(mplTypes.CreateRawAesKeyringInput( - keyNamespace := namespace, - keyName := name, - wrappingKey := seq(32, i => 0), - wrappingAlg := mplTypes.ALG_AES256_GCM_IV12_TAG16 - )); - } - - method GetKmsKeyring() - returns (output: mplTypes.IKeyring) - ensures output.ValidState() && fresh(output) && fresh(output.History) && fresh(output.Modifies) - { - var kmsKey := Fixtures.keyArn; - var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); - var esdk :- expect ESDK.ESDK(config := defaultConfig); - var mpl :- expect MaterialProviders.MaterialProviders(); - var clientSupplier :- expect mpl.CreateDefaultClientSupplier(mplTypes.CreateDefaultClientSupplierInput); - var kmsClient :- expect clientSupplier.GetClient(mplTypes.GetClientInput(region := "us-west-2")); - - output :- expect mpl.CreateAwsKmsKeyring( - mplTypes.CreateAwsKmsKeyringInput( - kmsKeyId := kmsKey, - kmsClient := kmsClient, - grantTokens := None - ) - ); - - } - + import Types = AwsCryptographyEncryptionSdkTypes + import mplTypes = AwsCryptographyMaterialProvidersTypes + import primitivesTypes = AwsCryptographyPrimitivesTypes + import KeyStoreTypes = AwsCryptographyKeyStoreTypes + import MaterialProviders + import KeyStore + import ComAmazonawsKmsTypes + import KMS = Com.Amazonaws.Kms + import DDB = Com.Amazonaws.Dynamodb + import DDBTypes = ComAmazonawsDynamodbTypes + import ESDK + import opened Wrappers + import UTF8 + + import Fixtures + + // THIS IS A TESTING RESOURCE DO NOT USE IN A PRODUCTION ENVIRONMENT + const keyArn := Fixtures.keyArn + const hierarchyKeyArn := Fixtures.hierarchyKeyArn; + const branchKeyStoreName: DDBTypes.TableName := Fixtures.branchKeyStoreName + const logicalKeyStoreName := branchKeyStoreName + // These tests require a keystore populated with these keys + const BRANCH_KEY_ID := Fixtures.branchKeyId + + method {:test} TestReprEncryptionContextWithSameECHappyCase() + { + // The string "asdf" as bytes + var asdf := [ 97, 115, 100, 102 ]; + + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + var mpl :- expect MaterialProviders.MaterialProviders(); + + // get keyrings + var rsaKeyring := GetRsaKeyring(); + var kmsKeyring := GetKmsKeyring(); + var aesKeyring := GetAesKeyring(); + var hKeyring := GetHierarchicalKeyring(); + + var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( + generator := Some(aesKeyring), + childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] + )); + + // HAPPY CASE 1 + // Test supply same encryption context on encrypt and decrypt NO filtering + var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); + + var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := None, + keyring := Some(multiKeyring), + algorithmSuiteId := None, + frameLength := None + )); + + expect encryptOutput.Success?; + var esdkCiphertext := encryptOutput.value.ciphertext; + + // Test RSA + var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(rsaKeyring), + encryptionContext := Some(encryptionContext) + )); + + expect decryptOutput.Success?; + var cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + + // Test KMS + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(kmsKeyring), + encryptionContext := Some(encryptionContext) + )); + + expect decryptOutput.Success?; + cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + + // Test AES + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(aesKeyring), + encryptionContext := Some(encryptionContext) + )); + + expect decryptOutput.Success?; + cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + + // Test Hierarchy Keyring + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(hKeyring), + encryptionContext := Some(encryptionContext) + )); + + expect decryptOutput.Success?; + cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + } + + method {:test} TestRemoveOnEncryptAndSupplyOnDecryptHappyCase() + { + // The string "asdf" as bytes + var asdf := [ 97, 115, 100, 102 ]; + + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + var mpl :- expect MaterialProviders.MaterialProviders(); + + // get keyrings + var rsaKeyring := GetRsaKeyring(); + var kmsKeyring := GetKmsKeyring(); + var aesKeyring := GetAesKeyring(); + var hKeyring := GetHierarchicalKeyring(); + + var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( + generator := Some(aesKeyring), + childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] + )); + + // Happy Test Case 2 + // On Encrypt we will only write one encryption context key value to the header + // we will then supply only what we didn't write wth no required ec cmm, + // This test case is checking that the default cmm is doing the correct filtering by using + var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); + var reproducedEncryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.A); + // These keys mean that we will not write these on the message but are required for message authentication on decrypt. + var requiredEncryptionContextKeys := Fixtures.SmallEncryptionContextKeys(Fixtures.SmallEncryptionContextVariation.A); + + // TEST RSA + var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := multiKeyring + ) + ); + + // Create Required EC CMM with the required EC Keys we want + var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + // At the moment reqCMM can only be created with a CMM, you cannot + // create one by only passing in a keyring. + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) + ); + + var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(reqCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None + )); + + expect encryptOutput.Success?; + var esdkCiphertext := encryptOutput.value.ciphertext; + + // Switch to only RSA keyring + var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(rsaKeyring), + encryptionContext := Some(reproducedEncryptionContext) + )); + + expect decryptOutput.Success?; + var cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + + // Switch to only KMS keyring + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(kmsKeyring), + encryptionContext := Some(reproducedEncryptionContext) + )); + + expect decryptOutput.Success?; + cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + + // Switch to only AES keyring + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(aesKeyring), + encryptionContext := Some(reproducedEncryptionContext) + )); + + expect decryptOutput.Success?; + cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + + // Switch to only Hierarchical keyring + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(hKeyring), + encryptionContext := Some(reproducedEncryptionContext) + )); + + expect decryptOutput.Success?; + cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + + } + + method {:test} TestRemoveOnEncryptRemoveAndSupplyOnDecryptHappyCase() + { + // The string "asdf" as bytes + var asdf := [ 97, 115, 100, 102 ]; + + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + var mpl :- expect MaterialProviders.MaterialProviders(); + + // get keyrings + var rsaKeyring := GetRsaKeyring(); + var kmsKeyring := GetKmsKeyring(); + var aesKeyring := GetAesKeyring(); + var hKeyring := GetHierarchicalKeyring(); + + var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( + generator := Some(aesKeyring), + childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] + )); + + // HAPPY CASE 3 + // On Encrypt we will only write one encryption context key value to the header + // we will then supply only what we didn't write but included in the signature while we + // are configured with the required encryption context cmm + var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); + var reproducedEncryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.A); + // These keys mean that we will not write these on the message but are required for message authentication on decrypt. + var requiredEncryptionContextKeys := Fixtures.SmallEncryptionContextKeys(Fixtures.SmallEncryptionContextVariation.A); + + // TEST RSA + var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := multiKeyring + ) + ); + + // Create Required EC CMM with the required EC Keys we want + var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + // At the moment reqCMM can only be created with a CMM, you cannot + // create one by only passing in a keyring. + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) + ); + + var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(reqCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None + )); + + expect encryptOutput.Success?; + var esdkCiphertext := encryptOutput.value.ciphertext; + + // Switch to only RSA keyring + defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := rsaKeyring + ) + ); + + // Create Required EC CMM with the required EC Keys we want + reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + // At the moment reqCMM can only be created with a CMM, you cannot + // create one by only passing in a keyring. + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) + ); + // Since we are passing in the correct reproduced encryption context this + // decrypt SHOULD succeed + var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := Some(reqCMM), + keyring := None, + encryptionContext := Some(reproducedEncryptionContext) + )); + + expect decryptOutput.Success?; + var cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + + // TEST KMS + // Switch to only KMS keyring + defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := kmsKeyring + ) + ); + + // Create Required EC CMM with the required EC Keys we want + reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + // At the moment reqCMM can only be created with a CMM, you cannot + // create one by only passing in a keyring. + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) + ); + // Since we are passing in the correct reproduced encryption context this + // decrypt SHOULD succeed + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := Some(reqCMM), + keyring := None, + encryptionContext := Some(reproducedEncryptionContext) + )); + + expect decryptOutput.Success?; + cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + + // TEST AES + // switch to only aes + defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := aesKeyring + ) + ); + + // Create Required EC CMM with the required EC Keys we want + reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + // At the moment reqCMM can only be created with a CMM, you cannot + // create one by only passing in a keyring. + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) + ); + // Since we are passing in the correct reproduced encryption context this + // decrypt SHOULD succeed + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := Some(reqCMM), + keyring := None, + encryptionContext := Some(reproducedEncryptionContext) + )); + + expect decryptOutput.Success?; + cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + + // TEST HIERARCHY + defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := hKeyring + ) + ); + + // Create Required EC CMM with the required EC Keys we want + reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + // At the moment reqCMM can only be created with a CMM, you cannot + // create one by only passing in a keyring. + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) + ); + // Since we are passing in the correct reproduced encryption context this + // decrypt SHOULD succeed + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := Some(reqCMM), + keyring := None, + encryptionContext := Some(reproducedEncryptionContext) + )); + + expect decryptOutput.Success?; + cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + } + + method {:test} TestRemoveOnDecryptIsBackwardsCompatibleHappyCase() + { + // The string "asdf" as bytes + var asdf := [ 97, 115, 100, 102 ]; + + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + var mpl :- expect MaterialProviders.MaterialProviders(); + + // get keyrings + var rsaKeyring := GetRsaKeyring(); + var kmsKeyring := GetKmsKeyring(); + var aesKeyring := GetAesKeyring(); + var hKeyring := GetHierarchicalKeyring(); + + var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( + generator := Some(aesKeyring), + childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] + )); + + // HAPPY CASE 4 + // On Encrypt we write all encryption context + // as if the message was encrypted before the feature existed. + // We will then have a required encryption context cmm + // that will require us to supply the encryption context on decrypt. + var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); + var reproducedEncryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.A); + // These keys mean that we will not write these on the message but are required for message authentication on decrypt. + var requiredEncryptionContextKeys := Fixtures.SmallEncryptionContextKeys(Fixtures.SmallEncryptionContextVariation.A); + + var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := multiKeyring + ) + ); + + // All encryption context is stored in the message + var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(defaultCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None + )); + + expect encryptOutput.Success?; + var esdkCiphertext := encryptOutput.value.ciphertext; + + // Switch to only RSA keyring + defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := rsaKeyring + ) + ); + + // Create Required EC CMM with the required EC Keys we want + var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + // At the moment reqCMM can only be created with a CMM, you cannot + // create one by only passing in a keyring. + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) + ); + // Since we are passing in the correct reproduced encryption context this + // decrypt SHOULD succeed + var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := Some(reqCMM), + keyring := None, + encryptionContext := Some(reproducedEncryptionContext) + )); + + expect decryptOutput.Success?; + var cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + + // TEST KMS + // Switch to only KMS keyring + defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := kmsKeyring + ) + ); + + // Create Required EC CMM with the required EC Keys we want + reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + // At the moment reqCMM can only be created with a CMM, you cannot + // create one by only passing in a keyring. + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) + ); + // Since we are passing in the correct reproduced encryption context this + // decrypt SHOULD succeed + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := Some(reqCMM), + keyring := None, + encryptionContext := Some(reproducedEncryptionContext) + )); + + expect decryptOutput.Success?; + cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + + // TEST AES + // switch to only aes + defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := aesKeyring + ) + ); + + // Create Required EC CMM with the required EC Keys we want + reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + // At the moment reqCMM can only be created with a CMM, you cannot + // create one by only passing in a keyring. + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) + ); + // Since we are passing in the correct reproduced encryption context this + // decrypt SHOULD succeed + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := Some(reqCMM), + keyring := None, + encryptionContext := Some(reproducedEncryptionContext) + )); + + expect decryptOutput.Success?; + cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + + // TEST HIERARCHY + defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := hKeyring + ) + ); + + // Create Required EC CMM with the required EC Keys we want + reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + // At the moment reqCMM can only be created with a CMM, you cannot + // create one by only passing in a keyring. + keyring := None, + requiredEncryptionContextKeys := requiredEncryptionContextKeys + ) + ); + // Since we are passing in the correct reproduced encryption context this + // decrypt SHOULD succeed + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := Some(reqCMM), + keyring := None, + encryptionContext := Some(reproducedEncryptionContext) + )); + + expect decryptOutput.Success?; + cycledPlaintext := decryptOutput.value.plaintext; + expect cycledPlaintext == asdf; + } + + method {:test} TestDifferentECOnDecryptFailure() + { + // encrypt {a, b} => decrypt {b:c} => fail + // encrypt {a, b} => decrypt {d} => fail + + // The string "asdf" as bytes + var asdf := [ 97, 115, 100, 102 ]; + + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + var mpl :- expect MaterialProviders.MaterialProviders(); + + // get keyrings + var rsaKeyring := GetRsaKeyring(); + var kmsKeyring := GetKmsKeyring(); + var aesKeyring := GetAesKeyring(); + var hKeyring := GetHierarchicalKeyring(); + + var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( + generator := Some(aesKeyring), + childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] + )); + + // FAILURE CASE 1 + // Encrypt with and store all encryption context in header + // On Decrypt supply additional encryption context not stored in the header; this MUST fail + // On Decrypt supply mismatched encryption context key values; this MUST fail + var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); + // Additional EC + var reproducedAdditionalEncryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.C); + // Mismatched EncryptionContext + var reproducedMismatchedEncryptionContext := Fixtures.SmallMismatchedEncryptionContex(Fixtures.SmallEncryptionContextVariation.AB); + + var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := None, + keyring := Some(multiKeyring), + algorithmSuiteId := None, + frameLength := None + )); + + expect encryptOutput.Success?; + var esdkCiphertext := encryptOutput.value.ciphertext; + + // Test RSA Failures + var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(rsaKeyring), + encryptionContext := Some(reproducedAdditionalEncryptionContext) + )); + + expect decryptOutput.Failure?; + + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(rsaKeyring), + encryptionContext := Some(reproducedMismatchedEncryptionContext) + )); + + expect decryptOutput.Failure?; + + // Test KMS Failures + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(kmsKeyring), + encryptionContext := Some(reproducedAdditionalEncryptionContext) + )); + + expect decryptOutput.Failure?; + + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(kmsKeyring), + encryptionContext := Some(reproducedMismatchedEncryptionContext) + )); + + expect decryptOutput.Failure?; + + // Test AES Failures + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(aesKeyring), + encryptionContext := Some(reproducedAdditionalEncryptionContext) + )); + + expect decryptOutput.Failure?; + + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(aesKeyring), + encryptionContext := Some(reproducedMismatchedEncryptionContext) + )); + + expect decryptOutput.Failure?; + + // Test Hierarchical Failures + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(hKeyring), + encryptionContext := Some(reproducedAdditionalEncryptionContext) + )); + + expect decryptOutput.Failure?; + + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(hKeyring), + encryptionContext := Some(reproducedMismatchedEncryptionContext) + )); + + expect decryptOutput.Failure?; + } + + method {:test} TestRemoveECAndNotSupplyOnDecryptFailure() + { + + // encrypt remove(a) RSA {a, b} => decrypt => fail + // encrypt remove(a) KMS {a, b} => decrypt => fail + // encrypt remove(a) AES {a, b} => decrypt => fail + // encrypt remove(a) Hie {a, b} => decrypt => fail + + // The string "asdf" as bytes + var asdf := [ 97, 115, 100, 102 ]; + + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + var mpl :- expect MaterialProviders.MaterialProviders(); + + // get keyrings + var rsaKeyring := GetRsaKeyring(); + var kmsKeyring := GetKmsKeyring(); + var aesKeyring := GetAesKeyring(); + var hKeyring := GetHierarchicalKeyring(); + + var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( + generator := Some(aesKeyring), + childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] + )); + + // FAILURE CASE 2 + // Encrypt will not store all Encryption Context, we will drop one entry but it will still get included in the + // header signture. + // Decrypt will not supply any reproduced Encryption Context; this MUST fail. + var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); + var requiredECKeys := Fixtures.SmallEncryptionContextKeys(Fixtures.SmallEncryptionContextVariation.A); + + var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := multiKeyring + ) + ); + + // Create Required EC CMM with the required EC Keys we want + var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + // At the moment reqCMM can only be created with a CMM, you cannot + // create one by only passing in a keyring. + keyring := None, + requiredEncryptionContextKeys := requiredECKeys + ) + ); + + var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(reqCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None + )); + + expect encryptOutput.Success?; + var esdkCiphertext := encryptOutput.value.ciphertext; + + // Test RSA Failure + var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(rsaKeyring), + encryptionContext := None + )); + + expect decryptOutput.Failure?; + + // Test KMS Failures + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(kmsKeyring), + encryptionContext := None + )); + + expect decryptOutput.Failure?; + + // Test AES Failures + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(aesKeyring), + encryptionContext := None + )); + + expect decryptOutput.Failure?; + + // Test Hierarchical Failures + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(hKeyring), + encryptionContext := None + )); + + expect decryptOutput.Failure?; + } + + method {:test} TestRemoveECAndSupplyMismatchedReprECFailure() + { + + // encrypt remove(a) RSA {a, b} => decrypt {b:c} => fail + // encrypt remove(a) KMS {a, b} => decrypt {b:c} => fail + // encrypt remove(a) AES {a, b} => decrypt {b:c} => fail + // encrypt remove(a) Hie {a, b} => decrypt {b:c} => fail + + // The string "asdf" as bytes + var asdf := [ 97, 115, 100, 102 ]; + + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + var mpl :- expect MaterialProviders.MaterialProviders(); + + // get keyrings + var rsaKeyring := GetRsaKeyring(); + var kmsKeyring := GetKmsKeyring(); + var aesKeyring := GetAesKeyring(); + var hKeyring := GetHierarchicalKeyring(); + + var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( + generator := Some(aesKeyring), + childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] + )); + + // FAILURE CASE 3 + // Encrypt will not store all Encryption Context, we will drop one entry but it will still get included in the + // header signture. + // Decrypt will supply the correct key but incorrect value; this MUST fail. + var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); + var requiredECKeys := Fixtures.SmallEncryptionContextKeys(Fixtures.SmallEncryptionContextVariation.A); + // this reproduced encryption context contains the key we didn't store, but it has the wrong value + var mismatchedReproducedEncryptionContext := Fixtures.SmallMismatchedEncryptionContex(Fixtures.SmallEncryptionContextVariation.A); + + var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := multiKeyring + ) + ); + + // Create Required EC CMM with the required EC Keys we want + var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + // At the moment reqCMM can only be created with a CMM, you cannot + // create one by only passing in a keyring. + keyring := None, + requiredEncryptionContextKeys := requiredECKeys + ) + ); + + var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(reqCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None + )); + + expect encryptOutput.Success?; + var esdkCiphertext := encryptOutput.value.ciphertext; + + // Test RSA Failure + var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(rsaKeyring), + encryptionContext := Some(mismatchedReproducedEncryptionContext) + )); + + expect decryptOutput.Failure?; + + // Test KMS Failures + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(kmsKeyring), + encryptionContext := Some(mismatchedReproducedEncryptionContext) + )); + + expect decryptOutput.Failure?; + + // Test AES Failures + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(aesKeyring), + encryptionContext := Some(mismatchedReproducedEncryptionContext) + )); + + expect decryptOutput.Failure?; + + // Test Hierarchical Failures + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(hKeyring), + encryptionContext := Some(mismatchedReproducedEncryptionContext) + )); + + expect decryptOutput.Failure?; + } + + method {:test} TestRemoveECAndSupplyWithMissingRequiredValueDecryptFailure() + { + // encrypt remove(a) RSA {a, b} => decrypt remove(a) => fail + // encrypt remove(a) KMS {a, b} => decrypt remove(a) => fail + // encrypt remove(a) AES {a, b} => decrypt remove(a) => fail + // encrypt remove(a) Hie {a, b} => decrypt remove(a) => fail + + // The string "asdf" as bytes + var asdf := [ 97, 115, 100, 102 ]; + + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + var mpl :- expect MaterialProviders.MaterialProviders(); + + // get keyrings + var rsaKeyring := GetRsaKeyring(); + var kmsKeyring := GetKmsKeyring(); + var aesKeyring := GetAesKeyring(); + var hKeyring := GetHierarchicalKeyring(); + + var multiKeyring :- expect mpl.CreateMultiKeyring(mplTypes.CreateMultiKeyringInput( + generator := Some(aesKeyring), + childKeyrings := [rsaKeyring, kmsKeyring, hKeyring] + )); + + // FAILURE CASE 4 + // Encrypt will not store all Encryption Context, we will drop one entry but it will still get included in the + // header signture. + // Decrypt will supply the correct key but incorrect value; this MUST fail. + var encryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.AB); + var requiredECKeys := Fixtures.SmallEncryptionContextKeys(Fixtures.SmallEncryptionContextVariation.A); + // this reproduced encryption context does not contain the key that was dropped + var droppedRequiredKeyEncryptionContext := Fixtures.SmallEncryptionContext(Fixtures.SmallEncryptionContextVariation.B); + + var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := multiKeyring + ) + ); + + // Create Required EC CMM with the required EC Keys we want + var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + // At the moment reqCMM can only be created with a CMM, you cannot + // create one by only passing in a keyring. + keyring := None, + requiredEncryptionContextKeys := requiredECKeys + ) + ); + + var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(reqCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None + )); + + expect encryptOutput.Success?; + var esdkCiphertext := encryptOutput.value.ciphertext; + + // Test RSA Failure + var decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(rsaKeyring), + encryptionContext := Some(droppedRequiredKeyEncryptionContext) + )); + + expect decryptOutput.Failure?; + + // Test KMS Failure + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(kmsKeyring), + encryptionContext := Some(droppedRequiredKeyEncryptionContext) + )); + + expect decryptOutput.Failure?; + + // Test AES Failure + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(aesKeyring), + encryptionContext := Some(droppedRequiredKeyEncryptionContext) + )); + + expect decryptOutput.Failure?; + + // Test Hierarchical Failure + decryptOutput := esdk.Decrypt(Types.DecryptInput( + ciphertext := esdkCiphertext, + materialsManager := None, + keyring := Some(hKeyring), + encryptionContext := Some(droppedRequiredKeyEncryptionContext) + )); + + expect decryptOutput.Failure?; + + } + + method {:test} TestReservedEncryptionContextKeyFailure() + { + // The string "asdf" as bytes + var asdf := [ 97, 115, 100, 102 ]; + + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + var mpl :- expect MaterialProviders.MaterialProviders(); + + // get keyrings + var rsaKeyring := GetRsaKeyring(); + + var encryptionContext := Fixtures.GetResrvedECMap(); + var requiredECKeys := [Fixtures.RESERVED_ENCRYPTION_CONTEXT]; + + var defaultCMM :- expect mpl.CreateDefaultCryptographicMaterialsManager( + mplTypes.CreateDefaultCryptographicMaterialsManagerInput( + keyring := rsaKeyring + ) + ); + + // Create Required EC CMM with the required EC Keys we want + // Although we are requesting that we remove a RESERVED key word from the encryption context + // The CMM instantiation will still succeed because the CMM is meant to work with different higher level + // encryption libraries who may have different reserved keys. Encryption will ultimately fail. + var reqCMM :- expect mpl.CreateRequiredEncryptionContextCMM( + mplTypes.CreateRequiredEncryptionContextCMMInput( + underlyingCMM := Some(defaultCMM), + // At the moment reqCMM can only be created with a CMM, you cannot + // create one by only passing in a keyring. + keyring := None, + requiredEncryptionContextKeys := requiredECKeys + ) + ); + + var encryptOutput := esdk.Encrypt(Types.EncryptInput( + plaintext := asdf, + encryptionContext := Some(encryptionContext), + materialsManager := Some(reqCMM), + keyring := None, + algorithmSuiteId := None, + frameLength := None + )); + + expect encryptOutput.Failure?; + + } + + method GetHierarchicalKeyring() + returns (output: mplTypes.IKeyring) + ensures output.ValidState() && fresh(output) && fresh(output.History) && fresh(output.Modifies) + { + var branchKeyId := BRANCH_KEY_ID; + var ttl : mplTypes.PositiveLong := (1 * 60000) * 10; + var mpl :- expect MaterialProviders.MaterialProviders(); + + var kmsClient :- expect KMS.KMSClient(); + var ddbClient :- expect DDB.DynamoDBClient(); + var kmsConfig := KeyStoreTypes.KMSConfiguration.kmsKeyArn(hierarchyKeyArn); + + var keyStoreConfig := KeyStoreTypes.KeyStoreConfig( + id := None, + kmsConfiguration := kmsConfig, + logicalKeyStoreName := logicalKeyStoreName, + grantTokens := None, + ddbTableName := branchKeyStoreName, + ddbClient := Some(ddbClient), + kmsClient := Some(kmsClient) + ); + + var keyStore :- expect KeyStore.KeyStore(keyStoreConfig); + + output :- expect mpl.CreateAwsKmsHierarchicalKeyring( + mplTypes.CreateAwsKmsHierarchicalKeyringInput( + branchKeyId := Some(branchKeyId), + branchKeyIdSupplier := None, + keyStore := keyStore, + ttlSeconds := ttl, + cache := None + )); + } + + method GetRsaKeyring() + returns (output: mplTypes.IKeyring) + ensures output.ValidState() && fresh(output) && fresh(output.History) && fresh(output.Modifies) + { + var mpl :- expect MaterialProviders.MaterialProviders(); + + var namespace, name := Fixtures.NamespaceAndName(0); + var keys := Fixtures.GenerateKeyPair(2048 as primitivesTypes.RSAModulusLengthBits); + output :- expect mpl.CreateRawRsaKeyring(mplTypes.CreateRawRsaKeyringInput( + keyNamespace := namespace, + keyName := name, + paddingScheme := mplTypes.PaddingScheme.OAEP_SHA1_MGF1, + publicKey := Option.Some(keys.publicKey.pem), + privateKey := Option.Some(keys.privateKey.pem) + )); + + } + + method GetAesKeyring() + returns (output: mplTypes.IKeyring) + ensures output.ValidState() && fresh(output) && fresh(output.History) && fresh(output.Modifies) + { + var mpl :- expect MaterialProviders.MaterialProviders(); + + var namespace, name := Fixtures.NamespaceAndName(0); + output :- expect mpl.CreateRawAesKeyring(mplTypes.CreateRawAesKeyringInput( + keyNamespace := namespace, + keyName := name, + wrappingKey := seq(32, i => 0), + wrappingAlg := mplTypes.ALG_AES256_GCM_IV12_TAG16 + )); + } + + method GetKmsKeyring() + returns (output: mplTypes.IKeyring) + ensures output.ValidState() && fresh(output) && fresh(output.History) && fresh(output.Modifies) + { + var kmsKey := Fixtures.keyArn; + var defaultConfig := ESDK.DefaultAwsEncryptionSdkConfig(); + var esdk :- expect ESDK.ESDK(config := defaultConfig); + var mpl :- expect MaterialProviders.MaterialProviders(); + var clientSupplier :- expect mpl.CreateDefaultClientSupplier(mplTypes.CreateDefaultClientSupplierInput); + var kmsClient :- expect clientSupplier.GetClient(mplTypes.GetClientInput(region := "us-west-2")); + + output :- expect mpl.CreateAwsKmsKeyring( + mplTypes.CreateAwsKmsKeyringInput( + kmsKeyId := kmsKey, + kmsClient := kmsClient, + grantTokens := None + ) + ); + + } + } \ No newline at end of file diff --git a/AwsEncryptionSDK/runtimes/go/examples/README.md b/AwsEncryptionSDK/runtimes/go/examples/README.md index df7de5e1b..cf5956f4b 100644 --- a/AwsEncryptionSDK/runtimes/go/examples/README.md +++ b/AwsEncryptionSDK/runtimes/go/examples/README.md @@ -14,10 +14,10 @@ and streaming APIs. You can find examples that demonstrate these APIs in the [`examples/`](./) directory. -* [How to encrypt and decrypt](./keyring/awskmskeyring/awskmskeyring.go) -* [How to change the algorithm suite](./misc/setencryptionalgorithmsuite.go) -* [How to set the commitment policy](./misc/commitmentpolicy.go) -* [How to limit the number of encrypted data keys (EDKs)](./misc/limitencrypteddatakeysexample.go) +- [How to encrypt and decrypt](./keyring/awskmskeyring/awskmskeyring.go) +- [How to change the algorithm suite](./misc/setencryptionalgorithmsuite.go) +- [How to set the commitment policy](./misc/commitmentpolicy.go) +- [How to limit the number of encrypted data keys (EDKs)](./misc/limitencrypteddatakeysexample.go) ## Configuration @@ -29,20 +29,20 @@ These examples will show you how to use the configuration tools that we include and how to create some of your own. We start with AWS KMS examples, then show how to use other wrapping keys. -* Using AWS Key Management Service (AWS KMS) - * [How to use one AWS KMS key](./keyring/awskmskeyring/awskmskeyring.go) - * [How to use multiple AWS KMS keys in different regions](./keyring/awskmsmrkmultikeyring/awskmsmrkmultikeyring.go) - * [How to decrypt when you don't know the AWS KMS key](./keyring/awskmsdiscoverykeyring/awskmsdiscoverykeyring.go) - * [How to limit decryption to a single region](./keyring/awskmsmrkdiscoverykeyring/awskmsmrkdiscoverykeyring.go) - * [How to decrypt with a preferred region but failover to others](./keyring/awskmsmrkdiscoverykeyring/awskmsmrkdiscoverykeyring.go) - * [How to reproduce the behavior of an AWS KMS master key provider](./keyring/awskmsmultikeyring/awskmsmultikeyring.go) -* Using raw wrapping keys - * [How to use a raw AES wrapping key](./keyring/rawaeskeyring/rawaeskeyring.go) - * [How to use a raw RSA wrapping key](./keyring/rawrsakeyring/rawrasakeyring.go) -* Combining wrapping keys - * [How to combine AWS KMS with an offline escrow key](./keyring/multikeyring/multikeyring.go) -* How to restrict algorithm suites - * [with a custom cryptographic materials manager](./cryptographicmaterialsmanager/restrictalgorithmsuite/signingsuiteonlycmm.go) +- Using AWS Key Management Service (AWS KMS) + - [How to use one AWS KMS key](./keyring/awskmskeyring/awskmskeyring.go) + - [How to use multiple AWS KMS keys in different regions](./keyring/awskmsmrkmultikeyring/awskmsmrkmultikeyring.go) + - [How to decrypt when you don't know the AWS KMS key](./keyring/awskmsdiscoverykeyring/awskmsdiscoverykeyring.go) + - [How to limit decryption to a single region](./keyring/awskmsmrkdiscoverykeyring/awskmsmrkdiscoverykeyring.go) + - [How to decrypt with a preferred region but failover to others](./keyring/awskmsmrkdiscoverykeyring/awskmsmrkdiscoverykeyring.go) + - [How to reproduce the behavior of an AWS KMS master key provider](./keyring/awskmsmultikeyring/awskmsmultikeyring.go) +- Using raw wrapping keys + - [How to use a raw AES wrapping key](./keyring/rawaeskeyring/rawaeskeyring.go) + - [How to use a raw RSA wrapping key](./keyring/rawrsakeyring/rawrasakeyring.go) +- Combining wrapping keys + - [How to combine AWS KMS with an offline escrow key](./keyring/multikeyring/multikeyring.go) +- How to restrict algorithm suites + - [with a custom cryptographic materials manager](./cryptographicmaterialsmanager/restrictalgorithmsuite/signingsuiteonlycmm.go) ### Keyrings @@ -83,8 +83,8 @@ To make sure that your example runs in our CI, please make sure that it meets the following requirements: 1. The example MUST be a distinct subdirectory or file in the [`examples/`](./) directory. -1. The example MAY be nested arbitrarily deeply. +1. The example MAY be nested arbitrarily deeply. 1. Each example file MUST contain exactly one example. 1. Each example filename MUST be descriptive. 1. Each example file MUST contain validation checks to check for expected returned values and MUST panic is the returned value is no expected. -1. Each example MUST also be called inside the `main` function of [main.go](./main.go). \ No newline at end of file +1. Each example MUST also be called inside the `main` function of [main.go](./main.go). diff --git a/AwsEncryptionSDK/runtimes/java/src/main/java/software/amazon/cryptography/encryptionsdk/internaldafny/__default.java b/AwsEncryptionSDK/runtimes/java/src/main/java/software/amazon/cryptography/encryptionsdk/internaldafny/__default.java index aacccd0ec..03ebfdbfd 100644 --- a/AwsEncryptionSDK/runtimes/java/src/main/java/software/amazon/cryptography/encryptionsdk/internaldafny/__default.java +++ b/AwsEncryptionSDK/runtimes/java/src/main/java/software/amazon/cryptography/encryptionsdk/internaldafny/__default.java @@ -1,4 +1,4 @@ package software.amazon.cryptography.encryptionsdk.internaldafny; -public class __default extends software.amazon.cryptography.encryptionsdk.internaldafny._ExternBase___default { -} +public class __default + extends software.amazon.cryptography.encryptionsdk.internaldafny._ExternBase___default {} diff --git a/AwsEncryptionSDK/runtimes/java/src/main/java/software/amazon/cryptography/encryptionsdk/internaldafny/types/__default.java b/AwsEncryptionSDK/runtimes/java/src/main/java/software/amazon/cryptography/encryptionsdk/internaldafny/types/__default.java index c9efdd237..8721c74f4 100644 --- a/AwsEncryptionSDK/runtimes/java/src/main/java/software/amazon/cryptography/encryptionsdk/internaldafny/types/__default.java +++ b/AwsEncryptionSDK/runtimes/java/src/main/java/software/amazon/cryptography/encryptionsdk/internaldafny/types/__default.java @@ -1,4 +1,4 @@ package software.amazon.cryptography.encryptionsdk.internaldafny.types; -public class __default extends software.amazon.cryptography.encryptionsdk.internaldafny.types._ExternBase___default { -} +public class __default + extends software.amazon.cryptography.encryptionsdk.internaldafny.types._ExternBase___default {} diff --git a/AwsEncryptionSDK/runtimes/net/CHANGELOG.md b/AwsEncryptionSDK/runtimes/net/CHANGELOG.md index bf9b9eb6a..3a51ab1a7 100644 --- a/AwsEncryptionSDK/runtimes/net/CHANGELOG.md +++ b/AwsEncryptionSDK/runtimes/net/CHANGELOG.md @@ -3,6 +3,7 @@ ## 4.1.0 ### Notes + - [(#646)](https://github.com/aws/aws-encryption-sdk-dafny/commit/10daadfa19db0e43fc0cc6d7b989f1fb477a22b0) Enforces input constraints. Prior to this fix, the AWS Encryption SDK in .NET (ESDK-NET) failed to enforce user input constraints. Input shapes without required members set would always result in a `NullReferenceException`. @@ -11,27 +12,27 @@ is submitted. ### Fixes -* fix: throw an exception when MemoryStream instance has an empty backing array [(#633)](https://github.com/aws/aws-encryption-sdk-dafny/commit/550c714743e84f93d09900b3338f59d0a54bb3ce) +- fix: throw an exception when MemoryStream instance has an empty backing array [(#633)](https://github.com/aws/aws-encryption-sdk-dafny/commit/550c714743e84f93d09900b3338f59d0a54bb3ce) ### Features -* feat: enforce input constraints [(#646)](https://github.com/aws/aws-encryption-sdk-dafny/commit/10daadfa19db0e43fc0cc6d7b989f1fb477a22b0) +- feat: enforce input constraints [(#646)](https://github.com/aws/aws-encryption-sdk-dafny/commit/10daadfa19db0e43fc0cc6d7b989f1fb477a22b0) ### Maintenance -* fix(CI): Daily CI uses correct workflow [(#641)](https://github.com/aws/aws-encryption-sdk-dafny/commit/771835e22f6ef3c3b34d0891fb61cb1a49bcf855) -* chore(ci): fix role to assume [(#622)](https://github.com/aws/aws-encryption-sdk-dafny/commit/c1f04fc41093593748f16da80d893c2ec5325545) -* chore(CI/CD): add semantic release automation [(#647)](https://github.com/aws/aws-encryption-sdk-dafny/commit/e7b5392ccc18f502a5517580a27bce5980e1913d) -* chore: Adopt SmithyDafnyMakefile.mk, fix nightly build [(#638)](https://github.com/aws/aws-encryption-sdk-dafny/commit/cd199795003d91984e24f1c04d9a84ae9c445372) -* chore(CI): add interop tests to daily ci [(#640)](https://github.com/aws/aws-encryption-sdk-dafny/commit/c9ad0181b544b258d66bf7b7e8d0b2be4cec7af9) -* chore: only run net48 on windows and use node 17 to run integration-node [(#639)](https://github.com/aws/aws-encryption-sdk-dafny/commit/d6c62fb68d974b47eb9d6cf9d8fbf249d6889b54) -* chore(.NET): Add ESDK-Net v4.0.1 generated vectors[(#636)](https://github.com/aws/aws-encryption-sdk-dafny/commit/efef49720c55a28cb422133385f8ece5ebc1da9c) -* chore(NET-SupportPolicy): Mark 3.x as Support [(#631)](https://github.com/aws/aws-encryption-sdk-dafny/commit/3c36f7a4a19646a8dfa6073be04676394502ef23) -* chore: Add manual trigger for nightly_dafny.yml [(#629)](https://github.com/aws/aws-encryption-sdk-dafny/commit/419b1cbfb4a5d85c03d0ad8c555a89108f199b98) -* chore: split vc gen on some methods to migrate to Dafny 4.4 [(#627)](https://github.com/aws/aws-encryption-sdk-dafny/commit/fdc65ca7495402b5b51017655015413eba846e7f) -* test: restore CODEOWNERS and daily CI [(#624)](https://github.com/aws/aws-encryption-sdk-dafny/commit/ff823ac918b822db548e703307d2ce462e79eef7) -* chore: update template to point to public repo [(#626)](https://github.com/aws/aws-encryption-sdk-dafny/commit/2b07a391208cb2a0508d1d915ae800e5de212d0e) -* chore: remove unused release step in test-prod [(#623)](https://github.com/aws/aws-encryption-sdk-dafny/commit/98839331a2e1154913d6ba4c88b0f4cba7322233) +- fix(CI): Daily CI uses correct workflow [(#641)](https://github.com/aws/aws-encryption-sdk-dafny/commit/771835e22f6ef3c3b34d0891fb61cb1a49bcf855) +- chore(ci): fix role to assume [(#622)](https://github.com/aws/aws-encryption-sdk-dafny/commit/c1f04fc41093593748f16da80d893c2ec5325545) +- chore(CI/CD): add semantic release automation [(#647)](https://github.com/aws/aws-encryption-sdk-dafny/commit/e7b5392ccc18f502a5517580a27bce5980e1913d) +- chore: Adopt SmithyDafnyMakefile.mk, fix nightly build [(#638)](https://github.com/aws/aws-encryption-sdk-dafny/commit/cd199795003d91984e24f1c04d9a84ae9c445372) +- chore(CI): add interop tests to daily ci [(#640)](https://github.com/aws/aws-encryption-sdk-dafny/commit/c9ad0181b544b258d66bf7b7e8d0b2be4cec7af9) +- chore: only run net48 on windows and use node 17 to run integration-node [(#639)](https://github.com/aws/aws-encryption-sdk-dafny/commit/d6c62fb68d974b47eb9d6cf9d8fbf249d6889b54) +- chore(.NET): Add ESDK-Net v4.0.1 generated vectors[(#636)](https://github.com/aws/aws-encryption-sdk-dafny/commit/efef49720c55a28cb422133385f8ece5ebc1da9c) +- chore(NET-SupportPolicy): Mark 3.x as Support [(#631)](https://github.com/aws/aws-encryption-sdk-dafny/commit/3c36f7a4a19646a8dfa6073be04676394502ef23) +- chore: Add manual trigger for nightly_dafny.yml [(#629)](https://github.com/aws/aws-encryption-sdk-dafny/commit/419b1cbfb4a5d85c03d0ad8c555a89108f199b98) +- chore: split vc gen on some methods to migrate to Dafny 4.4 [(#627)](https://github.com/aws/aws-encryption-sdk-dafny/commit/fdc65ca7495402b5b51017655015413eba846e7f) +- test: restore CODEOWNERS and daily CI [(#624)](https://github.com/aws/aws-encryption-sdk-dafny/commit/ff823ac918b822db548e703307d2ce462e79eef7) +- chore: update template to point to public repo [(#626)](https://github.com/aws/aws-encryption-sdk-dafny/commit/2b07a391208cb2a0508d1d915ae800e5de212d0e) +- chore: remove unused release step in test-prod [(#623)](https://github.com/aws/aws-encryption-sdk-dafny/commit/98839331a2e1154913d6ba4c88b0f4cba7322233) ## 4.0.1 @@ -43,19 +44,19 @@ when using the DefaultCMM. The HKDF invocation of non-committing algorithm suites failed to include the Message ID in the info parameter. -Neither of these issues -effect the security of messages +Neither of these issues +effect the security of messages written by the 4.0.0 release. -However, -these messages diverge +However, +these messages diverge from the Encryption SDK Message Specification. Thus: -* ESDK-NET v4.0.0 writes messages that only ESDK-NET v4.0.0 and greater can read. -* ESDK-NET v4.0.0 is ONLY able to read messages that are written by ESDK-NET v4.0.0 +- ESDK-NET v4.0.0 writes messages that only ESDK-NET v4.0.0 and greater can read. +- ESDK-NET v4.0.0 is ONLY able to read messages that are written by ESDK-NET v4.0.0 -These issues are fixed in 4.0.1, +These issues are fixed in 4.0.1, which writes messages according to the Encryption SDK Message Specification, and are interoperable with other implementations of this library. @@ -63,48 +64,48 @@ The option NetV4_RetryPolicy can be use to decrypt v4.0.0 messages. See [NetV4_0_0Example.cs](Examples/NetV4_0_0Example.cs) on how to use the NetV4_RetryPolicy and details on distributed applications. - ## 4.0.0 ### BREAKING CHANGES -* AWS Encryption SDK for .NET now directly depends on the AWS Cryptographic Material Providers Library for .NET -* Required Encryption Context CMM generates messages that the Encryption SDK for .NET < 4.0.0 cannot read - * This feature does not yet exist in other Encryption SDKs, as such, messages written using this feature are not interoperable - with other runtimes. -* AWS Encryption SDK now only supports .NET 6.0 and later, and .NET Framework 4.8.0 and later. +- AWS Encryption SDK for .NET now directly depends on the AWS Cryptographic Material Providers Library for .NET +- Required Encryption Context CMM generates messages that the Encryption SDK for .NET < 4.0.0 cannot read +- This feature does not yet exist in other Encryption SDKs, as such, messages written using this feature are not interoperable + with other runtimes. +- AWS Encryption SDK now only supports .NET 6.0 and later, and .NET Framework 4.8.0 and later. ### Features -* Required Encryption Context CMM -* AWS KMS RSA Keyring -* AWS KMS Hierarchical Keyring + +- Required Encryption Context CMM +- AWS KMS RSA Keyring +- AWS KMS Hierarchical Keyring ### NuGet Rename + _Added on October 16th, 2023_ As of version 4.0.0, the AWS Encryption SDK for .NET is on NuGet as [AWS.Cryptography.EncryptionSDK](https://www.nuget.org/packages/AWS.Cryptography.EncryptionSDK). Prior versions are under [AWS.EncryptionSDK](https://www.nuget.org/packages/AWS.EncryptionSDK). - ## 3.1.0 ### Fixes -* chore: pack README for display on NuGet page () -* fix: add DiscoveryFilter to MRK Discovery Keyring example () -* docs: fix .NET ESDK link in README () -* docs: fix .NET ESDK package name in README () -* docs: link to macOS setup wiki in README () +- chore: pack README for display on NuGet page () +- fix: add DiscoveryFilter to MRK Discovery Keyring example () +- docs: fix .NET ESDK link in README () +- docs: fix .NET ESDK package name in README () +- docs: link to macOS setup wiki in README () ### Maintenance -* chore: update generated KMS code () -* chore: use public spec URL for submodule () -* fix: use renamed directories for Duvet report () -* chore: bump Newtonsoft.Json in test vector projects () -* feat: add user agent to default KMS clients () -* chore: address potential unsoundness (dafny-lang/dafny#2500) () -* ci: use .NET 6.0 for release buildspecs () +- chore: update generated KMS code () +- chore: use public spec URL for submodule () +- fix: use renamed directories for Duvet report () +- chore: bump Newtonsoft.Json in test vector projects () +- feat: add user agent to default KMS clients () +- chore: address potential unsoundness (dafny-lang/dafny#2500) () +- ci: use .NET 6.0 for release buildspecs () ## 3.0.0 (2022-05-17) diff --git a/AwsEncryptionSDK/runtimes/net/Examples/README.md b/AwsEncryptionSDK/runtimes/net/Examples/README.md index f2c320e75..4b6883d2e 100644 --- a/AwsEncryptionSDK/runtimes/net/Examples/README.md +++ b/AwsEncryptionSDK/runtimes/net/Examples/README.md @@ -14,10 +14,10 @@ and streaming APIs. You can find examples that demonstrate these APIs in the [`Examples/`](./) directory. -* [How to encrypt and decrypt](./Keyring/AwsKmsKeyringExample.cs) -* [How to change the algorithm suite](./NonSigningAlgorithmSuiteExample.cs) -* [How to set the commitment policy](./CommitmentPolicy.cs) -* [How to limit the number of encrypted data keys (EDKs)](./LimitEncryptedDataKeysExample.cs) +- [How to encrypt and decrypt](./Keyring/AwsKmsKeyringExample.cs) +- [How to change the algorithm suite](./NonSigningAlgorithmSuiteExample.cs) +- [How to set the commitment policy](./CommitmentPolicy.cs) +- [How to limit the number of encrypted data keys (EDKs)](./LimitEncryptedDataKeysExample.cs) ## Configuration @@ -29,20 +29,20 @@ These examples will show you how to use the configuration tools that we include and how to create some of your own. We start with AWS KMS examples, then show how to use other wrapping keys. -* Using AWS Key Management Service (AWS KMS) - * [How to use one AWS KMS key](./Keyring/AwsKmsKeyringExample.cs) - * [How to use multiple AWS KMS keys in different regions](./Keyring/AwsKmsMrkDiscoveryMultiKeyringExample.cs) - * [How to decrypt when you don't know the AWS KMS key](./Keyring/AwsKmsDiscoveryKeyringExample.cs) - * [How to limit decryption to a single region](./Keyring/AwsKmsMrkDiscoveryKeyringExample.cs) - * [How to decrypt with a preferred region but failover to others](./Keyring/AwsKmsMrkDiscoveryMultiKeyringExample.cs) - * [How to reproduce the behavior of an AWS KMS master key provider](./Keyring/AwsKmsMultiKeyringExample.cs) -* Using raw wrapping keys - * [How to use a raw AES wrapping key](./Keyring/RawAESKeyringExample.cs) - * [How to use a raw RSA wrapping key](./Keyring/RawRSAKeyringExample.cs) -* Combining wrapping keys - * [How to combine AWS KMS with an offline escrow key](./Keyring/MultiKeyringExample.cs) -* How to restrict algorithm suites - * [with a custom cryptographic materials manager](./CryptographicMaterialsManager/RestrictAlgorithmSuite/SigningSuiteOnlyCMM.cs) +- Using AWS Key Management Service (AWS KMS) + - [How to use one AWS KMS key](./Keyring/AwsKmsKeyringExample.cs) + - [How to use multiple AWS KMS keys in different regions](./Keyring/AwsKmsMrkDiscoveryMultiKeyringExample.cs) + - [How to decrypt when you don't know the AWS KMS key](./Keyring/AwsKmsDiscoveryKeyringExample.cs) + - [How to limit decryption to a single region](./Keyring/AwsKmsMrkDiscoveryKeyringExample.cs) + - [How to decrypt with a preferred region but failover to others](./Keyring/AwsKmsMrkDiscoveryMultiKeyringExample.cs) + - [How to reproduce the behavior of an AWS KMS master key provider](./Keyring/AwsKmsMultiKeyringExample.cs) +- Using raw wrapping keys + - [How to use a raw AES wrapping key](./Keyring/RawAESKeyringExample.cs) + - [How to use a raw RSA wrapping key](./Keyring/RawRSAKeyringExample.cs) +- Combining wrapping keys + - [How to combine AWS KMS with an offline escrow key](./Keyring/MultiKeyringExample.cs) +- How to restrict algorithm suites + - [with a custom cryptographic materials manager](./CryptographicMaterialsManager/RestrictAlgorithmSuite/SigningSuiteOnlyCMM.cs) ### Keyrings @@ -86,7 +86,7 @@ please make sure that it meets the following requirements: 1. The example MAY be nested arbitrarily deeply. 1. Each example file MUST contain exactly one example. 1. Each example filename MUST be descriptive. -1. Each example file MUST contain a public class matching the filename, +1. Each example file MUST contain a public class matching the filename, with a method called `Run` that runs the example. 1. Each example MUST be exercised by a `[Fact]` test method within its class that invokes `Run`, providing only the results of methods from the [`ExampleUtils`](./ExampleUtils/ExampleUtils.cs) class. diff --git a/AwsEncryptionSDK/runtimes/net/Generated/AwsEncryptionSdk/CollectionOfErrors.cs b/AwsEncryptionSDK/runtimes/net/Generated/AwsEncryptionSdk/CollectionOfErrors.cs index f39ded66d..0a3ba6154 100644 --- a/AwsEncryptionSDK/runtimes/net/Generated/AwsEncryptionSdk/CollectionOfErrors.cs +++ b/AwsEncryptionSDK/runtimes/net/Generated/AwsEncryptionSdk/CollectionOfErrors.cs @@ -17,7 +17,7 @@ public class CollectionOfErrors : Exception private static string ListAsString(List list) { if (list.Count < 1) return ""; - string [] msgArr = new string [list.Count]; + string[] msgArr = new string[list.Count]; for (int i = 0; i < list.Count; i++) msgArr[i] = $"{list[i].GetType().Name} :: {list[i].Message}"; return String.Join("\n\t", msgArr); diff --git a/AwsEncryptionSDK/runtimes/net/README.md b/AwsEncryptionSDK/runtimes/net/README.md index 305bebd23..36cf0734f 100644 --- a/AwsEncryptionSDK/runtimes/net/README.md +++ b/AwsEncryptionSDK/runtimes/net/README.md @@ -9,11 +9,13 @@ AWS Encryption SDK for .NET The AWS Encryption SDK is available on [NuGet](https://www.nuget.org/) and can referenced from an existing `.csproj` through typical ways. Using the dotnet CLI: + ```shell dotnet add .csproj package AWS.Cryptography.EncryptionSDK ``` Alternatively, you may directly modify the `.csproj` and add the AWS Encryption SDK to `PackageReference` `ItemGroup`: + ```xml ``` @@ -35,8 +37,8 @@ To build, the AWS Encryption SDK requires the most up to date version of [Dafny] The AWS Encryption SDK targets frameworks [`net48` and `net6.0`](https://docs.microsoft.com/en-us/dotnet/standard/frameworks#supported-target-frameworks). To build and test the AWS Encryption SDK, you must install the following .NET tools: -* [.NET 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) or newer -* [.NET Framework 4.8.0](https://docs.microsoft.com/en-us/dotnet/framework/install/) or newer (if on Windows) +- [.NET 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) or newer +- [.NET Framework 4.8.0](https://docs.microsoft.com/en-us/dotnet/framework/install/) or newer (if on Windows) You will also need to ensure that you fetch all submodules using either `git clone --recursive ...` when cloning the repository or `git submodule update --init` on an existing clone. @@ -58,7 +60,7 @@ If you set up the AWS Encryption SDK to use the AWS KMS Keyring, the AWS Encryption SDK will make calls to AWS KMS on your behalf, using the appropriate AWS SDK. -However, you must first set up AWS credentials for use with the AWS SDK. +However, you must first set up AWS credentials for use with the AWS SDK. Instructions for setting up AWS credentials are available in the [AWS Docs for the AWS SDK for .NET.](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html). ## Testing the AWS Encryption SDK for .NET @@ -78,7 +80,7 @@ Run the test suite with: cd AwsEncryptionSDK make transpile_test_net # Windows/Linux -make test_net +make test_net # On Mac make test_net_mac_brew ``` @@ -97,11 +99,13 @@ Please note that tests and test vectors require internet access and valid AWS cr Most c# IDEs appreciate Solution files. To generate one Solution file for all the projects here, run: + ``` cd AwsEncryptionSDK/runtimes/net dotnet new sln --name ESDK dotnet sln add $(find . -name '*.csproj') ``` + Then ask your IDE to open `ESDK.sln`. ## License diff --git a/AwsEncryptionSDK/runtimes/net/TestVectorsNative/TestVectorGenerator/README.md b/AwsEncryptionSDK/runtimes/net/TestVectorsNative/TestVectorGenerator/README.md index 28583770e..2ebaf0260 100644 --- a/AwsEncryptionSDK/runtimes/net/TestVectorsNative/TestVectorGenerator/README.md +++ b/AwsEncryptionSDK/runtimes/net/TestVectorsNative/TestVectorGenerator/README.md @@ -7,8 +7,8 @@ as described in WrappedESDK(AwsEncryptionSdkConfig config) { - software.amazon.cryptography.encryptionsdk.model.AwsEncryptionSdkConfig wrappedConfig = ToNative.AwsEncryptionSdkConfig(config); - if (wrappedConfig.netV4_0_0_RetryPolicy() == NetV4_0_0_RetryPolicy.ALLOW_RETRY) { - throw new IllegalArgumentException("Native AWS Encryption SDK for Java does not support NetV4_0_0_RetryPolicy.ALLOW_RETRY"); + public static Result WrappedESDK( + AwsEncryptionSdkConfig config + ) { + software.amazon.cryptography.encryptionsdk.model.AwsEncryptionSdkConfig wrappedConfig = + ToNative.AwsEncryptionSdkConfig(config); + if ( + wrappedConfig.netV4_0_0_RetryPolicy() == NetV4_0_0_RetryPolicy.ALLOW_RETRY + ) { + throw new IllegalArgumentException( + "Native AWS Encryption SDK for Java does not support NetV4_0_0_RetryPolicy.ALLOW_RETRY" + ); } - CommitmentPolicy commitmentPolicy = _esdkDafnyCommitmentPolicyToNative(wrappedConfig.commitmentPolicy()); + CommitmentPolicy commitmentPolicy = _esdkDafnyCommitmentPolicyToNative( + wrappedConfig.commitmentPolicy() + ); - int maxEncryptedDataKeys = wrappedConfig.maxEncryptedDataKeys() == 0 ? 1 : (int) wrappedConfig.maxEncryptedDataKeys(); + int maxEncryptedDataKeys = wrappedConfig.maxEncryptedDataKeys() == 0 + ? 1 + : (int) wrappedConfig.maxEncryptedDataKeys(); final AwsCrypto awsCrypto; if (wrappedConfig.maxEncryptedDataKeys() == 0) { - awsCrypto = AwsCrypto.builder() - .withCommitmentPolicy(commitmentPolicy) - .build(); + awsCrypto = + AwsCrypto.builder().withCommitmentPolicy(commitmentPolicy).build(); } else { - awsCrypto = AwsCrypto.builder() - .withCommitmentPolicy(commitmentPolicy) - .withMaxEncryptedDataKeys(maxEncryptedDataKeys) - .build(); + awsCrypto = + AwsCrypto + .builder() + .withCommitmentPolicy(commitmentPolicy) + .withMaxEncryptedDataKeys(maxEncryptedDataKeys) + .build(); } TestESDK wrappedEsdk = TestESDK.builder().impl(awsCrypto).build(); - return software.amazon.cryptography.encryptionsdk.internaldafny._ExternBase___default.CreateSuccessOfClient(wrappedEsdk); + return software.amazon.cryptography.encryptionsdk.internaldafny._ExternBase___default.CreateSuccessOfClient( + wrappedEsdk + ); } - private static CommitmentPolicy _esdkDafnyCommitmentPolicyToNative(ESDKCommitmentPolicy esdkCommitmentPolicy) { + private static CommitmentPolicy _esdkDafnyCommitmentPolicyToNative( + ESDKCommitmentPolicy esdkCommitmentPolicy + ) { switch (esdkCommitmentPolicy) { case FORBID_ENCRYPT_ALLOW_DECRYPT: return CommitmentPolicy.ForbidEncryptAllowDecrypt; @@ -48,7 +63,9 @@ private static CommitmentPolicy _esdkDafnyCommitmentPolicyToNative(ESDKCommitmen case REQUIRE_ENCRYPT_REQUIRE_DECRYPT: return CommitmentPolicy.RequireEncryptRequireDecrypt; default: - throw new IllegalArgumentException("Unsupported CommitmentPolicy: " + esdkCommitmentPolicy); + throw new IllegalArgumentException( + "Unsupported CommitmentPolicy: " + esdkCommitmentPolicy + ); } } } diff --git a/TestVectors/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/encryptionsdk/wrapped/TestESDK.java b/TestVectors/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/encryptionsdk/wrapped/TestESDK.java index 262bb6227..1bc75edbb 100644 --- a/TestVectors/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/encryptionsdk/wrapped/TestESDK.java +++ b/TestVectors/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/encryptionsdk/wrapped/TestESDK.java @@ -4,6 +4,7 @@ package software.amazon.cryptography.encryptionsdk.wrapped; import Wrappers_Compile.Result; +import com.amazonaws.encryptionsdk.AwsCrypto; import com.amazonaws.encryptionsdk.CryptoAlgorithm; import com.amazonaws.encryptionsdk.CryptoResult; import dafny.DafnyMap; @@ -13,7 +14,6 @@ import java.nio.ByteBuffer; import java.util.Map; import java.util.Objects; -import com.amazonaws.encryptionsdk.AwsCrypto; import software.amazon.cryptography.encryptionsdk.ESDK; import software.amazon.cryptography.encryptionsdk.ToDafny; import software.amazon.cryptography.encryptionsdk.ToNative; @@ -47,24 +47,54 @@ public Result Decrypt(DecryptInput dafnyInput) { if (Objects.isNull(nativeInput.materialsManager())) { // Call decrypt with keyring if (Objects.isNull(nativeInput.encryptionContext())) { - decryptResult = this._impl.decryptData(nativeInput.keyring(), nativeInput.ciphertext().array()); + decryptResult = + this._impl.decryptData( + nativeInput.keyring(), + nativeInput.ciphertext().array() + ); } else { - decryptResult = this._impl.decryptData(nativeInput.keyring(), nativeInput.ciphertext().array(), nativeInput.encryptionContext()); + decryptResult = + this._impl.decryptData( + nativeInput.keyring(), + nativeInput.ciphertext().array(), + nativeInput.encryptionContext() + ); } } else { if (Objects.isNull(nativeInput.encryptionContext())) { - decryptResult = this._impl.decryptData(nativeInput.materialsManager(), nativeInput.ciphertext().array()); + decryptResult = + this._impl.decryptData( + nativeInput.materialsManager(), + nativeInput.ciphertext().array() + ); } else { - decryptResult = this._impl.decryptData(nativeInput.materialsManager(), nativeInput.ciphertext().array(), nativeInput.encryptionContext()); + decryptResult = + this._impl.decryptData( + nativeInput.materialsManager(), + nativeInput.ciphertext().array(), + nativeInput.encryptionContext() + ); } } - DafnySequence plaintext = Simple.ByteSequence(decryptResult.getResult()); - DafnyMap, ? extends DafnySequence> encryptionContext = - software.amazon.cryptography.materialproviders.ToDafny.EncryptionContext(decryptResult.getEncryptionContext()); - ESDKAlgorithmSuiteId algorithmSuiteId = software.amazon.cryptography.materialproviders.ToDafny.ESDKAlgorithmSuiteId( - decryptResult.getCryptoAlgorithm().getAlgorithmSuiteId().ESDK() + DafnySequence plaintext = Simple.ByteSequence( + decryptResult.getResult() + ); + DafnyMap< + ? extends DafnySequence, + ? extends DafnySequence + > encryptionContext = + software.amazon.cryptography.materialproviders.ToDafny.EncryptionContext( + decryptResult.getEncryptionContext() + ); + ESDKAlgorithmSuiteId algorithmSuiteId = + software.amazon.cryptography.materialproviders.ToDafny.ESDKAlgorithmSuiteId( + decryptResult.getCryptoAlgorithm().getAlgorithmSuiteId().ESDK() + ); + DecryptOutput dafnyOutput = new DecryptOutput( + plaintext, + encryptionContext, + algorithmSuiteId ); - DecryptOutput dafnyOutput = new DecryptOutput(plaintext, encryptionContext, algorithmSuiteId); return Result.create_Success( DecryptOutput._typeDescriptor(), @@ -88,31 +118,63 @@ public Result Encrypt(EncryptInput dafnyInput) { // Java ESDK is special and you have to set the algorithm suite both in the keyring which the // test vectors do, but also in the client itself. - CryptoAlgorithm cryptoAlgorithm = _getAlgorithmSuite(nativeInput.algorithmSuiteId()); + CryptoAlgorithm cryptoAlgorithm = _getAlgorithmSuite( + nativeInput.algorithmSuiteId() + ); this._impl.setEncryptionAlgorithm(cryptoAlgorithm); if (Objects.isNull(nativeInput.materialsManager())) { // Call decrypt with keyring if (Objects.isNull(nativeInput.encryptionContext())) { - encryptResult = this._impl.encryptData(nativeInput.keyring(), nativeInput.plaintext().array()); + encryptResult = + this._impl.encryptData( + nativeInput.keyring(), + nativeInput.plaintext().array() + ); } else { - encryptResult = this._impl.encryptData(nativeInput.keyring(), nativeInput.plaintext().array(), nativeInput.encryptionContext()); + encryptResult = + this._impl.encryptData( + nativeInput.keyring(), + nativeInput.plaintext().array(), + nativeInput.encryptionContext() + ); } } else { if (Objects.isNull(nativeInput.encryptionContext())) { - encryptResult = this._impl.encryptData(nativeInput.materialsManager(), nativeInput.plaintext().array()); + encryptResult = + this._impl.encryptData( + nativeInput.materialsManager(), + nativeInput.plaintext().array() + ); } else { - encryptResult = this._impl.encryptData(nativeInput.materialsManager(), nativeInput.plaintext().array(), nativeInput.encryptionContext()); + encryptResult = + this._impl.encryptData( + nativeInput.materialsManager(), + nativeInput.plaintext().array(), + nativeInput.encryptionContext() + ); } } - dafny.DafnySequence ciphertext = Simple.ByteSequence(encryptResult.getResult()); - DafnyMap, ? extends DafnySequence> encryptionContext = - software.amazon.cryptography.materialproviders.ToDafny.EncryptionContext(encryptResult.getEncryptionContext()); - ESDKAlgorithmSuiteId algorithmSuiteId = software.amazon.cryptography.materialproviders.ToDafny.ESDKAlgorithmSuiteId( - encryptResult.getCryptoAlgorithm().getAlgorithmSuiteId().ESDK() + dafny.DafnySequence ciphertext = Simple.ByteSequence( + encryptResult.getResult() ); + DafnyMap< + ? extends DafnySequence, + ? extends DafnySequence + > encryptionContext = + software.amazon.cryptography.materialproviders.ToDafny.EncryptionContext( + encryptResult.getEncryptionContext() + ); + ESDKAlgorithmSuiteId algorithmSuiteId = + software.amazon.cryptography.materialproviders.ToDafny.ESDKAlgorithmSuiteId( + encryptResult.getCryptoAlgorithm().getAlgorithmSuiteId().ESDK() + ); - EncryptOutput dafnyOutput = new EncryptOutput(ciphertext, encryptionContext, algorithmSuiteId); + EncryptOutput dafnyOutput = new EncryptOutput( + ciphertext, + encryptionContext, + algorithmSuiteId + ); return Result.create_Success( EncryptOutput._typeDescriptor(), Error._typeDescriptor(), @@ -127,7 +189,9 @@ public Result Encrypt(EncryptInput dafnyInput) { } } - private CryptoAlgorithm _getAlgorithmSuite(software.amazon.cryptography.materialproviders.model.ESDKAlgorithmSuiteId esdkAlgorithmSuiteId) { + private CryptoAlgorithm _getAlgorithmSuite( + software.amazon.cryptography.materialproviders.model.ESDKAlgorithmSuiteId esdkAlgorithmSuiteId + ) { switch (esdkAlgorithmSuiteId) { case ALG_AES_128_GCM_IV12_TAG16_NO_KDF: return CryptoAlgorithm.ALG_AES_128_GCM_IV12_TAG16_NO_KDF; @@ -152,7 +216,9 @@ private CryptoAlgorithm _getAlgorithmSuite(software.amazon.cryptography.material case ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384: return CryptoAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384; default: - throw new IllegalArgumentException("Unrecognized ESDK algorithmSuiteId: " + esdkAlgorithmSuiteId); + throw new IllegalArgumentException( + "Unrecognized ESDK algorithmSuiteId: " + esdkAlgorithmSuiteId + ); } } diff --git a/TestVectors/runtimes/java/src/test/java/TestWrappedESDKMain/__default.java b/TestVectors/runtimes/java/src/test/java/TestWrappedESDKMain/__default.java index ce798166d..9228cceed 100644 --- a/TestVectors/runtimes/java/src/test/java/TestWrappedESDKMain/__default.java +++ b/TestVectors/runtimes/java/src/test/java/TestWrappedESDKMain/__default.java @@ -6,7 +6,7 @@ public class __default extends _ExternBase___default { public static dafny.DafnySequence< ? extends Character - > GetTestVectorExecutionDirectory() { + > GetTestVectorExecutionDirectory() { return DafnySequence.asString(""); } } diff --git a/cfn/CI.yaml b/cfn/CI.yaml index 497a1e10b..ebe578c0a 100644 --- a/cfn/CI.yaml +++ b/cfn/CI.yaml @@ -21,7 +21,7 @@ Parameters: Resources: GitHubCIRole: - Type: 'AWS::IAM::Role' + Type: "AWS::IAM::Role" Properties: RoleName: !Sub "GitHub-CI-${ProjectName}-Role-${AWS::Region}" Description: "Access DDB, KMS, Resources for CI from GitHub" diff --git a/cfn/net/CA-Staging.yml b/cfn/net/CA-Staging.yml index 62cec7a13..530a8f100 100644 --- a/cfn/net/CA-Staging.yml +++ b/cfn/net/CA-Staging.yml @@ -36,4 +36,3 @@ Resources: Properties: DomainName: !Ref DomainName RepositoryName: !Sub "${RepositoryName}-staging" - diff --git a/cfn/net/CB-Release.yml b/cfn/net/CB-Release.yml index 29adc849b..a814f0a61 100644 --- a/cfn/net/CB-Release.yml +++ b/cfn/net/CB-Release.yml @@ -112,7 +112,7 @@ Resources: } ] } - + AssumeArtifactRolePolicy: Type: "AWS::IAM::ManagedPolicy" Properties: @@ -240,28 +240,28 @@ Resources: } ] } - + CryptoToolsKMS: - Type: "AWS::IAM::ManagedPolicy" - Properties: - ManagedPolicyName: !Sub >- - CrypotToolsKMSPolicy-${ProjectName}-${AWS::Region}-codebuild-${ProjectName}-service-role - Path: /service-role/ - PolicyDocument: !Sub | - { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Resource": [ - "arn:aws:kms:*:658956600833:key/*", - "arn:aws:kms:*:658956600833:alias/*" - ], - "Action": [ - "kms:Encrypt", - "kms:Decrypt", - "kms:GenerateDataKey" - ] - } - ] - } + Type: "AWS::IAM::ManagedPolicy" + Properties: + ManagedPolicyName: !Sub >- + CrypotToolsKMSPolicy-${ProjectName}-${AWS::Region}-codebuild-${ProjectName}-service-role + Path: /service-role/ + PolicyDocument: !Sub | + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Resource": [ + "arn:aws:kms:*:658956600833:key/*", + "arn:aws:kms:*:658956600833:alias/*" + ], + "Action": [ + "kms:Encrypt", + "kms:Decrypt", + "kms:GenerateDataKey" + ] + } + ] + } diff --git a/codebuild/dafny/verify.yml b/codebuild/dafny/verify.yml index bed5700c1..a47775131 100644 --- a/codebuild/dafny/verify.yml +++ b/codebuild/dafny/verify.yml @@ -14,8 +14,8 @@ phases: - dotnet build -t:VerifyDafny -p:TestVerifyOverride="verificationLogger:trx" test - MAX_VERIFICATION_DURATION_SECONDS=40 python3 verification-times-from-trx.py test/TestResults/*.trx reports: - Dafny: - file-format: VisualStudioTrx - files: - - '**/*' - base-directory: 'test/TestResults' + Dafny: + file-format: VisualStudioTrx + files: + - "**/*" + base-directory: "test/TestResults" diff --git a/codebuild/dotnet/benchmark-windows.yml b/codebuild/dotnet/benchmark-windows.yml index 7fef22a01..acd42562e 100644 --- a/codebuild/dotnet/benchmark-windows.yml +++ b/codebuild/dotnet/benchmark-windows.yml @@ -2,9 +2,8 @@ version: 0.2 env: variables: - BENCHMARK_PLAINTEXT_LENGTH_BYTES: '1,1000,1000000' - BENCHMARK_FRAME_LENGTH_BYTES: '4096' # the ESDK's default - + BENCHMARK_PLAINTEXT_LENGTH_BYTES: "1,1000,1000000" + BENCHMARK_FRAME_LENGTH_BYTES: "4096" # the ESDK's default phases: install: diff --git a/project.properties b/project.properties new file mode 100644 index 000000000..450316e50 --- /dev/null +++ b/project.properties @@ -0,0 +1,7 @@ +dafnyVersion=4.9.0 +dafnyVerifyVersion=4.9.0 +dafnyFormatVersion=4.9.0 +projectJavaVersion=4.1.0 +mplDependencyJavaVersion=1.8.0 +dafnyRuntimeJavaVersion=4.9.0 +smithyDafnyJavaConversionVersion=0.1.1 diff --git a/releases/go/encryption-sdk/README.md b/releases/go/encryption-sdk/README.md index 38465be36..2388cd09b 100644 --- a/releases/go/encryption-sdk/README.md +++ b/releases/go/encryption-sdk/README.md @@ -1,6 +1,5 @@ # AWS Encryption SDK for Go - This is the official AWS Encryption SDK for Go. ## [CHANGELOG](https://github.com/aws/aws-encryption-sdk/blob/mainline/AwsEncryptionSDK/releases/go/encryption-sdk/CHANGELOG.md) @@ -15,7 +14,6 @@ For more details about the design and architecture of the AWS Encryption SDK, se `go get github.com/aws/aws-encryption-sdk/releases/go/encryption-sdk@latest` - ## Examples for AWS Encryption SDK in Go Please look at the Examples on how to use the Encryption SDK in Go [here](https://github.com/aws/aws-encryption-sdk/tree/mainline/releases/go/encryption-sdk/examples). diff --git a/releases/go/encryption-sdk/examples/README.md b/releases/go/encryption-sdk/examples/README.md index df7de5e1b..cf5956f4b 100644 --- a/releases/go/encryption-sdk/examples/README.md +++ b/releases/go/encryption-sdk/examples/README.md @@ -14,10 +14,10 @@ and streaming APIs. You can find examples that demonstrate these APIs in the [`examples/`](./) directory. -* [How to encrypt and decrypt](./keyring/awskmskeyring/awskmskeyring.go) -* [How to change the algorithm suite](./misc/setencryptionalgorithmsuite.go) -* [How to set the commitment policy](./misc/commitmentpolicy.go) -* [How to limit the number of encrypted data keys (EDKs)](./misc/limitencrypteddatakeysexample.go) +- [How to encrypt and decrypt](./keyring/awskmskeyring/awskmskeyring.go) +- [How to change the algorithm suite](./misc/setencryptionalgorithmsuite.go) +- [How to set the commitment policy](./misc/commitmentpolicy.go) +- [How to limit the number of encrypted data keys (EDKs)](./misc/limitencrypteddatakeysexample.go) ## Configuration @@ -29,20 +29,20 @@ These examples will show you how to use the configuration tools that we include and how to create some of your own. We start with AWS KMS examples, then show how to use other wrapping keys. -* Using AWS Key Management Service (AWS KMS) - * [How to use one AWS KMS key](./keyring/awskmskeyring/awskmskeyring.go) - * [How to use multiple AWS KMS keys in different regions](./keyring/awskmsmrkmultikeyring/awskmsmrkmultikeyring.go) - * [How to decrypt when you don't know the AWS KMS key](./keyring/awskmsdiscoverykeyring/awskmsdiscoverykeyring.go) - * [How to limit decryption to a single region](./keyring/awskmsmrkdiscoverykeyring/awskmsmrkdiscoverykeyring.go) - * [How to decrypt with a preferred region but failover to others](./keyring/awskmsmrkdiscoverykeyring/awskmsmrkdiscoverykeyring.go) - * [How to reproduce the behavior of an AWS KMS master key provider](./keyring/awskmsmultikeyring/awskmsmultikeyring.go) -* Using raw wrapping keys - * [How to use a raw AES wrapping key](./keyring/rawaeskeyring/rawaeskeyring.go) - * [How to use a raw RSA wrapping key](./keyring/rawrsakeyring/rawrasakeyring.go) -* Combining wrapping keys - * [How to combine AWS KMS with an offline escrow key](./keyring/multikeyring/multikeyring.go) -* How to restrict algorithm suites - * [with a custom cryptographic materials manager](./cryptographicmaterialsmanager/restrictalgorithmsuite/signingsuiteonlycmm.go) +- Using AWS Key Management Service (AWS KMS) + - [How to use one AWS KMS key](./keyring/awskmskeyring/awskmskeyring.go) + - [How to use multiple AWS KMS keys in different regions](./keyring/awskmsmrkmultikeyring/awskmsmrkmultikeyring.go) + - [How to decrypt when you don't know the AWS KMS key](./keyring/awskmsdiscoverykeyring/awskmsdiscoverykeyring.go) + - [How to limit decryption to a single region](./keyring/awskmsmrkdiscoverykeyring/awskmsmrkdiscoverykeyring.go) + - [How to decrypt with a preferred region but failover to others](./keyring/awskmsmrkdiscoverykeyring/awskmsmrkdiscoverykeyring.go) + - [How to reproduce the behavior of an AWS KMS master key provider](./keyring/awskmsmultikeyring/awskmsmultikeyring.go) +- Using raw wrapping keys + - [How to use a raw AES wrapping key](./keyring/rawaeskeyring/rawaeskeyring.go) + - [How to use a raw RSA wrapping key](./keyring/rawrsakeyring/rawrasakeyring.go) +- Combining wrapping keys + - [How to combine AWS KMS with an offline escrow key](./keyring/multikeyring/multikeyring.go) +- How to restrict algorithm suites + - [with a custom cryptographic materials manager](./cryptographicmaterialsmanager/restrictalgorithmsuite/signingsuiteonlycmm.go) ### Keyrings @@ -83,8 +83,8 @@ To make sure that your example runs in our CI, please make sure that it meets the following requirements: 1. The example MUST be a distinct subdirectory or file in the [`examples/`](./) directory. -1. The example MAY be nested arbitrarily deeply. +1. The example MAY be nested arbitrarily deeply. 1. Each example file MUST contain exactly one example. 1. Each example filename MUST be descriptive. 1. Each example file MUST contain validation checks to check for expected returned values and MUST panic is the returned value is no expected. -1. Each example MUST also be called inside the `main` function of [main.go](./main.go). \ No newline at end of file +1. Each example MUST also be called inside the `main` function of [main.go](./main.go). diff --git a/releases/rust/esdk/examples/README.md b/releases/rust/esdk/examples/README.md index 5f75e54b2..52c81baec 100644 --- a/releases/rust/esdk/examples/README.md +++ b/releases/rust/esdk/examples/README.md @@ -14,10 +14,10 @@ and streaming APIs. You can find examples that demonstrate these APIs in the [`examples/`](./) directory. -* [How to encrypt and decrypt](./keyring/aws_kms_keyring_example.rs) -* [How to change the algorithm suite](./set_encryption_algorithm_suite_example.rs) -* [How to set the commitment policy](./set_commitment_policy_example.rs) -* [How to limit the number of encrypted data keys (EDKs)](./limit_encrypted_data_keys_example.rs) +- [How to encrypt and decrypt](./keyring/aws_kms_keyring_example.rs) +- [How to change the algorithm suite](./set_encryption_algorithm_suite_example.rs) +- [How to set the commitment policy](./set_commitment_policy_example.rs) +- [How to limit the number of encrypted data keys (EDKs)](./limit_encrypted_data_keys_example.rs) ## Configuration @@ -29,20 +29,20 @@ These examples will show you how to use the configuration tools that we include and how to create some of your own. We start with AWS KMS examples, then show how to use other wrapping keys. -* Using AWS Key Management Service (AWS KMS) - * [How to use one AWS KMS key](./keyring/aws_kms_keyring_example.rs) - * [How to use multiple AWS KMS keys in different regions](./keyring/aws_kms_mrk_discovery_multi_keyring_example.rs) - * [How to decrypt when you don't know the AWS KMS key](./keyring/aws_kms_discovery_keyring_example.rs) - * [How to limit decryption to a single region](./keyring/aws_kms_mrk_discovery_keyring_example.rs) - * [How to decrypt with a preferred region but failover to others](./keyring/aws_kms_mrk_discovery_multi_keyring_example.rs) - * [How to reproduce the behavior of an AWS KMS master key provider](./keyring/aws_kms_multi_keyring_example.rs) -* Using raw wrapping keys - * [How to use a raw AES wrapping key](./keyring/raw_aes_keyring_example.rs) - * [How to use a raw RSA wrapping key](./keyring/raw_rsa_keyring_example.rs) -* Combining wrapping keys - * [How to combine AWS KMS with an offline escrow key](./keyring/multi_keyring_example.rs) -* How to restrict algorithm suites - * [with a custom cryptographic materials manager](./cryptographic_materials_manager/restrict_algorithm_suite/signing_suite_only_cmm.rs) +- Using AWS Key Management Service (AWS KMS) + - [How to use one AWS KMS key](./keyring/aws_kms_keyring_example.rs) + - [How to use multiple AWS KMS keys in different regions](./keyring/aws_kms_mrk_discovery_multi_keyring_example.rs) + - [How to decrypt when you don't know the AWS KMS key](./keyring/aws_kms_discovery_keyring_example.rs) + - [How to limit decryption to a single region](./keyring/aws_kms_mrk_discovery_keyring_example.rs) + - [How to decrypt with a preferred region but failover to others](./keyring/aws_kms_mrk_discovery_multi_keyring_example.rs) + - [How to reproduce the behavior of an AWS KMS master key provider](./keyring/aws_kms_multi_keyring_example.rs) +- Using raw wrapping keys + - [How to use a raw AES wrapping key](./keyring/raw_aes_keyring_example.rs) + - [How to use a raw RSA wrapping key](./keyring/raw_rsa_keyring_example.rs) +- Combining wrapping keys + - [How to combine AWS KMS with an offline escrow key](./keyring/multi_keyring_example.rs) +- How to restrict algorithm suites + - [with a custom cryptographic materials manager](./cryptographic_materials_manager/restrict_algorithm_suite/signing_suite_only_cmm.rs) ### Keyrings