From 9297e1bad3860301bcf52b73466ec4b762e4f817 Mon Sep 17 00:00:00 2001
From: Darwin Chowdary <39110935+imabhichow@users.noreply.github.com>
Date: Tue, 5 Dec 2023 15:20:43 -0800
Subject: [PATCH 1/3] feat!: Integrate ESDK-Java with AWS Cryptographic
Material Providers Library (MPL) for Keyring and CMM Support. (#1864)
feat!: Integrate ESDK-Java with AWS Cryptographic Material Providers Library (MPL) for Keyring and CMM Support.
New Features:
The AWS ESDK for Java now incorporates the AWS Cryptographic Material Providers Library (MPL), enabling the use of Keyrings and Cryptographic Materials Managers (CMMs).
BREAKING CHANGE:
This feature update includes a breaking change that requires AWS SDK v2 Java as a hard dependency.
---
.github/workflows/ci.yml | 31 +
.gitmodules | 3 +
aws-encryption-sdk-specification | 2 +-
codebuild/ci/release-ci.yml | 21 +
codebuild/ci/vectors-ci.yml | 29 +
codebuild/ci/vectors-generator.yml | 53 ++
codebuild/release/release-prod.yml | 19 +
codebuild/release/release-staging.yml | 19 +
.../aws-kms-mrk-aware-multi-keyrings.java | 104 ---
.../aws-kms-mrk-aware-symmetric-keyring.java | 226 -----
...re-symmetric-region-discovery-keyring.java | 125 ---
pom.xml | 39 +-
.../keyrings/AwsKmsRsaKeyringExample.java | 224 +++++
.../BasicEncryptionKeyringExample.java | 89 ++
.../DiscoveryDecryptionKeyringExample.java | 130 +++
...ryMultiRegionDecryptionKeyringExample.java | 161 ++++
.../EscrowedEncryptKeyringExample.java | 234 +++++
.../keyrings/FileStreamingKeyringExample.java | 124 +++
.../keyrings/MultiKeyringExample.java | 160 ++++
.../MultipleCmkEncryptKeyringExample.java | 128 +++
.../keyrings/RawAesKeyringExample.java | 115 +++
.../keyrings/RawRsaKeyringExample.java | 149 ++++
.../RequiredEncryptionContextCMMExample.java | 110 +++
.../SetCommitmentPolicyKeyringExample.java | 102 +++
.../SetEncryptionAlgorithmKeyringExample.java | 98 ++
...thRequiredEncryptionContextCMMExample.java | 124 +++
.../AwsKmsHierarchicalKeyringExample.java | 333 +++++++
.../hierarchical/CreateBranchKeyId.java | 45 +
.../ExampleBranchKeyIdSupplier.java | 44 +
.../hierarchical/VersionBranchKeyId.java | 43 +
.../{ => v2}/BasicEncryptionExample.java | 2 +-
.../BasicMultiRegionKeyEncryptionExample.java | 2 +-
.../{ => v2}/DiscoveryDecryptionExample.java | 2 +-
...DiscoveryMultiRegionDecryptionExample.java | 2 +-
.../{ => v2}/EscrowedEncryptExample.java | 2 +-
.../{ => v2}/FileStreamingExample.java | 2 +-
.../{ => v2}/MultipleCmkEncryptExample.java | 2 +-
.../{ => v2}/RestrictRegionExample.java | 2 +-
.../{ => v2}/SetCommitmentPolicyExample.java | 12 +-
.../SetEncryptionAlgorithmExample.java | 2 +-
.../{ => v2}/SimpleDataKeyCachingExample.java | 2 +-
.../amazonaws/encryptionsdk/AwsCrypto.java | 839 +++++++++++++++++-
.../amazonaws/encryptionsdk/CMMHandler.java | 100 +++
.../encryptionsdk/CommitmentPolicy.java | 23 +-
.../encryptionsdk/CryptoAlgorithm.java | 407 +++------
.../encryptionsdk/CryptoInputStream.java | 5 +-
.../encryptionsdk/CryptoOutputStream.java | 5 +-
.../amazonaws/encryptionsdk/CryptoResult.java | 9 +-
.../DefaultCryptoMaterialsManager.java | 1 +
.../internal/DecryptionHandler.java | 228 ++++-
.../internal/EncryptionHandler.java | 56 +-
.../internal/TrailingSignatureAlgorithm.java | 60 +-
.../model/DecryptionMaterials.java | 18 +
.../model/DecryptionMaterialsHandler.java | 76 ++
.../model/DecryptionMaterialsRequest.java | 18 +
.../model/EncryptionMaterials.java | 2 +
.../model/EncryptionMaterialsHandler.java | 105 +++
.../AwsKmsHierarchicalKeyringExampleTest.java | 26 +
.../keyrings/AwsKmsRsaKeyringExampleTest.java | 15 +
.../BasicEncryptionKeyringExampleTest.java | 15 +
...DiscoveryDecryptionKeyringExampleTest.java | 19 +
...ltiRegionDecryptionKeyringExampleTest.java | 19 +
.../keyrings/MultiKeyringExampleTest.java | 15 +
.../MultipleCmkEncryptKeyringExampleTest.java | 16 +
.../keyrings/RawAesKeyringExampleTest.java | 17 +
.../keyrings/RawRsaKeyringExampleTest.java | 19 +
...quiredEncryptionContextCMMExampleTest.java | 16 +
...SetCommitmentPolicyKeyringExampleTest.java | 16 +
...EncryptionAlgorithmKeyringExampleTest.java | 16 +
...quiredEncryptionContextCMMExampleTest.java | 47 +
.../{ => v2}/BasicEncryptionExampleTest.java | 2 +-
...icMultiRegionKeyEncryptionExampleTest.java | 2 +-
.../DiscoveryDecryptionExampleTest.java | 2 +-
...overyMultiRegionDecryptionExampleTest.java | 2 +-
.../MultipleCmkEncryptExampleTest.java | 2 +-
.../{ => v2}/RestrictRegionExampleTest.java | 2 +-
.../SetCommitmentPolicyExampleTest.java | 2 +-
.../SetEncryptionAlgorithmExampleTest.java | 2 +-
.../SimpleDataKeyCachingExampleTest.java | 2 +-
.../encryptionsdk/AllTestsSuite.java | 53 +-
.../AwsCryptoIntegrationTest.java | 613 +++++++++++++
.../encryptionsdk/CryptoAlgorithmTest.java | 4 +-
.../encryptionsdk/CryptoInputStreamTest.java | 465 ++++++++++
.../encryptionsdk/CryptoOutputStreamTest.java | 72 ++
.../encryptionsdk/DecryptionMethod.java | 141 ++-
.../EncryptionContextCMMTest.java | 818 +++++++++++++++++
.../com/amazonaws/encryptionsdk/Fixtures.java | 116 +++
.../encryptionsdk/ParsedCiphertextTest.java | 4 +-
.../encryptionsdk/TestVectorGenerator.java | 570 ++++++++++++
.../encryptionsdk/TestVectorRunner.java | 134 ++-
.../internal/DecryptionHandlerTest.java | 4 +-
.../internal/EncryptionHandlerTest.java | 70 +-
.../encryptionsdk/jce/JceMasterKeyTest.java | 6 +-
.../encryptionsdk/kms/KMSTestFixtures.java | 7 +
.../MaxEncryptedDataKeysIntegrationTest.java | 7 +-
src/test/resources/keys.json | 214 +++++
submodules/MaterialProviders | 1 +
97 files changed, 7765 insertions(+), 876 deletions(-)
create mode 100644 codebuild/ci/vectors-generator.yml
delete mode 100644 compliance_exceptions/aws-kms-mrk-aware-multi-keyrings.java
delete mode 100644 compliance_exceptions/aws-kms-mrk-aware-symmetric-keyring.java
delete mode 100644 compliance_exceptions/aws-kms-mrk-aware-symmetric-region-discovery-keyring.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/AwsKmsRsaKeyringExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/BasicEncryptionKeyringExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/DiscoveryDecryptionKeyringExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/DiscoveryMultiRegionDecryptionKeyringExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/EscrowedEncryptKeyringExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/FileStreamingKeyringExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/MultiKeyringExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/MultipleCmkEncryptKeyringExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/RawAesKeyringExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/RawRsaKeyringExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/RequiredEncryptionContextCMMExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/SetCommitmentPolicyKeyringExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/SetEncryptionAlgorithmKeyringExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/StreamingWithRequiredEncryptionContextCMMExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/AwsKmsHierarchicalKeyringExample.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/CreateBranchKeyId.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/ExampleBranchKeyIdSupplier.java
create mode 100644 src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/VersionBranchKeyId.java
rename src/examples/java/com/amazonaws/crypto/examples/{ => v2}/BasicEncryptionExample.java (98%)
rename src/examples/java/com/amazonaws/crypto/examples/{ => v2}/BasicMultiRegionKeyEncryptionExample.java (99%)
rename src/examples/java/com/amazonaws/crypto/examples/{ => v2}/DiscoveryDecryptionExample.java (99%)
rename src/examples/java/com/amazonaws/crypto/examples/{ => v2}/DiscoveryMultiRegionDecryptionExample.java (99%)
rename src/examples/java/com/amazonaws/crypto/examples/{ => v2}/EscrowedEncryptExample.java (99%)
rename src/examples/java/com/amazonaws/crypto/examples/{ => v2}/FileStreamingExample.java (99%)
rename src/examples/java/com/amazonaws/crypto/examples/{ => v2}/MultipleCmkEncryptExample.java (99%)
rename src/examples/java/com/amazonaws/crypto/examples/{ => v2}/RestrictRegionExample.java (99%)
rename src/examples/java/com/amazonaws/crypto/examples/{ => v2}/SetCommitmentPolicyExample.java (99%)
rename src/examples/java/com/amazonaws/crypto/examples/{ => v2}/SetEncryptionAlgorithmExample.java (99%)
rename src/examples/java/com/amazonaws/crypto/examples/{ => v2}/SimpleDataKeyCachingExample.java (98%)
create mode 100644 src/main/java/com/amazonaws/encryptionsdk/CMMHandler.java
create mode 100644 src/main/java/com/amazonaws/encryptionsdk/model/DecryptionMaterialsHandler.java
create mode 100644 src/main/java/com/amazonaws/encryptionsdk/model/EncryptionMaterialsHandler.java
create mode 100644 src/test/java/com/amazonaws/crypto/examples/keyrings/AwsKmsHierarchicalKeyringExampleTest.java
create mode 100644 src/test/java/com/amazonaws/crypto/examples/keyrings/AwsKmsRsaKeyringExampleTest.java
create mode 100644 src/test/java/com/amazonaws/crypto/examples/keyrings/BasicEncryptionKeyringExampleTest.java
create mode 100644 src/test/java/com/amazonaws/crypto/examples/keyrings/DiscoveryDecryptionKeyringExampleTest.java
create mode 100644 src/test/java/com/amazonaws/crypto/examples/keyrings/DiscoveryMultiRegionDecryptionKeyringExampleTest.java
create mode 100644 src/test/java/com/amazonaws/crypto/examples/keyrings/MultiKeyringExampleTest.java
create mode 100644 src/test/java/com/amazonaws/crypto/examples/keyrings/MultipleCmkEncryptKeyringExampleTest.java
create mode 100644 src/test/java/com/amazonaws/crypto/examples/keyrings/RawAesKeyringExampleTest.java
create mode 100644 src/test/java/com/amazonaws/crypto/examples/keyrings/RawRsaKeyringExampleTest.java
create mode 100644 src/test/java/com/amazonaws/crypto/examples/keyrings/RequiredEncryptionContextCMMExampleTest.java
create mode 100644 src/test/java/com/amazonaws/crypto/examples/keyrings/SetCommitmentPolicyKeyringExampleTest.java
create mode 100644 src/test/java/com/amazonaws/crypto/examples/keyrings/SetEncryptionAlgorithmKeyringExampleTest.java
create mode 100644 src/test/java/com/amazonaws/crypto/examples/keyrings/StreamingWithRequiredEncryptionContextCMMExampleTest.java
rename src/test/java/com/amazonaws/crypto/examples/{ => v2}/BasicEncryptionExampleTest.java (89%)
rename src/test/java/com/amazonaws/crypto/examples/{ => v2}/BasicMultiRegionKeyEncryptionExampleTest.java (91%)
rename src/test/java/com/amazonaws/crypto/examples/{ => v2}/DiscoveryDecryptionExampleTest.java (91%)
rename src/test/java/com/amazonaws/crypto/examples/{ => v2}/DiscoveryMultiRegionDecryptionExampleTest.java (93%)
rename src/test/java/com/amazonaws/crypto/examples/{ => v2}/MultipleCmkEncryptExampleTest.java (90%)
rename src/test/java/com/amazonaws/crypto/examples/{ => v2}/RestrictRegionExampleTest.java (92%)
rename src/test/java/com/amazonaws/crypto/examples/{ => v2}/SetCommitmentPolicyExampleTest.java (89%)
rename src/test/java/com/amazonaws/crypto/examples/{ => v2}/SetEncryptionAlgorithmExampleTest.java (90%)
rename src/test/java/com/amazonaws/crypto/examples/{ => v2}/SimpleDataKeyCachingExampleTest.java (96%)
create mode 100644 src/test/java/com/amazonaws/encryptionsdk/AwsCryptoIntegrationTest.java
create mode 100644 src/test/java/com/amazonaws/encryptionsdk/EncryptionContextCMMTest.java
create mode 100644 src/test/java/com/amazonaws/encryptionsdk/Fixtures.java
create mode 100644 src/test/java/com/amazonaws/encryptionsdk/TestVectorGenerator.java
create mode 100644 src/test/resources/keys.json
create mode 160000 submodules/MaterialProviders
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 98a79a5d..53d2817f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -58,6 +58,37 @@ jobs:
env-vars-for-codebuild: JAVA_ENV_VERSION
env:
JAVA_ENV_VERSION: ${{ matrix.platform.distribution }}${{ matrix.version }}
+ generateTestVectors:
+ name: Generate Vectors
+ runs-on: ubuntu-latest
+ strategy:
+ max-parallel: 1
+ fail-fast: true
+ matrix:
+ platform:
+ - distribution: openjdk
+ image: "aws/codebuild/standard:3.0"
+ - distribution: corretto
+ image: "aws/codebuild/amazonlinux2-x86_64-standard:3.0" # Corretto only runs on AL2
+ version: [ 8, 11 ]
+ steps:
+ - name: Configure AWS Credentials
+ uses: aws-actions/configure-aws-credentials@v2
+ with:
+ role-to-assume: ${{ secrets.CI_AWS_ROLE_ARN }}
+ aws-region: us-west-2
+ role-duration-seconds: 3600
+ - name: Generate Test Vectors
+ uses: aws-actions/aws-codebuild-run-build@v1
+ timeout-minutes: 60
+ with:
+ project-name: AWS-ESDK-Java-CI
+ buildspec-override: codebuild/ci/vectors-generator.yml
+ compute-type-override: BUILD_GENERAL1_LARGE
+ image-override: ${{ matrix.platform.image }}
+ env-vars-for-codebuild: JAVA_ENV_VERSION
+ env:
+ JAVA_ENV_VERSION: ${{ matrix.platform.distribution }}${{ matrix.version }}
releaseCI:
name: Release CI
runs-on: ubuntu-latest
diff --git a/.gitmodules b/.gitmodules
index b90e3bf8..f4916f35 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
[submodule "aws-encryption-sdk-specification"]
path = aws-encryption-sdk-specification
url = https://github.com/awslabs/aws-encryption-sdk-specification.git
+[submodule "submodules/MaterialProviders"]
+ path = submodules/MaterialProviders
+ url = https://github.com/aws/aws-cryptographic-material-providers-library-java.git
diff --git a/aws-encryption-sdk-specification b/aws-encryption-sdk-specification
index c35fbd91..bfbe06dd 160000
--- a/aws-encryption-sdk-specification
+++ b/aws-encryption-sdk-specification
@@ -1 +1 @@
-Subproject commit c35fbd91b28303d69813119088c44b5006395eb4
+Subproject commit bfbe06dd7333fc27aad0e311c5dfff9fec40c4f0
diff --git a/codebuild/ci/release-ci.yml b/codebuild/ci/release-ci.yml
index 1f799295..d6b89a23 100644
--- a/codebuild/ci/release-ci.yml
+++ b/codebuild/ci/release-ci.yml
@@ -17,6 +17,16 @@ phases:
install:
runtime-versions:
java: openjdk11
+ commands:
+ - git submodule update --init submodules/MaterialProviders
+ # Get Dafny
+ - curl https://github.com/dafny-lang/dafny/releases/download/v4.2.0/dafny-4.2.0-x64-ubuntu-20.04.zip -L -o dafny.zip
+ - unzip -qq dafny.zip && rm dafny.zip
+ - export PATH="$PWD/dafny:$PATH"
+ # Get Gradle 7.6
+ - curl https://services.gradle.org/distributions/gradle-7.6-all.zip -L -o gradle.zip
+ - unzip -qq gradle.zip && rm gradle.zip
+ - export PATH="$PWD/gradle-7.6/bin:$PATH"
pre_build:
commands:
- export SETTINGS_FILE=$(pwd)/codebuild/release/settings.xml
@@ -24,6 +34,17 @@ phases:
- export CODEARTIFACT_REPO_URL=https://${DOMAIN}-${ACCOUNT}.d.codeartifact.${REGION}.amazonaws.com/maven/${REPOSITORY}
- aws secretsmanager get-secret-value --region us-west-2 --secret-id Maven-GPG-Keys-CI --query SecretBinary --output text | base64 -d > ~/mvn_gpg.tgz
- tar -xvf ~/mvn_gpg.tgz -C ~
+
+ # Build and deploy to maven local
+ - cd submodules/MaterialProviders
+ - git checkout $BRANCH
+ - cd TestVectorsAwsCryptographicMaterialProviders/
+ # This works because `node` is installed by default on GHA runners
+ - CORES=$(node -e 'console.log(os.cpus().length)')
+ - make build_java CORES=$CORES
+ - ./runtimes/java/gradlew -p runtimes/java publishMavenLocalPublicationToMavenLocal
+ - cd $CODEBUILD_SRC_DIR
+
build:
commands:
- VERSION_HASH="$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)-$CODEBUILD_RESOLVED_SOURCE_VERSION-$GITHUB_EVENT_NAME"
diff --git a/codebuild/ci/vectors-ci.yml b/codebuild/ci/vectors-ci.yml
index ae4ff9e1..0ff26ab7 100644
--- a/codebuild/ci/vectors-ci.yml
+++ b/codebuild/ci/vectors-ci.yml
@@ -4,6 +4,35 @@ phases:
install:
runtime-versions:
java: $JAVA_ENV_VERSION
+ commands:
+ - git submodule update --init submodules/MaterialProviders
+ # Get Dafny
+ - curl https://github.com/dafny-lang/dafny/releases/download/v4.2.0/dafny-4.2.0-x64-ubuntu-20.04.zip -L -o dafny.zip
+ - unzip -qq dafny.zip && rm dafny.zip
+ - export PATH="$PWD/dafny:$PATH"
+ # Get Gradle 7.6
+ - curl https://services.gradle.org/distributions/gradle-7.6-all.zip -L -o gradle.zip
+ - unzip -qq gradle.zip && rm gradle.zip
+ - export PATH="$PWD/gradle-7.6/bin:$PATH"
+ pre_build:
+ commands:
+ # Assume Role to access non-prod resources
+ - TMP_ROLE=$(aws sts assume-role --role-arn "arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Java-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')
+ - aws sts get-caller-identity
+
+ # Build and deploy TestVectors to maven local
+ - cd submodules/MaterialProviders
+ - git checkout $BRANCH
+ - cd TestVectorsAwsCryptographicMaterialProviders/
+ # This works because `node` is installed by default on GHA runners
+ - CORES=$(node -e 'console.log(os.cpus().length)')
+ - make build_java CORES=$CORES
+ - ./runtimes/java/gradlew -p runtimes/java publishMavenLocalPublicationToMavenLocal
+ - cd $CODEBUILD_SRC_DIR
build:
commands:
- mvn install -T 8 -Dgpg.skip=true -ntp "-DtestVectorZip=file://$CODEBUILD_SRC_DIR/src/test/resources/aws-encryption-sdk-test-vectors/vectors/awses-decrypt/python-2.3.0.zip"
diff --git a/codebuild/ci/vectors-generator.yml b/codebuild/ci/vectors-generator.yml
new file mode 100644
index 00000000..f219a55c
--- /dev/null
+++ b/codebuild/ci/vectors-generator.yml
@@ -0,0 +1,53 @@
+version: 0.2
+
+phases:
+ install:
+ runtime-versions:
+ java: $JAVA_ENV_VERSION
+ commands:
+ - n 16
+ # Install the Javascript ESDK run test vectors
+ - npm install -g @aws-crypto/integration-node
+
+ - git submodule update --init submodules/MaterialProviders
+ # Get Dafny
+ - curl https://github.com/dafny-lang/dafny/releases/download/v4.2.0/dafny-4.2.0-x64-ubuntu-20.04.zip -L -o dafny.zip
+ - unzip -qq dafny.zip && rm dafny.zip
+ - export PATH="$PWD/dafny:$PATH"
+ # Get Gradle 7.6
+ - curl https://services.gradle.org/distributions/gradle-7.6-all.zip -L -o gradle.zip
+ - unzip -qq gradle.zip && rm gradle.zip
+ - export PATH="$PWD/gradle-7.6/bin:$PATH"
+ pre_build:
+ commands:
+ # Assume Role to access non-prod resources
+ - TMP_ROLE=$(aws sts assume-role --role-arn "arn:aws:iam::370957321024:role/GitHub-CI-Public-ESDK-Java-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')
+ - aws sts get-caller-identity
+
+ # Build and deploy to maven local
+ - cd submodules/MaterialProviders
+ - git checkout $BRANCH
+ - cd TestVectorsAwsCryptographicMaterialProviders/
+ # This works because `node` is installed by default on GHA runners
+ - CORES=$(node -e 'console.log(os.cpus().length)')
+ - make build_java CORES=$CORES
+ - ./runtimes/java/gradlew -p runtimes/java publishMavenLocalPublicationToMavenLocal
+ - cd $CODEBUILD_SRC_DIR
+ build:
+ commands:
+ - export VECTORS_ZIP="$CODEBUILD_SRC_DIR/generated_vectors.zip"
+ # Generate test vectors by encrypting with Keyrings
+ # Ignore Testing coverage requirement by skipping jacoco
+ - mvn -B -ntp install -Dgpg.skip=true -Djacoco.skip=true "-Dtest=TestVectorGenerator" "-DzipFilePath=$VECTORS_ZIP" "-DkeysManifest=$CODEBUILD_SRC_DIR/src/test/resources/keys.json"
+ # Decrypt generated vectors with Javascript ESDK
+ - integration-node decrypt -v $VECTORS_ZIP
+
+ - rm $VECTORS_ZIP
+ # Generate test vectors by encrypting with MasterKeys
+ - mvn -B -ntp install -Dgpg.skip=true -Djacoco.skip=true -Dmasterkey=true "-Dtest=TestVectorGenerator" "-DzipFilePath=$VECTORS_ZIP" "-DkeysManifest=$CODEBUILD_SRC_DIR/src/test/resources/keys.json"
+ # Decrypt generated vectors with Javascript ESDK
+ - integration-node decrypt -v $VECTORS_ZIP
diff --git a/codebuild/release/release-prod.yml b/codebuild/release/release-prod.yml
index 1e519f39..05c98ce9 100644
--- a/codebuild/release/release-prod.yml
+++ b/codebuild/release/release-prod.yml
@@ -16,12 +16,31 @@ phases:
install:
runtime-versions:
java: corretto11
+ commands:
+ - git submodule update --init submodules/MaterialProviders
+ # Get Dafny
+ - curl https://github.com/dafny-lang/dafny/releases/download/v4.2.0/dafny-4.2.0-x64-ubuntu-20.04.zip -L -o dafny.zip
+ - unzip -qq dafny.zip && rm dafny.zip
+ - export PATH="$PWD/dafny:$PATH"
+ # Get Gradle 7.6
+ - curl https://services.gradle.org/distributions/gradle-7.6-all.zip -L -o gradle.zip
+ - unzip -qq gradle.zip && rm gradle.zip
+ - export PATH="$PWD/gradle-7.6/bin:$PATH"
pre_build:
commands:
- git checkout $BRANCH
- export SETTINGS_FILE=$(pwd)/codebuild/release/settings.xml
- aws secretsmanager get-secret-value --region us-west-2 --secret-id Maven-GPG-Keys-Release --query SecretBinary --output text | base64 -d > ~/mvn_gpg.tgz
- tar -xvf ~/mvn_gpg.tgz -C ~
+ # Build and deploy TestVectorsAwsCryptographicMaterialProviders to maven local
+ - cd submodules/MaterialProviders
+ - git checkout $BRANCH
+ - cd TestVectorsAwsCryptographicMaterialProviders/
+ # This works because `node` is installed by default on GHA runners
+ - CORES=$(node -e 'console.log(os.cpus().length)')
+ - make build_java CORES=$CORES
+ - ./runtimes/java/gradlew -p runtimes/java publishMavenLocalPublicationToMavenLocal
+ - cd $CODEBUILD_SRC_DIR
build:
commands:
- |
diff --git a/codebuild/release/release-staging.yml b/codebuild/release/release-staging.yml
index e9bb1142..c53cf1b6 100644
--- a/codebuild/release/release-staging.yml
+++ b/codebuild/release/release-staging.yml
@@ -18,6 +18,16 @@ phases:
install:
runtime-versions:
java: corretto11
+ commands:
+ - git submodule update --init submodules/MaterialProviders
+ # Get Dafny
+ - curl https://github.com/dafny-lang/dafny/releases/download/v4.2.0/dafny-4.2.0-x64-ubuntu-20.04.zip -L -o dafny.zip
+ - unzip -qq dafny.zip && rm dafny.zip
+ - export PATH="$PWD/dafny:$PATH"
+ # Get Gradle 7.6
+ - curl https://services.gradle.org/distributions/gradle-7.6-all.zip -L -o gradle.zip
+ - unzip -qq gradle.zip && rm gradle.zip
+ - export PATH="$PWD/gradle-7.6/bin:$PATH"
pre_build:
commands:
- export SETTINGS_FILE=$(pwd)/codebuild/release/settings.xml
@@ -25,6 +35,15 @@ phases:
- export CODEARTIFACT_REPO_URL=https://${DOMAIN}-${ACCOUNT}.d.codeartifact.${REGION}.amazonaws.com/maven/${REPOSITORY}
- aws secretsmanager get-secret-value --region us-west-2 --secret-id Maven-GPG-Keys-Release --query SecretBinary --output text | base64 -d > ~/mvn_gpg.tgz
- tar -xvf ~/mvn_gpg.tgz -C ~
+ # Build and deploy TestVectorsAwsCryptographicMaterialProviders to maven local
+ - cd submodules/MaterialProviders
+ - git checkout $BRANCH
+ - cd TestVectorsAwsCryptographicMaterialProviders/
+ # This works because `node` is installed by default on GHA runners
+ - CORES=$(node -e 'console.log(os.cpus().length)')
+ - make build_java CORES=$CORES
+ - ./runtimes/java/gradlew -p runtimes/java publishMavenLocalPublicationToMavenLocal
+ - cd $CODEBUILD_SRC_DIR
build:
commands:
- VERSION_HASH="$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)-$CODEBUILD_RESOLVED_SOURCE_VERSION"
diff --git a/compliance_exceptions/aws-kms-mrk-aware-multi-keyrings.java b/compliance_exceptions/aws-kms-mrk-aware-multi-keyrings.java
deleted file mode 100644
index e40f72c6..00000000
--- a/compliance_exceptions/aws-kms-mrk-aware-multi-keyrings.java
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-
-// The AWS Encryption SDK - Java does not implement
-// any of the Keyring interface at this time.
-
-//= compliance/framework/aws-kms/aws-kms-mrk-aware-multi-keyrings.txt#2.5
-//= type=exception
-//# The caller MUST provide:
-//#
-//# * A set of Region strings
-//#
-//# * An optional discovery filter that is an AWS partition and a set of
-//# AWS accounts
-//#
-//# * An optional method that can take a region string and return an AWS
-//# KMS client e.g. a regional client supplier
-//#
-//# * An optional list of AWS KMS grant tokens
-//#
-//# If an empty set of Region is provided this function MUST fail. If
-//# any element of the set of regions is null or an empty string this
-//# function MUST fail. If a regional client supplier is not passed,
-//# then a default MUST be created that takes a region string and
-//# generates a default AWS SDK client for the given region.
-//#
-//# A set of AWS KMS clients MUST be created by calling regional client
-//# supplier for each region in the input set of regions.
-//#
-//# Then a set of AWS KMS MRK Aware Symmetric Region Discovery Keyring
-//# (aws-kms-mrk-aware-symmetric-region-discovery-keyring.md) MUST be
-//# created for each AWS KMS client by initializing each keyring with
-//#
-//# * The AWS KMS client
-//#
-//# * The input discovery filter
-//#
-//# * The input AWS KMS grant tokens
-//#
-//# Then a Multi-Keyring (../multi-keyring.md#inputs) MUST be initialize
-//# by using this set of discovery keyrings as the child keyrings
-//# (../multi-keyring.md#child-keyrings). This Multi-Keyring MUST be
-//# this functions output.
-
-//= compliance/framework/aws-kms/aws-kms-mrk-aware-multi-keyrings.txt#2.6
-//= type=exception
-//# The caller MUST provide:
-//#
-//# * An optional AWS KMS key identifiers to use as the generator.
-//#
-//# * An optional set of AWS KMS key identifiers to us as child
-//# keyrings.
-//#
-//# * An optional method that can take a region string and return an AWS
-//# KMS client e.g. a regional client supplier
-//#
-//# * An optional list of AWS KMS grant tokens
-//#
-//# If any of the AWS KMS key identifiers is null or an empty string this
-//# function MUST fail. At least one non-null or non-empty string AWS
-//# KMS key identifiers exists in the input this function MUST fail. All
-//# AWS KMS identifiers are passed to Assert AWS KMS MRK are unique (aws-
-//# kms-mrk-are-unique.md#Implementation) and the function MUST return
-//# success otherwise this MUST fail. If a regional client supplier is
-//# not passed, then a default MUST be created that takes a region string
-//# and generates a default AWS SDK client for the given region.
-//#
-//# If there is a generator input then the generator keyring MUST be a
-//# AWS KMS MRK Aware Symmetric Keyring (aws-kms-mrk-aware-symmetric-
-//# keyring.md) initialized with
-//#
-//# * The generator input.
-//#
-//# * The AWS KMS client that MUST be created by the regional client
-//# supplier when called with the region part of the generator ARN or
-//# a signal for the AWS SDK to select the default region.
-//#
-//# * The input list of AWS KMS grant tokens
-//#
-//# If there is a set of child identifiers then a set of AWS KMS MRK
-//# Aware Symmetric Keyring (aws-kms-mrk-aware-symmetric-keyring.md) MUST
-//# be created for each AWS KMS key identifier by initialized each
-//# keyring with
-//#
-//# * AWS KMS key identifier.
-//#
-//# * The AWS KMS client that MUST be created by the regional client
-//# supplier when called with the region part of the AWS KMS key
-//# identifier or a signal for the AWS SDK to select the default
-//# region.
-//#
-//# * The input list of AWS KMS grant tokens
-//#
-//# NOTE: The AWS Encryption SDK SHOULD NOT attempt to evaluate its own
-//# default region.
-//#
-//# Then a Multi-Keyring (../multi-keyring.md#inputs) MUST be initialize
-//# by using this generator keyring as the generator keyring (../multi-
-//# keyring.md#generator-keyring) and this set of child keyrings as the
-//# child keyrings (../multi-keyring.md#child-keyrings). This Multi-
-//# Keyring MUST be this functions output.
-
-
-
diff --git a/compliance_exceptions/aws-kms-mrk-aware-symmetric-keyring.java b/compliance_exceptions/aws-kms-mrk-aware-symmetric-keyring.java
deleted file mode 100644
index e4937758..00000000
--- a/compliance_exceptions/aws-kms-mrk-aware-symmetric-keyring.java
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-
-// The AWS Encryption SDK - Java does not implement
-// any of the Keyring interface at this time.
-
-//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.5
-//= type=exception
-//# MUST implement the AWS Encryption SDK Keyring interface (../keyring-
-//# interface.md#interface)
-
-//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.6
-//= type=exception
-//# On initialization the caller MUST provide:
-//#
-//# * An AWS KMS key identifier
-//#
-//# * An AWS KMS SDK client
-//#
-//# * An optional list of Grant Tokens
-//#
-//# The AWS KMS key identifier MUST NOT be null or empty. The AWS KMS
-//# key identifier MUST be a valid identifier (aws-kms-key-arn.md#a-
-//# valid-aws-kms-identifier). The AWS KMS SDK client MUST NOT be null.
-
-//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.7
-//= type=exception
-//# OnEncrypt MUST take encryption materials (structures.md#encryption-
-//# materials) as input.
-//#
-//# If the input encryption materials (structures.md#encryption-
-//# materials) do not contain a plaintext data key OnEncrypt MUST attempt
-//# to generate a new plaintext data key by calling AWS KMS
-//# GenerateDataKey (https://docs.aws.amazon.com/kms/latest/APIReference/
-//# API_GenerateDataKey.html).
-//#
-//# If the keyring calls AWS KMS GenerateDataKeys, it MUST use the
-//# configured AWS KMS client to make the call. The keyring MUST call
-//# AWS KMS GenerateDataKeys with a request constructed as follows:
-//#
-//# * "KeyId": this keyring's KMS key identifier.
-//#
-//# * "NumberOfBytes": the key derivation input length (algorithm-
-//# suites.md#key-derivation-input-length) specified by the algorithm
-//# suite (algorithm-suites.md) included in the input encryption
-//# materials (structures.md#encryption-materials).
-//#
-//# * "EncryptionContext": the encryption context
-//# (structures.md#encryption-context) included in the input
-//# encryption materials (structures.md#encryption-materials).
-//#
-//# * "GrantTokens": this keyring's grant tokens
-//# (https://docs.aws.amazon.com/kms/latest/developerguide/
-//# concepts.html#grant_token)
-//#
-//# If the call to AWS KMS GenerateDataKey
-//# (https://docs.aws.amazon.com/kms/latest/APIReference/
-//# API_GenerateDataKey.html) does not succeed, OnEncrypt MUST NOT modify
-//# the encryption materials (structures.md#encryption-materials) and
-//# MUST fail.
-//#
-//# If the Generate Data Key call succeeds, OnEncrypt MUST verify that
-//# the response "Plaintext" length matches the specification of the
-//# algorithm suite (algorithm-suites.md)'s Key Derivation Input Length
-//# field. The Generate Data Key response's "KeyId" MUST be A valid AWS
-//# KMS key ARN (aws-kms-key-arn.md#identifying-an-aws-kms-multi-region-
-//# key). If verified, OnEncrypt MUST do the following with the response
-//# from AWS KMS GenerateDataKey
-//# (https://docs.aws.amazon.com/kms/latest/APIReference/
-//# API_GenerateDataKey.html):
-//#
-//# * set the plaintext data key on the encryption materials
-//# (structures.md#encryption-materials) as the response "Plaintext".
-//#
-//# * append a new encrypted data key (structures.md#encrypted-data-key)
-//# to the encrypted data key list in the encryption materials
-//# (structures.md#encryption-materials), constructed as follows:
-//#
-//# - the ciphertext (structures.md#ciphertext) is the response
-//# "CiphertextBlob".
-//#
-//# - the key provider id (structures.md#key-provider-id) is "aws-
-//# kms".
-//#
-//# - the key provider information (structures.md#key-provider-
-//# information) is the response "KeyId".
-//#
-//# * OnEncrypt MUST output the modified encryption materials
-//# (structures.md#encryption-materials)
-//#
-//# Given a plaintext data key in the encryption materials
-//# (structures.md#encryption-materials), OnEncrypt MUST attempt to
-//# encrypt the plaintext data key using the configured AWS KMS key
-//# identifier.
-//#
-//# The keyring MUST call AWS KMS Encrypt
-//# (https://docs.aws.amazon.com/kms/latest/APIReference/
-//# API_Encrypt.html) using the configured AWS KMS client. The keyring
-//# MUST AWS KMS Encrypt call with a request constructed as follows:
-//#
-//# * "KeyId": The configured AWS KMS key identifier.
-//#
-//# * "PlaintextDataKey": the plaintext data key in the encryption
-//# materials (structures.md#encryption-materials).
-//#
-//# * "EncryptionContext": the encryption context
-//# (structures.md#encryption-context) included in the input
-//# encryption materials (structures.md#encryption-materials).
-//#
-//# * "GrantTokens": this keyring's grant tokens
-//# (https://docs.aws.amazon.com/kms/latest/developerguide/
-//# concepts.html#grant_token)
-//#
-//# If the call to AWS KMS Encrypt
-//# (https://docs.aws.amazon.com/kms/latest/APIReference/
-//# API_Encrypt.html) does not succeed, OnEncrypt MUST fail.
-//#
-//# If the Encrypt call succeeds The response's "KeyId" MUST be A valid
-//# AWS KMS key ARN (aws-kms-key-arn.md#identifying-an-aws-kms-multi-
-//# region-key). If verified, OnEncrypt MUST do the following with the
-//# response from AWS KMS Encrypt
-//# (https://docs.aws.amazon.com/kms/latest/APIReference/
-//# API_Encrypt.html):
-//#
-//# * append a new encrypted data key (structures.md#encrypted-data-key)
-//# to the encrypted data key list in the encryption materials
-//# (structures.md#encryption-materials), constructed as follows:
-//#
-//# - The ciphertext (structures.md#ciphertext) is the response
-//# "CiphertextBlob".
-//#
-//# - The key provider id (structures.md#key-provider-id) is "aws-
-//# kms".
-//#
-//# - The key provider information (structures.md#key-provider-
-//# information) is the response "KeyId". Note that the "KeyId" in
-//# the response is always in key ARN format.
-//#
-//# If all Encrypt calls succeed, OnEncrypt MUST output the modified
-//# encryption materials (structures.md#encryption-materials).
-
-//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.8
-//= type=exception
-//# OnDecrypt MUST take decryption materials (structures.md#decryption-
-//# materials) and a list of encrypted data keys
-//# (structures.md#encrypted-data-key) as input.
-//#
-//# If the decryption materials (structures.md#decryption-materials)
-//# already contained a valid plaintext data key OnDecrypt MUST
-//# immediately return the unmodified decryption materials
-//# (structures.md#decryption-materials).
-//#
-//# The set of encrypted data keys MUST first be filtered to match this
-//# keyring's configuration. For the encrypted data key to match
-//#
-//# * Its provider ID MUST exactly match the value "aws-kms".
-//#
-//# * The provider info MUST be a valid AWS KMS ARN (aws-kms-key-
-//# arn.md#a-valid-aws-kms-arn) with a resource type of "key" or
-//# OnDecrypt MUST fail.
-//#
-//# * The the function AWS KMS MRK Match for Decrypt (aws-kms-mrk-match-
-//# for-decrypt.md#implementation) called with the configured AWS KMS
-//# key identifier and the provider info MUST return "true".
-//#
-//# For each encrypted data key in the filtered set, one at a time, the
-//# OnDecrypt MUST attempt to decrypt the data key. If this attempt
-//# results in an error, then these errors MUST be collected.
-//#
-//# To attempt to decrypt a particular encrypted data key
-//# (structures.md#encrypted-data-key), OnDecrypt MUST call AWS KMS
-//# Decrypt (https://docs.aws.amazon.com/kms/latest/APIReference/
-//# API_Decrypt.html) with the configured AWS KMS client.
-//#
-//# When calling AWS KMS Decrypt
-//# (https://docs.aws.amazon.com/kms/latest/APIReference/
-//# API_Decrypt.html), the keyring MUST call with a request constructed
-//# as follows:
-//#
-//# * "KeyId": The configured AWS KMS key identifier.
-//#
-//# * "CiphertextBlob": the encrypted data key ciphertext
-//# (structures.md#ciphertext).
-//#
-//# * "EncryptionContext": the encryption context
-//# (structures.md#encryption-context) included in the input
-//# decryption materials (structures.md#decryption-materials).
-//#
-//# * "GrantTokens": this keyring's grant tokens
-//# (https://docs.aws.amazon.com/kms/latest/developerguide/
-//# concepts.html#grant_token)
-//#
-//# If the call to AWS KMS Decrypt
-//# (https://docs.aws.amazon.com/kms/latest/APIReference/
-//# API_Decrypt.html) succeeds OnDecrypt verifies
-//#
-//# * The "KeyId" field in the response MUST equal the configured AWS
-//# KMS key identifier.
-//#
-//# * The length of the response's "Plaintext" MUST equal the key
-//# derivation input length (algorithm-suites.md#key-derivation-input-
-//# length) specified by the algorithm suite (algorithm-suites.md)
-//# included in the input decryption materials
-//# (structures.md#decryption-materials).
-//#
-//# If the response does not satisfies these requirements then an error
-//# MUST be collected and the next encrypted data key in the filtered set
-//# MUST be attempted.
-//#
-//# If the response does satisfies these requirements then OnDecrypt MUST
-//# do the following with the response:
-//#
-//# * set the plaintext data key on the decryption materials
-//# (structures.md#decryption-materials) as the response "Plaintext".
-//#
-//# * immediately return the modified decryption materials
-//# (structures.md#decryption-materials).
-//#
-//# If OnDecrypt fails to successfully decrypt any encrypted data key
-//# (structures.md#encrypted-data-key), then it MUST yield an error that
-//# includes all the collected errors.
-
-
-
-
-
diff --git a/compliance_exceptions/aws-kms-mrk-aware-symmetric-region-discovery-keyring.java b/compliance_exceptions/aws-kms-mrk-aware-symmetric-region-discovery-keyring.java
deleted file mode 100644
index f57c07fe..00000000
--- a/compliance_exceptions/aws-kms-mrk-aware-symmetric-region-discovery-keyring.java
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-
-// The AWS Encryption SDK - Java does not implement
-// any of the Keyring interface at this time.
-
-//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-keyring.txt#2.5
-//= type=exception
-//# MUST implement that AWS Encryption SDK Keyring interface (../keyring-
-//# interface.md#interface)
-
-//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-keyring.txt#2.6
-//= type=exception
-//# On initialization the caller MUST provide:
-//#
-//# * An AWS KMS client
-//#
-//# * An optional discovery filter that is an AWS partition and a set of
-//# AWS accounts
-//#
-//# * An optional list of AWS KMS grant tokens
-//#
-//# The keyring MUST know what Region the AWS KMS client is in. It
-//# SHOULD obtain this information directly from the client as opposed to
-//# having an additional parameter. However if it can not, then it MUST
-//# NOT create the client itself. It SHOULD have a Region parameter and
-//# SHOULD try to identify mismatched configurations. i.e. The client is
-//# in Region A and the Region parameter is B.
-
-//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-keyring.txt#2.7
-//= type=exception
-//# This function MUST fail.
-
-//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-keyring.txt#2.8
-//= type=exception
-//# OnDecrypt MUST take decryption materials (structures.md#decryption-
-//# materials) and a list of encrypted data keys
-//# (structures.md#encrypted-data-key) as input.
-//#
-//# If the decryption materials (structures.md#decryption-materials)
-//# already contained a valid plaintext data key OnDecrypt MUST
-//# immediately return the unmodified decryption materials
-//# (structures.md#decryption-materials).
-//#
-//# The set of encrypted data keys MUST first be filtered to match this
-//# keyring's configuration. For the encrypted data key to match
-//#
-//# * Its provider ID MUST exactly match the value "aws-kms".
-//#
-//# * The provider info MUST be a valid AWS KMS ARN (aws-kms-key-
-//# arn.md#a-valid-aws-kms-arn) with a resource type of "key" or
-//# OnDecrypt MUST fail.
-//#
-//# * If a discovery filter is configured, its partition and the
-//# provider info partition MUST match.
-//#
-//# * If a discovery filter is configured, its set of accounts MUST
-//# contain the provider info account.
-//#
-//# * If the provider info is not identified as a multi-Region key (aws-
-//# kms-key-arn.md#identifying-an-aws-kms-multi-region-key), then the
-//# provider info's Region MUST match the AWS KMS client region.
-//#
-//# For each encrypted data key in the filtered set, one at a time, the
-//# OnDecrypt MUST attempt to decrypt the data key. If this attempt
-//# results in an error, then these errors are collected.
-//#
-//# To attempt to decrypt a particular encrypted data key
-//# (structures.md#encrypted-data-key), OnDecrypt MUST call AWS KMS
-//# Decrypt (https://docs.aws.amazon.com/kms/latest/APIReference/
-//# API_Decrypt.html) with the configured AWS KMS client.
-//#
-//# When calling AWS KMS Decrypt
-//# (https://docs.aws.amazon.com/kms/latest/APIReference/
-//# API_Decrypt.html), the keyring MUST call with a request constructed
-//# as follows:
-//#
-//# * "KeyId": If the provider info's resource type is "key" and its
-//# resource is a multi-Region key then a new ARN MUST be created
-//# where the region part MUST equal the AWS KMS client region and
-//# every other part MUST equal the provider info. Otherwise it MUST
-//# be the provider info.
-//#
-//# * "CiphertextBlob": The encrypted data key ciphertext
-//# (structures.md#ciphertext).
-//#
-//# * "EncryptionContext": The encryption context
-//# (structures.md#encryption-context) included in the input
-//# decryption materials (structures.md#decryption-materials).
-//#
-//# * "GrantTokens": this keyring's grant tokens
-//# (https://docs.aws.amazon.com/kms/latest/developerguide/
-//# concepts.html#grant_token)
-//#
-//# If the call to AWS KMS Decrypt
-//# (https://docs.aws.amazon.com/kms/latest/APIReference/
-//# API_Decrypt.html) succeeds OnDecrypt verifies
-//#
-//# * The "KeyId" field in the response MUST equal the requested "KeyId"
-//#
-//# * The length of the response's "Plaintext" MUST equal the key
-//# derivation input length (algorithm-suites.md#key-derivation-input-
-//# length) specified by the algorithm suite (algorithm-suites.md)
-//# included in the input decryption materials
-//# (structures.md#decryption-materials).
-//#
-//# If the response does not satisfies these requirements then an error
-//# is collected and the next encrypted data key in the filtered set MUST
-//# be attempted.
-//#
-//# Since the response does satisfies these requirements then OnDecrypt
-//# MUST do the following with the response:
-//#
-//# * set the plaintext data key on the decryption materials
-//# (structures.md#decryption-materials) as the response "Plaintext".
-//#
-//# * immediately return the modified decryption materials
-//# (structures.md#decryption-materials).
-//#
-//# If OnDecrypt fails to successfully decrypt any encrypted data key
-//# (structures.md#encrypted-data-key), then it MUST yield an error that
-//# includes all collected errors.
-
-
-
diff --git a/pom.xml b/pom.xml
index 22e5d207..01d41440 100644
--- a/pom.xml
+++ b/pom.xml
@@ -62,8 +62,37 @@
Arguments: + * + *
Arguments: + * + *
Arguments: + * + *
Arguments: + * + *
Arguments: + * + *
You might use AWS Key Management Service (AWS KMS) for most encryption and decryption + * operations, but still want the option of decrypting your data offline independently of AWS KMS. + * This sample demonstrates one way to do this. + * + *
The sample encrypts data under both an AWS KMS customer master key (CMK) and an "escrowed" RSA + * key pair so that either key alone can decrypt it. You might commonly use the AWS KMS CMK for + * decryption. However, at any time, you can use the private RSA key to decrypt the ciphertext + * independent of AWS KMS. + * + *
This sample uses the RawRsaKeyring to generate a RSA public-private key pair and saves the key + * pair in memory. In practice, you would store the private key in a secure offline location, such + * as an offline HSM, and distribute the public key to your development team. + */ +public class EscrowedEncryptKeyringExample { + private static ByteBuffer publicEscrowKey; + private static ByteBuffer privateEscrowKey; + + public static void main(final String[] args) throws Exception { + // This sample generates a new random key for each operation. + // In practice, you would distribute the public key and save the private key in secure + // storage. + generateEscrowKeyPair(); + + final String kmsArn = args[0]; + final String fileName = args[1]; + + standardEncrypt(kmsArn, fileName); + standardDecrypt(kmsArn, fileName); + + escrowDecrypt(fileName); + } + + private static void standardEncrypt(final String kmsArn, final String fileName) throws Exception { + // Encrypt with the KMS CMK and the escrowed public key + // 1. Instantiate the SDK + // This builds the AwsCrypto client with the RequireEncryptRequireDecrypt commitment policy, + // which enforces that this client only encrypts using committing algorithm suites and enforces + // that this client will only decrypt encrypted messages that were created with a committing + // algorithm suite. + // This is the default commitment policy if you build the client with + // `AwsCrypto.builder().build()` + // or `AwsCrypto.standard()`. + final AwsCrypto crypto = + AwsCrypto.builder() + .withCommitmentPolicy(CommitmentPolicy.RequireEncryptRequireDecrypt) + .build(); + + // 2. Create the AWS KMS keyring. + // We create a multi keyring, as this interface creates the KMS client for us automatically. + final MaterialProviders matProv = + MaterialProviders.builder() + .MaterialProvidersConfig(MaterialProvidersConfig.builder().build()) + .build(); + final CreateAwsKmsMultiKeyringInput keyringInput = + CreateAwsKmsMultiKeyringInput.builder().generator(kmsArn).build(); + final IKeyring kmsKeyring = matProv.CreateAwsKmsMultiKeyring(keyringInput); + + // 3. Create the Raw Rsa Keyring with Public Key. + final CreateRawRsaKeyringInput encryptingKeyringInput = + CreateRawRsaKeyringInput.builder() + .keyName("Escrow") + .keyNamespace("Escrow") + .paddingScheme(PaddingScheme.OAEP_SHA512_MGF1) + .publicKey(publicEscrowKey) + .build(); + IKeyring rsaPublicKeyring = matProv.CreateRawRsaKeyring(encryptingKeyringInput); + + // 4. Create the multi-keyring. + final CreateMultiKeyringInput createMultiKeyringInput = + CreateMultiKeyringInput.builder() + .generator(kmsKeyring) + .childKeyrings(Collections.singletonList(rsaPublicKeyring)) + .build(); + IKeyring multiKeyring = matProv.CreateMultiKeyring(createMultiKeyringInput); + + // 5. Encrypt the file + // To simplify the code, we omit the encryption context. Production code should always + // use an encryption context. For an example, see the other SDK samples. + final FileInputStream in = new FileInputStream(fileName); + final FileOutputStream out = new FileOutputStream(fileName + ".encrypted"); + final CryptoOutputStream> encryptingStream = crypto.createEncryptingStream(multiKeyring, out); + + IOUtils.copy(in, encryptingStream); + in.close(); + encryptingStream.close(); + } + + private static void standardDecrypt(final String kmsArn, final String fileName) throws Exception { + // Decrypt with the AWS KMS CMK and the escrow public key. You can use a combined provider, + // as shown here, or just the AWS KMS master key provider. + + // 1. Instantiate the SDK. + // This builds the AwsCrypto client with the RequireEncryptRequireDecrypt commitment policy, + // which enforces that this client only encrypts using committing algorithm suites and enforces + // that this client will only decrypt encrypted messages that were created with a committing + // algorithm suite. + // This is the default commitment policy if you build the client with + // `AwsCrypto.builder().build()` + // or `AwsCrypto.standard()`. + final AwsCrypto crypto = + AwsCrypto.builder() + .withCommitmentPolicy(CommitmentPolicy.RequireEncryptRequireDecrypt) + .build(); + + // 2. Create the AWS KMS keyring. + // We create a multi keyring, as this interface creates the KMS client for us automatically. + final MaterialProviders matProv = + MaterialProviders.builder() + .MaterialProvidersConfig(MaterialProvidersConfig.builder().build()) + .build(); + final CreateAwsKmsMultiKeyringInput keyringInput = + CreateAwsKmsMultiKeyringInput.builder().generator(kmsArn).build(); + IKeyring kmsKeyring = matProv.CreateAwsKmsMultiKeyring(keyringInput); + + // 3. Create the Raw Rsa Keyring with Public Key. + final CreateRawRsaKeyringInput encryptingKeyringInput = + CreateRawRsaKeyringInput.builder() + .keyName("Escrow") + .keyNamespace("Escrow") + .paddingScheme(PaddingScheme.OAEP_SHA512_MGF1) + .publicKey(publicEscrowKey) + .build(); + IKeyring rsaPublicKeyring = matProv.CreateRawRsaKeyring(encryptingKeyringInput); + + // 4. Create the multi-keyring. + final CreateMultiKeyringInput createMultiKeyringInput = + CreateMultiKeyringInput.builder() + .generator(kmsKeyring) + .childKeyrings(Collections.singletonList(rsaPublicKeyring)) + .build(); + IKeyring multiKeyring = matProv.CreateMultiKeyring(createMultiKeyringInput); + + // 5. Decrypt the file + // To simplify the code, we omit the encryption context. Production code should always + // use an encryption context. For an example, see the other SDK samples. + final FileInputStream in = new FileInputStream(fileName + ".encrypted"); + final FileOutputStream out = new FileOutputStream(fileName + ".decrypted"); + // Since we are using a signing algorithm suite, we avoid streaming decryption directly to the + // output file, + // to ensure that the trailing signature is verified before writing any untrusted plaintext to + // disk. + final ByteArrayOutputStream plaintextBuffer = new ByteArrayOutputStream(); + final CryptoOutputStream> decryptingStream = + crypto.createDecryptingStream(multiKeyring, plaintextBuffer); + IOUtils.copy(in, decryptingStream); + in.close(); + decryptingStream.close(); + final ByteArrayInputStream plaintextReader = + new ByteArrayInputStream(plaintextBuffer.toByteArray()); + IOUtils.copy(plaintextReader, out); + out.close(); + } + + private static void escrowDecrypt(final String fileName) throws Exception { + // You can decrypt the stream using only the private key. + // This method does not call AWS KMS. + + // 1. Instantiate the SDK + final AwsCrypto crypto = AwsCrypto.standard(); + + // 2. Create the Raw Rsa Keyring with Private Key. + final MaterialProviders matProv = + MaterialProviders.builder() + .MaterialProvidersConfig(MaterialProvidersConfig.builder().build()) + .build(); + final CreateRawRsaKeyringInput encryptingKeyringInput = + CreateRawRsaKeyringInput.builder() + .keyName("Escrow") + .keyNamespace("Escrow") + .paddingScheme(PaddingScheme.OAEP_SHA512_MGF1) + .publicKey(publicEscrowKey) + .privateKey(privateEscrowKey) + .build(); + IKeyring escrowPrivateKeyring = matProv.CreateRawRsaKeyring(encryptingKeyringInput); + + // 3. Decrypt the file + // To simplify the code, we omit the encryption context. Production code should always + // use an encryption context. For an example, see the other SDK samples. + final FileInputStream in = new FileInputStream(fileName + ".encrypted"); + final FileOutputStream out = new FileOutputStream(fileName + ".deescrowed"); + final CryptoOutputStream> decryptingStream = + crypto.createDecryptingStream(escrowPrivateKeyring, out); + IOUtils.copy(in, decryptingStream); + in.close(); + decryptingStream.close(); + } + + private static void generateEscrowKeyPair() throws GeneralSecurityException { + final KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA"); + kg.initialize(4096); // Escrow keys should be very strong + final KeyPair keyPair = kg.generateKeyPair(); + publicEscrowKey = RawRsaKeyringExample.getPEMPublicKey(keyPair.getPublic()); + privateEscrowKey = RawRsaKeyringExample.getPEMPrivateKey(keyPair.getPrivate()); + } +} diff --git a/src/examples/java/com/amazonaws/crypto/examples/keyrings/FileStreamingKeyringExample.java b/src/examples/java/com/amazonaws/crypto/examples/keyrings/FileStreamingKeyringExample.java new file mode 100644 index 00000000..c35746cb --- /dev/null +++ b/src/examples/java/com/amazonaws/crypto/examples/keyrings/FileStreamingKeyringExample.java @@ -0,0 +1,124 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazonaws.crypto.examples.keyrings; + +import com.amazonaws.encryptionsdk.AwsCrypto; +import com.amazonaws.encryptionsdk.CommitmentPolicy; +import com.amazonaws.encryptionsdk.CryptoAlgorithm; +import com.amazonaws.encryptionsdk.CryptoInputStream; +import com.amazonaws.encryptionsdk.jce.JceMasterKey; +import com.amazonaws.util.IOUtils; +import software.amazon.cryptography.materialproviders.IKeyring; +import software.amazon.cryptography.materialproviders.MaterialProviders; +import software.amazon.cryptography.materialproviders.model.AesWrappingAlg; +import software.amazon.cryptography.materialproviders.model.CreateRawAesKeyringInput; +import software.amazon.cryptography.materialproviders.model.MaterialProvidersConfig; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.SecureRandom; +import java.util.Collections; +import java.util.Map; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +/** + * Encrypts and then decrypts a file under a random key. + * + *
Arguments: + * + *
This program demonstrates using a standard Java {@link SecretKey} object as a {@link IKeyring}
+ * to encrypt and decrypt streaming data.
+ */
+public class FileStreamingKeyringExample {
+ private static String srcFile;
+
+ public static void main(String[] args) throws IOException {
+ srcFile = args[0];
+
+ // In this example, we generate a random key. In practice,
+ // you would get a key from an existing store
+ SecretKey cryptoKey = retrieveEncryptionKey();
+
+ // Create a Raw Aes Keyring using the random key and an AES-GCM encryption algorithm
+ final MaterialProviders materialProviders =
+ MaterialProviders.builder()
+ .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
+ .build();
+ final CreateRawAesKeyringInput keyringInput =
+ CreateRawAesKeyringInput.builder()
+ .wrappingKey(ByteBuffer.wrap(cryptoKey.getEncoded()))
+ .keyNamespace("Example")
+ .keyName("RandomKey")
+ .wrappingAlg(AesWrappingAlg.ALG_AES128_GCM_IV12_TAG16)
+ .build();
+ final IKeyring keyring = materialProviders.CreateRawAesKeyring(keyringInput);
+
+ // Instantiate the SDK.
+ // This builds the AwsCrypto client with the RequireEncryptRequireDecrypt commitment policy,
+ // which enforces that this client only encrypts using committing algorithm suites and enforces
+ // that this client will only decrypt encrypted messages that were created with a committing
+ // algorithm suite.
+ // This is the default commitment policy if you build the client with
+ // `AwsCrypto.builder().build()`
+ // or `AwsCrypto.standard()`.
+ // This also chooses to encrypt with an algorithm suite that doesn't include signing for faster
+ // decryption,
+ // since this use case assumes that the contexts that encrypt and decrypt are equally trusted.
+ final AwsCrypto crypto =
+ AwsCrypto.builder()
+ .withCommitmentPolicy(CommitmentPolicy.RequireEncryptRequireDecrypt)
+ .withEncryptionAlgorithm(CryptoAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY)
+ .build();
+
+ // Create an encryption context to identify this ciphertext
+ Map Arguments:
+ *
+ * This example takes in an `aesKeyBytes` parameter. This parameter should be a ByteBuffer
+ * representing a 256-bit AES key. If this example is run through the class' main method, it will
+ * create a new key.
+ */
+public class MultiKeyringExample {
+
+ private static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8);
+
+ public static void main(final String[] args) {
+ final String keyArn = args[0];
+
+ // Generate a new AES key
+ ByteBuffer aesKeyBytes = generateAesKeyBytes();
+
+ encryptAndDecryptWithKeyring(keyArn, aesKeyBytes);
+ }
+
+ public static void encryptAndDecryptWithKeyring(String keyArn, ByteBuffer aesKeyBytes) {
+ // 1. Instantiate the SDK
+ // This builds the AwsCrypto client with the RequireEncryptRequireDecrypt commitment policy,
+ // which enforces that this client only encrypts using committing algorithm suites and enforces
+ // that this client will only decrypt encrypted messages that were created with a committing
+ // algorithm suite.
+ // This is the default commitment policy if you build the client with
+ // `AwsCrypto.builder().build()`
+ // or `AwsCrypto.standard()`.
+ final AwsCrypto crypto =
+ AwsCrypto.builder()
+ .withCommitmentPolicy(CommitmentPolicy.RequireEncryptRequireDecrypt)
+ .build();
+
+ // 2. Create the raw AES keyring.
+ final MaterialProviders matProv =
+ MaterialProviders.builder()
+ .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
+ .build();
+ final CreateRawAesKeyringInput createRawAesKeyringInput =
+ CreateRawAesKeyringInput.builder()
+ .keyName("my-aes-key-name")
+ .keyNamespace("my-key-namespace")
+ .wrappingKey(aesKeyBytes)
+ .wrappingAlg(AesWrappingAlg.ALG_AES256_GCM_IV12_TAG16)
+ .build();
+ IKeyring rawAesKeyring = matProv.CreateRawAesKeyring(createRawAesKeyringInput);
+
+ // 3. Create the AWS KMS keyring.
+ // We create a multi keyring, as this interface creates the KMS client for us automatically.
+ final CreateAwsKmsMultiKeyringInput kmsMultiKeyringInput =
+ CreateAwsKmsMultiKeyringInput.builder().generator(keyArn).build();
+ IKeyring kmsKeyring = matProv.CreateAwsKmsMultiKeyring(kmsMultiKeyringInput);
+
+ // 4. Create the multi-keyring.
+ // We will label the AWS KMS keyring as the generator and the raw AES keyring as the
+ // only child keyring.
+ // You must provide a generator keyring to encrypt data.
+ // You may provide additional child keyrings. Each child keyring will be able to
+ // decrypt data encrypted with the multi-keyring on its own. It does not need
+ // knowledge of any other child keyrings or the generator keyring to decrypt.
+ final CreateMultiKeyringInput createMultiKeyringInput =
+ CreateMultiKeyringInput.builder()
+ .generator(kmsKeyring)
+ .childKeyrings(Collections.singletonList(rawAesKeyring))
+ .build();
+ final IKeyring multiKeyring = matProv.CreateMultiKeyring(createMultiKeyringInput);
+
+ // 5. Create an encryption context
+ // Most encrypted data should have an associated encryption context
+ // to protect integrity. This sample uses placeholder values.
+ // For more information see:
+ // blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management
+ final Map Arguments:
+ *
+ * This example takes in an `aesKeyBytes` parameter. This parameter should be a ByteBuffer
+ * representing a 256-bit AES key. If this example is run through the class' main method, it will
+ * create a new key. In practice, users of this library should not randomly generate a key, and
+ * should instead retrieve an existing key from a secure key management system (e.g. an HSM).
+ */
+public class RawAesKeyringExample {
+
+ private static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8);
+
+ public static void main(final String[] args) {
+ // Generate a new AES key
+ ByteBuffer aesKeyBytes = generateAesKeyBytes();
+
+ encryptAndDecryptWithKeyring(aesKeyBytes);
+ }
+
+ public static void encryptAndDecryptWithKeyring(final ByteBuffer aesKeyBytes) {
+ // 1. Instantiate the SDK
+ // This builds the AwsCrypto client with the RequireEncryptRequireDecrypt commitment policy,
+ // which enforces that this client only encrypts using committing algorithm suites and enforces
+ // that this client will only decrypt encrypted messages that were created with a committing
+ // algorithm suite.
+ // This is the default commitment policy if you build the client with
+ // `AwsCrypto.builder().build()`
+ // or `AwsCrypto.standard()`.
+ final AwsCrypto crypto =
+ AwsCrypto.builder()
+ .withCommitmentPolicy(CommitmentPolicy.RequireEncryptRequireDecrypt)
+ .build();
+
+ // 2. Create the Raw Aes Keyring.
+ final CreateRawAesKeyringInput keyringInput =
+ CreateRawAesKeyringInput.builder()
+ .keyName("my-aes-key-name")
+ .keyNamespace("my-key-namespace")
+ .wrappingKey(aesKeyBytes)
+ .wrappingAlg(AesWrappingAlg.ALG_AES256_GCM_IV12_TAG16)
+ .build();
+ final MaterialProviders matProv =
+ MaterialProviders.builder()
+ .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
+ .build();
+ final IKeyring rawAesKeyring = matProv.CreateRawAesKeyring(keyringInput);
+
+ // 3. Create an encryption context
+ // Most encrypted data should have an associated encryption context
+ // to protect integrity. This sample uses placeholder values.
+ // For more information see:
+ // blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management
+ final Map This configuration should only be used as part of a migration from version 1.x to 2.x, or for
+ * advanced users with specialized requirements. We recommend that AWS Encryption SDK users use the
+ * default commitment policy whenever possible.
+ *
+ * Arguments:
+ *
+ * Arguments:
+ *
+ * Establishing a key hierarchy like this has two benefits:
+ *
+ * First, by caching the branch key material, and only calling KMS to re-establish authentication
+ * regularly according to your configured TTL, you limit how often you need to call KMS to protect
+ * your data. This is a performance security tradeoff, where your authentication, audit, and logging
+ * from KMS is no longer one-to-one with every encrypt or decrypt call. Additionally, KMS Cloudtrail
+ * cannot be used to distinguish Encrypt and Decrypt calls, and you cannot restrict who has
+ * Encryption rights from who has Decryption rights since they both ONLY need KMS:Decrypt. However,
+ * the benefit is that you no longer have to make a network call to KMS for every encrypt or
+ * decrypt.
+ *
+ * Second, this key hierarchy facilitates cryptographic isolation of a tenant's data in a
+ * multi-tenant data store. Each tenant can have a unique Branch Key, that is only used to protect
+ * the tenant's data. You can either statically configure a single branch key to ensure you are
+ * restricting access to a single tenant, or you can implement an interface that selects the Branch
+ * Key based on the Encryption Context.
+ *
+ * This example demonstrates configuring a Hierarchical Keyring with a Branch Key ID Supplier to
+ * encrypt and decrypt data for two separate tenants.
+ *
+ * This example requires access to the DDB Table where you are storing the Branch Keys. This
+ * table must be configured with the following primary key configuration: - Partition key is named
+ * "partition_key" with type (S) - Sort key is named "sort_key" with type (S)
+ *
+ * This example also requires using a KMS Key. You need the following access on this key: -
+ * GenerateDataKeyWithoutPlaintext - Decrypt
+ */
+public class AwsKmsHierarchicalKeyringExample {
+ private static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8);
+
+ public static void encryptAndDecryptWithKeyring(
+ String keyStoreTableName, String logicalKeyStoreName, String kmsKeyId) {
+ // Instantiate the SDK
+ // This builds the AwsCrypto client with the RequireEncryptRequireDecrypt commitment policy,
+ // which enforces that this client only encrypts using committing algorithm suites and enforces
+ // that this client will only decrypt encrypted messages that were created with a committing
+ // algorithm suite.
+ // This is the default commitment policy if you build the client with
+ // `AwsCrypto.builder().build()`
+ // or `AwsCrypto.standard()`.
+ final AwsCrypto crypto = AwsCrypto.builder().build();
+
+ // Configure your KeyStore resource.
+ // This SHOULD be the same configuration that you used
+ // to initially create and populate your KeyStore.
+ final KeyStore keystore =
+ KeyStore.builder()
+ .KeyStoreConfig(
+ KeyStoreConfig.builder()
+ .ddbClient(DynamoDbClient.create())
+ .ddbTableName(keyStoreTableName)
+ .logicalKeyStoreName(logicalKeyStoreName)
+ .kmsClient(KmsClient.create())
+ .kmsConfiguration(KMSConfiguration.builder().kmsKeyArn(kmsKeyId).build())
+ .build())
+ .build();
+
+ // Call CreateKey to create two new active branch keys
+ final String branchKeyIdA =
+ keystore.CreateKey(CreateKeyInput.builder().build()).branchKeyIdentifier();
+ final String branchKeyIdB =
+ keystore.CreateKey(CreateKeyInput.builder().build()).branchKeyIdentifier();
+
+ // Create a branch key supplier that maps the branch key id to a more readable format
+ final IBranchKeyIdSupplier branchKeyIdSupplier =
+ new ExampleBranchKeyIdSupplier(branchKeyIdA, branchKeyIdB);
+
+ // 4. Create the Hierarchical Keyring.
+ final MaterialProviders matProv =
+ MaterialProviders.builder()
+ .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
+ .build();
+ final CreateAwsKmsHierarchicalKeyringInput keyringInput =
+ CreateAwsKmsHierarchicalKeyringInput.builder()
+ .keyStore(keystore)
+ .branchKeyIdSupplier(branchKeyIdSupplier)
+ .ttlSeconds(600)
+ .cache(
+ CacheType.builder() // OPTIONAL
+ .Default(DefaultCache.builder().entryCapacity(100).build())
+ .build())
+ .build();
+ final IKeyring hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
+
+ // The Branch Key Id supplier uses the encryption context to determine which branch key id will
+ // be used to encrypt data.
+ // Create encryption context for TenantA
+ Map
* Configures a client with a specific commitment policy, then
diff --git a/src/examples/java/com/amazonaws/crypto/examples/SetEncryptionAlgorithmExample.java b/src/examples/java/com/amazonaws/crypto/examples/v2/SetEncryptionAlgorithmExample.java
similarity index 99%
rename from src/examples/java/com/amazonaws/crypto/examples/SetEncryptionAlgorithmExample.java
rename to src/examples/java/com/amazonaws/crypto/examples/v2/SetEncryptionAlgorithmExample.java
index b49d6bb9..7eb15d40 100644
--- a/src/examples/java/com/amazonaws/crypto/examples/SetEncryptionAlgorithmExample.java
+++ b/src/examples/java/com/amazonaws/crypto/examples/v2/SetEncryptionAlgorithmExample.java
@@ -1,7 +1,7 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
-package com.amazonaws.crypto.examples;
+package com.amazonaws.crypto.examples.v2;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
diff --git a/src/examples/java/com/amazonaws/crypto/examples/SimpleDataKeyCachingExample.java b/src/examples/java/com/amazonaws/crypto/examples/v2/SimpleDataKeyCachingExample.java
similarity index 98%
rename from src/examples/java/com/amazonaws/crypto/examples/SimpleDataKeyCachingExample.java
rename to src/examples/java/com/amazonaws/crypto/examples/v2/SimpleDataKeyCachingExample.java
index 633850a7..4437a010 100644
--- a/src/examples/java/com/amazonaws/crypto/examples/SimpleDataKeyCachingExample.java
+++ b/src/examples/java/com/amazonaws/crypto/examples/v2/SimpleDataKeyCachingExample.java
@@ -1,7 +1,7 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
-package com.amazonaws.crypto.examples;
+package com.amazonaws.crypto.examples.v2;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
diff --git a/src/main/java/com/amazonaws/encryptionsdk/AwsCrypto.java b/src/main/java/com/amazonaws/encryptionsdk/AwsCrypto.java
index 5268935b..701af85e 100644
--- a/src/main/java/com/amazonaws/encryptionsdk/AwsCrypto.java
+++ b/src/main/java/com/amazonaws/encryptionsdk/AwsCrypto.java
@@ -5,15 +5,26 @@
import com.amazonaws.encryptionsdk.exception.AwsCryptoException;
import com.amazonaws.encryptionsdk.exception.BadCiphertextException;
-import com.amazonaws.encryptionsdk.internal.*;
+import com.amazonaws.encryptionsdk.internal.DecryptionHandler;
+import com.amazonaws.encryptionsdk.internal.EncryptionHandler;
+import com.amazonaws.encryptionsdk.internal.LazyMessageCryptoHandler;
+import com.amazonaws.encryptionsdk.internal.MessageCryptoHandler;
+import com.amazonaws.encryptionsdk.internal.ProcessingSummary;
+import com.amazonaws.encryptionsdk.internal.SignaturePolicy;
+import com.amazonaws.encryptionsdk.internal.Utils;
import com.amazonaws.encryptionsdk.model.CiphertextHeaders;
-import com.amazonaws.encryptionsdk.model.EncryptionMaterials;
+import com.amazonaws.encryptionsdk.model.EncryptionMaterialsHandler;
import com.amazonaws.encryptionsdk.model.EncryptionMaterialsRequest;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Map;
+import software.amazon.cryptography.materialproviders.ICryptographicMaterialsManager;
+import software.amazon.cryptography.materialproviders.IKeyring;
+import software.amazon.cryptography.materialproviders.MaterialProviders;
+import software.amazon.cryptography.materialproviders.model.CreateDefaultCryptographicMaterialsManagerInput;
+import software.amazon.cryptography.materialproviders.model.MaterialProvidersConfig;
/**
* Provides the primary entry-point to the AWS Encryption SDK. All encryption and decryption
@@ -45,9 +56,9 @@
* should be used to encrypt the {@code DataKeys} by calling {@link
* MasterKeyProvider#getMasterKeysForEncryption(MasterKeyRequest)} . When more than one {@code
* MasterKey} is returned, the first {@code MasterKeys} is used to create the {@code DataKeys} by
- * calling {@link MasterKey#generateDataKey(CryptoAlgorithm,java.util.Map)} . All of the other
+ * calling {@link MasterKey#generateDataKey(CryptoAlgorithm, java.util.Map)} . All of the other
* {@code MasterKeys} are then used to re-encrypt that {@code DataKey} with {@link
- * MasterKey#encryptDataKey(CryptoAlgorithm,java.util.Map,DataKey)} . This list of {@link
+ * MasterKey#encryptDataKey(CryptoAlgorithm, java.util.Map, DataKey)} . This list of {@link
* EncryptedDataKey EncryptedDataKeys} (the same {@code DataKey} possibly encrypted multiple times)
* is stored in the {@link com.amazonaws.encryptionsdk.model.CiphertextHeaders}.
*
@@ -78,6 +89,7 @@ public class AwsCrypto {
private static final CommitmentPolicy DEFAULT_COMMITMENT_POLICY =
CommitmentPolicy.RequireEncryptRequireDecrypt;
private final CommitmentPolicy commitmentPolicy_;
+ private final MaterialProviders materialProviders_;
/**
* The maximum number of encrypted data keys to unwrap (resp. wrap) on decrypt (resp. encrypt), if
@@ -109,6 +121,7 @@ private AwsCrypto(Builder builder) {
encryptionAlgorithm_ = builder.encryptionAlgorithm_;
encryptionFrameSize_ = builder.encryptionFrameSize_;
maxEncryptedDataKeys_ = builder.maxEncryptedDataKeys_;
+ materialProviders_ = builder.materialProviders_;
}
public static class Builder {
@@ -116,6 +129,7 @@ public static class Builder {
private int encryptionFrameSize_ = getDefaultFrameSize();
private CommitmentPolicy commitmentPolicy_;
private int maxEncryptedDataKeys_ = CiphertextHeaders.NO_MAX_ENCRYPTED_DATA_KEYS;
+ private MaterialProviders materialProviders_ = null;
private Builder() {}
@@ -124,6 +138,7 @@ private Builder(final AwsCrypto client) {
encryptionFrameSize_ = client.encryptionFrameSize_;
commitmentPolicy_ = client.commitmentPolicy_;
maxEncryptedDataKeys_ = client.maxEncryptedDataKeys_;
+ materialProviders_ = client.materialProviders_;
}
/**
@@ -140,6 +155,17 @@ public Builder withEncryptionAlgorithm(CryptoAlgorithm encryptionAlgorithm) {
return this;
}
+ /**
+ * Sets the {@link MaterialProviders} for cryptographic operations.
+ *
+ * @param materialProviders The {@link MaterialProviders}
+ * @return The Builder, for method chaining
+ */
+ public Builder withMaterialProviders(MaterialProviders materialProviders) {
+ this.materialProviders_ = materialProviders;
+ return this;
+ }
+
/**
* Sets the frame size of the encrypted messages that the Aws Crypto client produces. The Aws
* Crypto client will use the last frame size set with either {@link
@@ -181,6 +207,12 @@ public Builder withMaxEncryptedDataKeys(int maxEncryptedDataKeys) {
}
public AwsCrypto build() {
+ if (materialProviders_ == null) {
+ materialProviders_ =
+ MaterialProviders.builder()
+ .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
+ .build();
+ }
return new AwsCrypto(this);
}
}
@@ -262,6 +294,7 @@ public int getEncryptionFrameSize() {
* This method is equivalent to calling {@link #estimateCiphertextSize(CryptoMaterialsManager,
* int, Map)} with a {@link DefaultCryptoMaterialsManager} based on the given provider.
*/
+ @Deprecated
public This method is equivalent to calling {@link
+ * #estimateCiphertextSize(ICryptographicMaterialsManager, int, Map)} with a {@link
+ * ICryptographicMaterialsManager} based on the given keyring.
+ */
+ public This method is equivalent to calling {@link #encryptData(ICryptographicMaterialsManager,
+ * byte[], Map)}
+ */
+ public CryptoResult This method is equivalent to calling {@link #encryptData(CryptoMaterialsManager, byte[],
* Map)} using a {@link DefaultCryptoMaterialsManager} based on the given provider.
*/
+ @Deprecated
public Note that if the encrypted message includes a trailing signature, by necessity it cannot be
+ * verified until after the decrypted plaintext has been released to the underlying {@link
+ * OutputStream}! This behavior can be avoided by using the non-streaming #decryptData(IKeyring,
+ * byte[]) method instead, or #createUnsignedMessageDecryptingStream(IKeyring, OutputStream) if
+ * you do not need to decrypt signed messages.
+ *
+ * @see #decryptData(IKeyring, byte[])
+ * @see #createUnsignedMessageDecryptingStream(IKeyring, OutputStream)
+ * @see javax.crypto.CipherOutputStream
+ */
+ public Note that if the encrypted message includes a trailing signature, by necessity it cannot be
+ * verified until after the decrypted plaintext has been released to the underlying {@link
+ * OutputStream}! This behavior can be avoided by using the non-streaming #decryptData(IKeyring,
+ * byte[], Map Note that if the encrypted message includes a trailing signature, by necessity it cannot be
+ * verified until after the decrypted plaintext has been produced from the {@link InputStream}!
+ * This behavior can be avoided by using the non-streaming #decryptData(IKeyring, byte[]) method
+ * instead, or #createUnsignedMessageDecryptingStream(IKeyring, InputStream) if you do not need to
+ * decrypt signed messages.
+ *
+ * @see #decryptData(IKeyring, byte[])
+ * @see #createUnsignedMessageDecryptingStream(IKeyring, InputStream)
+ * @see javax.crypto.CipherInputStream
+ */
+ public Note that if the encrypted message includes a trailing signature, by necessity it cannot be
+ * verified until after the decrypted plaintext has been produced from the {@link InputStream}!
+ * This behavior can be avoided by using the non-streaming #decryptData(IKeyring, byte[],
+ * Map Note that if the encrypted message includes a trailing signature, by necessity it cannot be
+ * verified until after the decrypted plaintext has been released to the underlying {@link
+ * OutputStream}! This behavior can be avoided by using the non-streaming
+ * #decryptData(ICryptographicMaterialsManager, byte[]) method instead, or
+ * #createUnsignedMessageDecryptingStream(ICryptographicMaterialsManager, OutputStream) if you do
+ * not need to decrypt signed messages.
+ *
+ * @see #decryptData(ICryptographicMaterialsManager, byte[])
+ * @see #createUnsignedMessageDecryptingStream(ICryptographicMaterialsManager, OutputStream)
+ * @see javax.crypto.CipherOutputStream
+ */
+ public CryptoOutputStream> createDecryptingStream(
+ final ICryptographicMaterialsManager materialsManager, final OutputStream os) {
+ final MessageCryptoHandler cryptoHandler =
+ DecryptionHandler.create(
+ materialsManager,
+ commitmentPolicy_,
+ SignaturePolicy.AllowEncryptAllowDecrypt,
+ maxEncryptedDataKeys_);
+ return new CryptoOutputStream(os, cryptoHandler);
+ }
+
+ /**
+ * Returns a {@link CryptoOutputStream} which decrypts the data prior to passing it onto the
+ * underlying {@link OutputStream}.
+ *
+ * Note that if the encrypted message includes a trailing signature, by necessity it cannot be
+ * verified until after the decrypted plaintext has been released to the underlying {@link
+ * OutputStream}! This behavior can be avoided by using the non-streaming
+ * #decryptData(ICryptographicMaterialsManager, byte[], Map
+ *
+ *
+ *
+ *
+ */
+public class MultipleCmkEncryptKeyringExample {
+
+ private static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8);
+
+ public static void main(final String[] args) {
+ final String keyArn1 = args[0];
+ final String keyArn2 = args[1];
+
+ encryptAndDecryptWithKeyring(keyArn1, keyArn2);
+ }
+
+ public static void encryptAndDecryptWithKeyring(final String keyArn1, final String keyArn2) {
+ // Instantiate the SDK.
+ // This builds the AwsCrypto client with the RequireEncryptRequireDecrypt commitment policy,
+ // which enforces that this client only encrypts using committing algorithm suites and enforces
+ // that this client will only decrypt encrypted messages that were created with a committing
+ // algorithm suite.
+ // This is the default commitment policy if you build the client with
+ // `AwsCrypto.builder().build()`
+ // or `AwsCrypto.standard()`.
+ final AwsCrypto crypto =
+ AwsCrypto.builder()
+ .withCommitmentPolicy(CommitmentPolicy.RequireEncryptRequireDecrypt)
+ .build();
+
+ // 2. Create the multi-keyring.
+ // We will label the AWS KMS keyring as the generator and the raw AES keyring as the
+ // only child keyring.
+ // You must provide a generator keyring to encrypt data.
+ // You may provide additional child keyrings. Each child keyring will be able to
+ // decrypt data encrypted with the multi-keyring on its own. It does not need
+ // knowledge of any other child keyrings or the generator keyring to decrypt.
+ final MaterialProviders materialProviders =
+ MaterialProviders.builder()
+ .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
+ .build();
+ final CreateAwsKmsMultiKeyringInput encryptingInput =
+ CreateAwsKmsMultiKeyringInput.builder()
+ .generator(keyArn1)
+ .kmsKeyIds(Arrays.asList(keyArn1, keyArn2))
+ .build();
+ final IKeyring multiCmkKeyring = materialProviders.CreateAwsKmsMultiKeyring(encryptingInput);
+
+ // 3. Create the child keyrings
+ // Instantiate an AWS KMS Keyring that are configured with keyArn1 and keyArn2
+ // separately.
+ // These will be used later in this example to show that the encrypted messages created by
+ // multiCmkKeyring
+ // can be decrypted by AWS KMS Keyrings that are configured with either CMK.
+ final IKeyring singleCMKKeyring1 =
+ materialProviders.CreateAwsKmsMultiKeyring(
+ CreateAwsKmsMultiKeyringInput.builder().generator(keyArn1).build());
+ final IKeyring singleCMKKeyring2 =
+ materialProviders.CreateAwsKmsMultiKeyring(
+ CreateAwsKmsMultiKeyringInput.builder().generator(keyArn1).build());
+
+ // 4. Create an encryption context
+ // Most encrypted data should have an associated encryption context
+ // to protect integrity. This sample uses placeholder values.
+ // For more information see:
+ // blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management
+ final Map
+ *
+ */
+public class SetCommitmentPolicyKeyringExample {
+
+ private static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8);
+
+ public static void main(final String[] args) {
+ final String keyArn = args[0];
+
+ encryptAndDecryptWithKeyrings(keyArn);
+ }
+
+ public static void encryptAndDecryptWithKeyrings(final String keyArn) {
+ // 1. Instantiate the SDK with a specific commitment policy
+ //
+ // `withCommitmentPolicy(CommitmentPolicy)` configures the client with
+ // a commitment policy that dictates whether the client is required to encrypt
+ // using committing algorithms and whether the client must require that the messages
+ // it decrypts were encrypted using committing algorithms.
+ // In this example, we set the commitment policy to `ForbidEncryptAllowDecrypt`.
+ // This policy enforces that the client writes using non-committing algorithms,
+ // and allows decrypting of messages created with committing algorithms.
+ //
+ // If this value is not set, the client is configured to use our recommended default:
+ // `RequireEncryptRequireDecrypt`.
+ // This policy enforces that the client uses committing algorithms
+ // to encrypt and enforces that the client only decrypts messages created with committing
+ // algorithms.
+ // We recommend using the default whenever possible.
+ final AwsCrypto crypto =
+ AwsCrypto.builder()
+ .withCommitmentPolicy(CommitmentPolicy.ForbidEncryptAllowDecrypt)
+ .build();
+
+ // 2. Create the AWS KMS keyring.
+ // We create a multi keyring, as this interface creates the KMS client for us automatically.
+ final MaterialProviders materialProviders =
+ MaterialProviders.builder()
+ .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
+ .build();
+ final IKeyring kmsKeyring =
+ materialProviders.CreateAwsKmsMultiKeyring(
+ CreateAwsKmsMultiKeyringInput.builder().generator(keyArn).build());
+
+ // 3. Create an encryption context
+ // Most encrypted data should have an associated encryption context
+ // to protect integrity. This sample uses placeholder values.
+ // For more information see:
+ // blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management
+ final Map
+ *
+ */
+public class SetEncryptionAlgorithmKeyringExample {
+
+ private static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8);
+
+ public static void main(final String[] args) {
+ final String keyArn = args[0];
+
+ encryptAndDecryptWithKeyring(keyArn);
+ }
+
+ public static void encryptAndDecryptWithKeyring(final String keyArn) {
+ // 1. Instantiate the SDK with the algorithm for encryption
+ //
+ // `withEncryptionAlgorithm(cryptoAlgorithm)` configures the client to encrypt
+ // using a specified encryption algorithm.
+ // This example sets the encryption algorithm to
+ // `CryptoAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`,
+ // which is an algorithm that does not contain message signing.
+ //
+ // If this value is not set, the client encrypts with the recommended default:
+ // `CryptoAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384`.
+ // We recommend using the default whenever possible.
+ // For a description of our supported algorithms, see
+ // https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/supported-algorithms.html
+ //
+ // You can update the encryption algorithm after constructing the client
+ // by using `crypto.setEncryptionAlgorithm(CryptoAlgorithm)`.
+ final AwsCrypto crypto =
+ AwsCrypto.builder()
+ .withEncryptionAlgorithm(CryptoAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY)
+ .build();
+
+ // 2. Create the AWS KMS keyring.
+ // We create a multi keyring, as this interface creates the KMS client for us automatically.
+ final MaterialProviders materialProviders =
+ MaterialProviders.builder()
+ .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
+ .build();
+ final CreateAwsKmsMultiKeyringInput encryptingInput =
+ CreateAwsKmsMultiKeyringInput.builder().generator(keyArn).build();
+ final IKeyring kmsKeyring = materialProviders.CreateAwsKmsMultiKeyring(encryptingInput);
+
+ // 3. Create an encryption context
+ // Most encrypted data should have an associated encryption context
+ // to protect integrity. This sample uses placeholder values.
+ // For more information see:
+ // blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management
+ final Map