decryptResult =
+ crypto.decryptData(
+ decryptingKeyring,
+ ciphertext,
+ // Verify that the encryption context in the result contains the
+ // encryption context supplied to the encryptData method
+ encryptionContext);
+
+ // 8. Verify that the decrypted plaintext matches the original plaintext
+ assert Arrays.equals(decryptResult.getResult(), EXAMPLE_DATA);
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/keyrings/EscrowedEncryptKeyringExample.java b/src/examples/java/com/amazonaws/crypto/examples/keyrings/EscrowedEncryptKeyringExample.java
new file mode 100644
index 00000000..70bc90bf
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/keyrings/EscrowedEncryptKeyringExample.java
@@ -0,0 +1,234 @@
+// 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.CryptoOutputStream;
+import com.amazonaws.util.IOUtils;
+import software.amazon.cryptography.materialproviders.IKeyring;
+import software.amazon.cryptography.materialproviders.MaterialProviders;
+import software.amazon.cryptography.materialproviders.model.CreateAwsKmsMultiKeyringInput;
+import software.amazon.cryptography.materialproviders.model.CreateMultiKeyringInput;
+import software.amazon.cryptography.materialproviders.model.CreateRawRsaKeyringInput;
+import software.amazon.cryptography.materialproviders.model.MaterialProvidersConfig;
+import software.amazon.cryptography.materialproviders.model.PaddingScheme;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.util.Collections;
+
+/**
+ * Encrypts a file using both AWS KMS Key and an asymmetric key pair.
+ *
+ * Arguments:
+ *
+ *
+ * - Key ARN: For help finding the Amazon Resource Name (ARN) of your AWS KMS customer master
+ * key (CMK), see 'Viewing Keys' at
+ * http://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html
+ *
- Name of file containing plaintext data to encrypt
+ *
+ *
+ * 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:
+ *
+ *
+ * - Name of file containing plaintext data to encrypt
+ *
+ *
+ * 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 context = Collections.singletonMap("Example", "FileStreaming");
+
+ // Because the file might be to large to load into memory, we stream the data, instead of
+ // loading it all at once.
+ FileInputStream in = new FileInputStream(srcFile);
+ CryptoInputStream encryptingStream =
+ crypto.createEncryptingStream(keyring, in, context);
+
+ FileOutputStream out = new FileOutputStream(srcFile + ".encrypted");
+ IOUtils.copy(encryptingStream, out);
+ encryptingStream.close();
+ out.close();
+
+ // Decrypt the file. Verify the encryption context before returning the plaintext.
+ // Since we encrypted using an unsigned algorithm suite, we can use the recommended
+ // createUnsignedMessageDecryptingStream method that only accepts unsigned messages.
+ in = new FileInputStream(srcFile + ".encrypted");
+ CryptoInputStream decryptingStream =
+ crypto.createUnsignedMessageDecryptingStream(keyring, in);
+ // Does it contain the expected encryption context?
+ if (!"FileStreaming"
+ .equals(decryptingStream.getCryptoResult().getEncryptionContext().get("Example"))) {
+ throw new IllegalStateException("Bad encryption context");
+ }
+
+ // Write the plaintext data to disk.
+ out = new FileOutputStream(srcFile + ".decrypted");
+ IOUtils.copy(decryptingStream, out);
+ decryptingStream.close();
+ out.close();
+ }
+
+ /**
+ * In practice, this key would be saved in a secure location. For this demo, we generate a new
+ * random key for each operation.
+ */
+ private static SecretKey retrieveEncryptionKey() {
+ SecureRandom rnd = new SecureRandom();
+ byte[] rawKey = new byte[16]; // 128 bits
+ rnd.nextBytes(rawKey);
+ return new SecretKeySpec(rawKey, "AES");
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/keyrings/MultiKeyringExample.java b/src/examples/java/com/amazonaws/crypto/examples/keyrings/MultiKeyringExample.java
new file mode 100644
index 00000000..eea846da
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/keyrings/MultiKeyringExample.java
@@ -0,0 +1,160 @@
+// 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.CryptoResult;
+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.CreateAwsKmsMultiKeyringInput;
+import software.amazon.cryptography.materialproviders.model.CreateMultiKeyringInput;
+import software.amazon.cryptography.materialproviders.model.CreateRawAesKeyringInput;
+import software.amazon.cryptography.materialproviders.model.MaterialProvidersConfig;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+/**
+ * This example creates a new multi-keyring which takes in multiple keyrings and uses them to
+ * encrypt and decrypt data. This example keyring consisting of an AWS KMS keyring (labeled the
+ * "generator keyring") and a raw AES keyring (labeled as the only "child keyring"). Data encrypted
+ * with a multi-keyring can be decrypted with any of its component keyrings.
+ *
+ * Arguments:
+ *
+ *
+ * - Key ARN: For help finding the Amazon Resource Name (ARN) of your AWS KMS customer master
+ * key (CMK), see 'Viewing Keys' at
+ * http://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html
+ *
+ *
+ * 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 encryptionContext =
+ Collections.singletonMap("ExampleContextKey", "ExampleContextValue");
+
+ // 6. Encrypt the data
+ final CryptoResult encryptResult =
+ crypto.encryptData(multiKeyring, EXAMPLE_DATA, encryptionContext);
+ final byte[] ciphertext = encryptResult.getResult();
+
+ // 7. Decrypt the data with the Multi Keyring that originally encrypted this data
+ final CryptoResult decryptResult =
+ crypto.decryptData(
+ multiKeyring,
+ ciphertext,
+ // Verify that the encryption context in the result contains the
+ // encryption context supplied to the encryptData method
+ encryptionContext);
+
+ // 8. Verify that the decrypted plaintext matches the original plaintext
+ assert Arrays.equals(decryptResult.getResult(), EXAMPLE_DATA);
+
+ // 9. Now show that the encrypted message can also be decrypted by child keyrings
+ // configured with either CMK.
+ final CryptoResult aesKeyringDecryptResult =
+ crypto.decryptData(rawAesKeyring, ciphertext, encryptionContext);
+ final CryptoResult kmsKeyringDecryptResult =
+ crypto.decryptData(kmsKeyring, ciphertext, encryptionContext);
+
+ // 10. Verify that the decrypted plaintext matches the original plaintext for each decryption
+ assert Arrays.equals(aesKeyringDecryptResult.getResult(), EXAMPLE_DATA);
+ assert Arrays.equals(kmsKeyringDecryptResult.getResult(), EXAMPLE_DATA);
+ }
+
+ public static ByteBuffer generateAesKeyBytes() {
+ // This example uses BouncyCastle's KeyGenerator to generate the key bytes.
+ // In practice, you should not generate this key in your code, and should instead
+ // retrieve this key from a secure key management system (e.g. HSM).
+ // This key is created here for example purposes only and should not be used for any other
+ // purpose.
+ KeyGenerator aesGen;
+ try {
+ aesGen = KeyGenerator.getInstance("AES");
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("No such algorithm", e);
+ }
+ aesGen.init(256, new SecureRandom());
+ SecretKey encryptionKey = aesGen.generateKey();
+ ByteBuffer encryptionKeyByteBuffer = ByteBuffer.wrap(encryptionKey.getEncoded());
+ return encryptionKeyByteBuffer;
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/keyrings/MultipleCmkEncryptKeyringExample.java b/src/examples/java/com/amazonaws/crypto/examples/keyrings/MultipleCmkEncryptKeyringExample.java
new file mode 100644
index 00000000..a5811bd8
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/keyrings/MultipleCmkEncryptKeyringExample.java
@@ -0,0 +1,128 @@
+// 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.CryptoResult;
+import software.amazon.cryptography.materialproviders.IKeyring;
+import software.amazon.cryptography.materialproviders.MaterialProviders;
+import software.amazon.cryptography.materialproviders.model.CreateAwsKmsMultiKeyringInput;
+import software.amazon.cryptography.materialproviders.model.MaterialProvidersConfig;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * This example creates a new multi-keyring which takes in multiple keyrings and uses them to
+ * encrypt and decrypt data. This example keyring consisting of an AWS KMS keyring (labeled the
+ * "generator keyring") and another AWS KMS keyring (labeled as the only "child keyring"). Data
+ * encrypted with a multi-keyring can be decrypted with any of its component keyrings.
+ *
+ * Arguments:
+ *
+ *
+ * - Key ARN 1: For help finding the Amazon Resource Name (ARN) of your AWS KMS customer master
+ * key (CMK), see 'Viewing Keys' at
+ * http://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html
+ *
- Key ARN 2: For help finding the Amazon Resource Name (ARN) of your AWS KMS customer master
+ * key (CMK), see 'Viewing Keys' at
+ * http://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html
+ *
+ */
+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 encryptionContext =
+ Collections.singletonMap("ExampleContextKey", "ExampleContextValue");
+
+ // 5. Encrypt the data
+ final CryptoResult encryptResult =
+ crypto.encryptData(multiCmkKeyring, EXAMPLE_DATA, encryptionContext);
+ final byte[] ciphertext = encryptResult.getResult();
+
+ // 6. Decrypt the data with the multi-keyring that originally encrypted this data
+ final CryptoResult decryptResult =
+ crypto.decryptData(
+ multiCmkKeyring,
+ ciphertext,
+ // Verify that the encryption context in the result contains the
+ // encryption context supplied to the encryptData method
+ encryptionContext);
+
+ // 8. Verify that the decrypted plaintext matches the original plaintext
+ assert Arrays.equals(decryptResult.getResult(), EXAMPLE_DATA);
+
+ // 9. Now show that the encrypted message can also be decrypted by child keyrings
+ // configured with either CMK.
+ final CryptoResult singleCmkDecryptResult1 =
+ crypto.decryptData(singleCMKKeyring1, ciphertext, encryptionContext);
+ final CryptoResult singleCmkDecryptResult2 =
+ crypto.decryptData(singleCMKKeyring2, ciphertext, encryptionContext);
+
+ // 10. Verify that the decrypted plaintext matches the original plaintext for each decryption
+ assert Arrays.equals(singleCmkDecryptResult1.getResult(), EXAMPLE_DATA);
+ assert Arrays.equals(singleCmkDecryptResult2.getResult(), EXAMPLE_DATA);
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/keyrings/RawAesKeyringExample.java b/src/examples/java/com/amazonaws/crypto/examples/keyrings/RawAesKeyringExample.java
new file mode 100644
index 00000000..c4e0140e
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/keyrings/RawAesKeyringExample.java
@@ -0,0 +1,115 @@
+// 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.CryptoResult;
+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.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+/**
+ * Encrypts and then decrypts data using an Raw Aes Keyring.
+ *
+ * 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 encryptionContext =
+ Collections.singletonMap("ExampleContextKey", "ExampleContextValue");
+
+ // 4. Encrypt the data
+ final CryptoResult encryptResult =
+ crypto.encryptData(rawAesKeyring, EXAMPLE_DATA, encryptionContext);
+ final byte[] ciphertext = encryptResult.getResult();
+
+ // 5. Decrypt the data
+ final CryptoResult decryptResult =
+ crypto.decryptData(
+ rawAesKeyring,
+ ciphertext,
+ // Verify that the encryption context in the result contains the
+ // encryption context supplied to the encryptData method
+ encryptionContext);
+
+ // 6. Verify that the decrypted plaintext matches the original plaintext
+ assert Arrays.equals(decryptResult.getResult(), EXAMPLE_DATA);
+ }
+
+ public static ByteBuffer generateAesKeyBytes() {
+ // This example uses BouncyCastle's KeyGenerator to generate the key bytes.
+ // In practice, you should not generate this key in your code, and should instead
+ // retrieve this key from a secure key management system (e.g. HSM).
+ // This key is created here for example purposes only and should not be used for any other
+ // purpose.
+ KeyGenerator aesGen;
+ try {
+ aesGen = KeyGenerator.getInstance("AES");
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("No such algorithm", e);
+ }
+ aesGen.init(256, new SecureRandom());
+ SecretKey encryptionKey = aesGen.generateKey();
+ ByteBuffer encryptionKeyByteBuffer = ByteBuffer.wrap(encryptionKey.getEncoded());
+ return encryptionKeyByteBuffer;
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/keyrings/RawRsaKeyringExample.java b/src/examples/java/com/amazonaws/crypto/examples/keyrings/RawRsaKeyringExample.java
new file mode 100644
index 00000000..5daacce1
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/keyrings/RawRsaKeyringExample.java
@@ -0,0 +1,149 @@
+// 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.CryptoResult;
+import software.amazon.cryptography.materialproviders.IKeyring;
+import software.amazon.cryptography.materialproviders.MaterialProviders;
+import software.amazon.cryptography.materialproviders.model.CreateRawRsaKeyringInput;
+import software.amazon.cryptography.materialproviders.model.MaterialProvidersConfig;
+import software.amazon.cryptography.materialproviders.model.PaddingScheme;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+
+import org.bouncycastle.util.io.pem.PemObject;
+import org.bouncycastle.util.io.pem.PemWriter;
+
+/**
+ * Encrypts and then decrypts data using an Raw Rsa Keyring. This example takes in Rsa Key Pair. If
+ * this example is run through the class' main method, it will create a new key pair. In practice,
+ * users of this library should not generate new key pairs like this, and should instead retrieve an
+ * existing key from a secure key management system (e.g. an HSM).
+ */
+public class RawRsaKeyringExample {
+
+ private static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8);
+
+ public static void main(final String[] args) {
+ KeyPair keyPair = generateKeyPair();
+ ByteBuffer publicKeyBytes = getPEMPublicKey(keyPair.getPublic());
+ ByteBuffer privateKeyBytes = getPEMPrivateKey(keyPair.getPrivate());
+
+ encryptAndDecryptWithKeyring(publicKeyBytes, privateKeyBytes);
+ }
+
+ public static void encryptAndDecryptWithKeyring(
+ final ByteBuffer publicKeyBytes, final ByteBuffer privateKeyBytes) {
+ // 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 Rsa Keyring with Public Key for Encryption.
+ final MaterialProviders matProv =
+ MaterialProviders.builder()
+ .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
+ .build();
+ final CreateRawRsaKeyringInput encryptingKeyringInput =
+ CreateRawRsaKeyringInput.builder()
+ .keyName("rsa-key")
+ .keyNamespace("rsa-keyring")
+ .paddingScheme(PaddingScheme.PKCS1)
+ .publicKey(publicKeyBytes)
+ .build();
+ final IKeyring encryptingKeyring = matProv.CreateRawRsaKeyring(encryptingKeyringInput);
+
+ // 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 encryptionContext =
+ Collections.singletonMap("ExampleContextKey", "ExampleContextValue");
+
+ // 4. Encrypt the data
+ final CryptoResult encryptResult =
+ crypto.encryptData(encryptingKeyring, EXAMPLE_DATA, encryptionContext);
+ final byte[] ciphertext = encryptResult.getResult();
+
+ // 5. Create the Raw Rsa Keyring with Private Key for Decryption.
+ final CreateRawRsaKeyringInput decryptingKeyringInput =
+ CreateRawRsaKeyringInput.builder()
+ .keyName("rsa-key")
+ .keyNamespace("rsa-keyring")
+ .paddingScheme(PaddingScheme.PKCS1)
+ .privateKey(privateKeyBytes)
+ .build();
+ final IKeyring decryptingKeyring = matProv.CreateRawRsaKeyring(decryptingKeyringInput);
+
+ // 6. Decrypt the data
+ final CryptoResult decryptResult =
+ crypto.decryptData(
+ decryptingKeyring,
+ ciphertext,
+ // Verify that the encryption context in the result contains the
+ // encryption context supplied to the encryptData method
+ encryptionContext);
+
+ // 7. Verify that the decrypted plaintext matches the original plaintext
+ assert Arrays.equals(decryptResult.getResult(), EXAMPLE_DATA);
+ }
+
+ public static KeyPair generateKeyPair() {
+ KeyPairGenerator rsaGen;
+ try {
+ rsaGen = KeyPairGenerator.getInstance("RSA");
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("No such algorithm", e);
+ }
+ rsaGen.initialize(2048, new SecureRandom());
+ return rsaGen.generateKeyPair();
+ }
+
+ public static ByteBuffer getPEMPublicKey(PublicKey publicKey) {
+ StringWriter publicKeyStringWriter = new StringWriter();
+ PemWriter publicKeyPemWriter = new PemWriter(publicKeyStringWriter);
+ try {
+ publicKeyPemWriter.writeObject(new PemObject("PUBLIC KEY", publicKey.getEncoded()));
+ publicKeyPemWriter.close();
+ } catch (IOException e) {
+ throw new RuntimeException("IOException while writing public key PEM", e);
+ }
+ return StandardCharsets.UTF_8.encode(publicKeyStringWriter.toString());
+ }
+
+ public static ByteBuffer getPEMPrivateKey(PrivateKey privateKey) {
+ StringWriter privateKeyStringWriter = new StringWriter();
+ PemWriter privateKeyPemWriter = new PemWriter(privateKeyStringWriter);
+ try {
+ privateKeyPemWriter.writeObject(new PemObject("PRIVATE KEY", privateKey.getEncoded()));
+ privateKeyPemWriter.close();
+ } catch (IOException e) {
+ throw new RuntimeException("IOException while writing private key PEM", e);
+ }
+ return StandardCharsets.UTF_8.encode(privateKeyStringWriter.toString());
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/keyrings/RequiredEncryptionContextCMMExample.java b/src/examples/java/com/amazonaws/crypto/examples/keyrings/RequiredEncryptionContextCMMExample.java
new file mode 100644
index 00000000..974d1744
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/keyrings/RequiredEncryptionContextCMMExample.java
@@ -0,0 +1,110 @@
+// 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.CryptoResult;
+import software.amazon.awssdk.services.kms.KmsClient;
+import software.amazon.cryptography.materialproviders.ICryptographicMaterialsManager;
+import software.amazon.cryptography.materialproviders.IKeyring;
+import software.amazon.cryptography.materialproviders.MaterialProviders;
+import software.amazon.cryptography.materialproviders.model.CreateAwsKmsKeyringInput;
+import software.amazon.cryptography.materialproviders.model.CreateDefaultCryptographicMaterialsManagerInput;
+import software.amazon.cryptography.materialproviders.model.CreateRequiredEncryptionContextCMMInput;
+import software.amazon.cryptography.materialproviders.model.MaterialProvidersConfig;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Demonstrate an encrypt/decrypt cycle using a Required Encryption Context CMM.
+ * A required encryption context CMM asks for required keys in the encryption context field
+ * on encrypt such that they will not be stored on the message, but WILL be included in the header signature.
+ * On decrypt the client MUST supply the key/value pair(s) that were not stored to successfully decrypt the message.
+ */
+public class RequiredEncryptionContextCMMExample {
+ 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
+ // 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 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 encryptionContext = new HashMap<>();
+ encryptionContext.put("key1", "value1");
+ encryptionContext.put("key2", "value2");
+ encryptionContext.put("requiredKey1", "requiredValue1");
+ encryptionContext.put("requiredKey2", "requiredValue2");
+
+ // 3. Create list of required encryption context keys.
+ // This is a list of keys that must be present in the encryption context.
+ final List requiredEncryptionContextKeys =
+ Arrays.asList("requiredKey1", "requiredKey2");
+
+ // 4. Create the AWS KMS keyring.
+ final MaterialProviders materialProviders =
+ MaterialProviders.builder()
+ .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
+ .build();
+ final CreateAwsKmsKeyringInput keyringInput =
+ CreateAwsKmsKeyringInput.builder().kmsKeyId(keyArn).kmsClient(KmsClient.create()).build();
+ final IKeyring kmsKeyring = materialProviders.CreateAwsKmsKeyring(keyringInput);
+
+ // 5. Create the required encryption context CMM.
+ final ICryptographicMaterialsManager cmm =
+ materialProviders.CreateDefaultCryptographicMaterialsManager(
+ CreateDefaultCryptographicMaterialsManagerInput.builder().keyring(kmsKeyring).build());
+
+ final ICryptographicMaterialsManager requiredCMM =
+ materialProviders.CreateRequiredEncryptionContextCMM(
+ CreateRequiredEncryptionContextCMMInput.builder()
+ .requiredEncryptionContextKeys(requiredEncryptionContextKeys)
+ .underlyingCMM(cmm)
+ .build());
+
+ // 6. Encrypt the data
+ final CryptoResult encryptResult =
+ crypto.encryptData(requiredCMM, EXAMPLE_DATA, encryptionContext);
+ final byte[] ciphertext = encryptResult.getResult();
+
+ // 7. Reproduce the encryption context.
+ // The reproduced encryption context MUST contain a value for
+ // every key in the configured required encryption context keys during encryption with
+ // Required Encryption Context CMM.
+ final Map reproducedEncryptionContext = new HashMap<>();
+ reproducedEncryptionContext.put("requiredKey1", "requiredValue1");
+ reproducedEncryptionContext.put("requiredKey2", "requiredValue2");
+
+ // 8. Decrypt the data
+ final CryptoResult decryptResult =
+ crypto.decryptData(requiredCMM, ciphertext, reproducedEncryptionContext);
+
+ // 9. Verify that the decrypted plaintext matches the original plaintext
+ assert Arrays.equals(decryptResult.getResult(), EXAMPLE_DATA);
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/keyrings/SetCommitmentPolicyKeyringExample.java b/src/examples/java/com/amazonaws/crypto/examples/keyrings/SetCommitmentPolicyKeyringExample.java
new file mode 100644
index 00000000..2f80f6f8
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/keyrings/SetCommitmentPolicyKeyringExample.java
@@ -0,0 +1,102 @@
+// 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.CryptoResult;
+import software.amazon.cryptography.materialproviders.IKeyring;
+import software.amazon.cryptography.materialproviders.MaterialProviders;
+import software.amazon.cryptography.materialproviders.model.CreateAwsKmsMultiKeyringInput;
+import software.amazon.cryptography.materialproviders.model.MaterialProvidersConfig;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Configures a client with a specific commitment policy, then encrypts and decrypts data using an
+ * AWS KMS Keyring.
+ *
+ * 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:
+ *
+ *
+ * - Key ARN: For help finding the Amazon Resource Name (ARN) of your AWS KMS customer master
+ * key (CMK), see 'Viewing Keys' at
+ * http://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html
+ *
+ */
+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 encryptionContext =
+ Collections.singletonMap("ExampleContextKey", "ExampleContextValue");
+
+ // 4. Encrypt the data
+ final CryptoResult encryptResult =
+ crypto.encryptData(kmsKeyring, EXAMPLE_DATA, encryptionContext);
+ final byte[] ciphertext = encryptResult.getResult();
+
+ // 5. Decrypt the data
+ final CryptoResult decryptResult =
+ crypto.decryptData(
+ kmsKeyring,
+ ciphertext,
+ // Verify that the encryption context in the result contains the
+ // encryption context supplied to the encryptData method
+ encryptionContext);
+
+ // 6. Verify that the decrypted plaintext matches the original plaintext
+ assert Arrays.equals(decryptResult.getResult(), EXAMPLE_DATA);
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/keyrings/SetEncryptionAlgorithmKeyringExample.java b/src/examples/java/com/amazonaws/crypto/examples/keyrings/SetEncryptionAlgorithmKeyringExample.java
new file mode 100644
index 00000000..3f9c73c5
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/keyrings/SetEncryptionAlgorithmKeyringExample.java
@@ -0,0 +1,98 @@
+// 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.CryptoAlgorithm;
+import com.amazonaws.encryptionsdk.CryptoResult;
+import software.amazon.cryptography.materialproviders.IKeyring;
+import software.amazon.cryptography.materialproviders.MaterialProviders;
+import software.amazon.cryptography.materialproviders.model.CreateAwsKmsMultiKeyringInput;
+import software.amazon.cryptography.materialproviders.model.MaterialProvidersConfig;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Configures a client with a specific encryption algorithm, then encrypts and decrypts data using
+ * that encryption algorithm and an Aws Kms Keyring.
+ *
+ * Arguments:
+ *
+ *
+ * - Key ARN: For help finding the Amazon Resource Name (ARN) of your AWS KMS customer master
+ * key (CMK), see 'Viewing Keys' at
+ * http://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html
+ *
+ */
+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 encryptionContext =
+ Collections.singletonMap("ExampleContextKey", "ExampleContextValue");
+
+ // 4. Encrypt the data
+ final CryptoResult encryptResult =
+ crypto.encryptData(kmsKeyring, EXAMPLE_DATA, encryptionContext);
+ final byte[] ciphertext = encryptResult.getResult();
+
+ // 5. Decrypt the data
+ final CryptoResult decryptResult =
+ crypto.decryptData(
+ kmsKeyring,
+ ciphertext,
+ // Verify that the encryption context in the result contains the
+ // encryption context supplied to the encryptData method
+ encryptionContext);
+
+ // 6. Verify that the decrypted plaintext matches the original plaintext
+ assert Arrays.equals(decryptResult.getResult(), EXAMPLE_DATA);
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/keyrings/StreamingWithRequiredEncryptionContextCMMExample.java b/src/examples/java/com/amazonaws/crypto/examples/keyrings/StreamingWithRequiredEncryptionContextCMMExample.java
new file mode 100644
index 00000000..5ca259ba
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/keyrings/StreamingWithRequiredEncryptionContextCMMExample.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 static org.junit.jupiter.api.Assertions.assertTrue;
+
+import com.amazonaws.encryptionsdk.AwsCrypto;
+import com.amazonaws.encryptionsdk.CommitmentPolicy;
+import com.amazonaws.encryptionsdk.CryptoInputStream;
+import com.amazonaws.util.IOUtils;
+import software.amazon.awssdk.services.kms.KmsClient;
+import software.amazon.cryptography.materialproviders.ICryptographicMaterialsManager;
+import software.amazon.cryptography.materialproviders.IKeyring;
+import software.amazon.cryptography.materialproviders.MaterialProviders;
+import software.amazon.cryptography.materialproviders.model.CreateAwsKmsKeyringInput;
+import software.amazon.cryptography.materialproviders.model.CreateDefaultCryptographicMaterialsManagerInput;
+import software.amazon.cryptography.materialproviders.model.CreateRequiredEncryptionContextCMMInput;
+import software.amazon.cryptography.materialproviders.model.MaterialProvidersConfig;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Demonstrate an encrypt/decrypt cycle using a Required Encryption Context CMM using an Input Stream as Input.
+ * A required encryption context CMM asks for required keys in the encryption context field
+ * on encrypt such that they will not be stored on the message, but WILL be included in the header signature.
+ * On decrypt the client MUST supply the key/value pair(s) that were not stored to successfully decrypt the message.
+ */
+public class StreamingWithRequiredEncryptionContextCMMExample {
+ public static void main(final String[] args) throws IOException {
+ final String srcFile = args[0];
+ final String keyArn = args[1];
+
+ encryptAndDecryptWithKeyring(srcFile, keyArn);
+ }
+
+ public static void encryptAndDecryptWithKeyring(final String srcFile, final String keyArn) throws IOException {
+ // 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)
+ .build();
+
+ // 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 encryptionContext = new HashMap<>();
+ encryptionContext.put("key1", "value1");
+ encryptionContext.put("key2", "value2");
+ encryptionContext.put("requiredKey1", "requiredValue1");
+ encryptionContext.put("requiredKey2", "requiredValue2");
+
+ // Create list of required encryption context keys.
+ // This is a list of keys that must be present in the encryption context.
+ final List requiredEncryptionContextKeys =
+ Arrays.asList("requiredKey1", "requiredKey2");
+
+ // Create the AWS KMS keyring.
+ final MaterialProviders materialProviders =
+ MaterialProviders.builder()
+ .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
+ .build();
+ final CreateAwsKmsKeyringInput keyringInput =
+ CreateAwsKmsKeyringInput.builder().kmsKeyId(keyArn).kmsClient(KmsClient.create()).build();
+ final IKeyring kmsKeyring = materialProviders.CreateAwsKmsKeyring(keyringInput);
+
+ // Create the required encryption context CMM.
+ final ICryptographicMaterialsManager cmm =
+ materialProviders.CreateDefaultCryptographicMaterialsManager(
+ CreateDefaultCryptographicMaterialsManagerInput.builder().keyring(kmsKeyring).build());
+
+ final ICryptographicMaterialsManager requiredCMM =
+ materialProviders.CreateRequiredEncryptionContextCMM(
+ CreateRequiredEncryptionContextCMMInput.builder()
+ .requiredEncryptionContextKeys(requiredEncryptionContextKeys)
+ .underlyingCMM(cmm)
+ .build());
+
+ // Because the file might be too large to load into memory, we stream the data, instead of
+ // loading it all at once.
+ FileInputStream in = new FileInputStream(srcFile);
+ CryptoInputStream encryptingStream =
+ crypto.createEncryptingStream(requiredCMM, in, encryptionContext);
+
+ FileOutputStream out = new FileOutputStream(srcFile + ".encrypted");
+ IOUtils.copy(encryptingStream, out);
+ encryptingStream.close();
+ out.close();
+
+ // Decrypt the file.
+ in = new FileInputStream(srcFile + ".encrypted");
+ CryptoInputStream decryptingStream =
+ crypto.createDecryptingStream(cmm, in, encryptionContext);
+
+ // Write the plaintext data to disk.
+ out = new FileOutputStream(srcFile + ".decrypted");
+ IOUtils.copy(decryptingStream, out);
+ decryptingStream.close();
+ out.close();
+
+ File file1 = new File(srcFile);
+ File file2 = new File(srcFile + ".decrypted");
+ assertTrue(org.apache.commons.io.FileUtils.contentEquals(file1, file2));
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/AwsKmsHierarchicalKeyringExample.java b/src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/AwsKmsHierarchicalKeyringExample.java
new file mode 100644
index 00000000..6e2572a1
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/AwsKmsHierarchicalKeyringExample.java
@@ -0,0 +1,333 @@
+// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.amazonaws.crypto.examples.keyrings.hierarchical;
+
+import com.amazonaws.encryptionsdk.AwsCrypto;
+import com.amazonaws.encryptionsdk.CryptoResult;
+import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
+import software.amazon.awssdk.services.kms.KmsClient;
+import software.amazon.cryptography.keystore.KeyStore;
+import software.amazon.cryptography.keystore.model.CreateKeyInput;
+import software.amazon.cryptography.keystore.model.KMSConfiguration;
+import software.amazon.cryptography.keystore.model.KeyStoreConfig;
+import software.amazon.cryptography.materialproviders.IBranchKeyIdSupplier;
+import software.amazon.cryptography.materialproviders.IKeyring;
+import software.amazon.cryptography.materialproviders.MaterialProviders;
+import software.amazon.cryptography.materialproviders.model.CacheType;
+import software.amazon.cryptography.materialproviders.model.CreateAwsKmsHierarchicalKeyringInput;
+import software.amazon.cryptography.materialproviders.model.DefaultCache;
+import software.amazon.cryptography.materialproviders.model.MaterialProvidersConfig;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * This example sets up the Hierarchical Keyring, which establishes a key hierarchy where "branch"
+ * keys are persisted in DynamoDb. These branch keys are used to protect your data keys, and these
+ * branch keys are themselves protected by a KMS Key.
+ *
+ * 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 encryptionContextA = new HashMap<>();
+ encryptionContextA.put("tenant", "TenantA");
+ encryptionContextA.put("encryption", "context");
+ encryptionContextA.put("is not", "secret");
+ encryptionContextA.put("but adds", "useful metadata");
+ encryptionContextA.put("that can help you", "be confident that");
+ encryptionContextA.put("the data you are handling", "is what you think it is");
+
+ // Create encryption context for TenantB
+ Map encryptionContextB = new HashMap<>();
+ encryptionContextB.put("tenant", "TenantB");
+ encryptionContextB.put("encryption", "context");
+ encryptionContextB.put("is not", "secret");
+ encryptionContextB.put("but adds", "useful metadata");
+ encryptionContextB.put("that can help you", "be confident that");
+ encryptionContextB.put("the data you are handling", "is what you think it is");
+
+ // Encrypt the data for encryptionContextA & encryptionContextB
+ final CryptoResult encryptResultA =
+ crypto.encryptData(hierarchicalKeyring, EXAMPLE_DATA, encryptionContextA);
+ final CryptoResult encryptResultB =
+ crypto.encryptData(hierarchicalKeyring, EXAMPLE_DATA, encryptionContextB);
+
+ // To attest that TenantKeyB cannot decrypt a message written by TenantKeyA
+ // let's construct more restrictive hierarchical keyrings.
+ final CreateAwsKmsHierarchicalKeyringInput keyringInputA =
+ CreateAwsKmsHierarchicalKeyringInput.builder()
+ .keyStore(keystore)
+ .branchKeyId(branchKeyIdA)
+ .ttlSeconds(600)
+ .cache(
+ CacheType.builder() // OPTIONAL
+ .Default(DefaultCache.builder().entryCapacity(100).build())
+ .build())
+ .build();
+ final IKeyring hierarchicalKeyringA = matProv.CreateAwsKmsHierarchicalKeyring(keyringInputA);
+
+ final CreateAwsKmsHierarchicalKeyringInput keyringInputB =
+ CreateAwsKmsHierarchicalKeyringInput.builder()
+ .keyStore(keystore)
+ .branchKeyId(branchKeyIdB)
+ .ttlSeconds(600)
+ .cache(
+ CacheType.builder() // OPTIONAL
+ .Default(DefaultCache.builder().entryCapacity(100).build())
+ .build())
+ .build();
+ final IKeyring hierarchicalKeyringB = matProv.CreateAwsKmsHierarchicalKeyring(keyringInputB);
+
+ boolean decryptFailed = false;
+ // Try to use keyring for Tenant B to decrypt a message encrypted with Tenant A's key
+ // Expected to fail.
+ try {
+ crypto.decryptData(hierarchicalKeyringB, encryptResultA.getResult());
+ } catch (Exception e) {
+ decryptFailed = true;
+ }
+ assert decryptFailed == true;
+
+ decryptFailed = false;
+ // Try to use keyring for Tenant A to decrypt a message encrypted with Tenant B's key
+ // Expected to fail.
+ try {
+ crypto.decryptData(hierarchicalKeyringA, encryptResultB.getResult());
+ } catch (Exception e) {
+ decryptFailed = true;
+ }
+ assert decryptFailed == true;
+
+ // Decrypt your encrypted data using the same keyring you used on encrypt.
+ final CryptoResult decryptResultA =
+ crypto.decryptData(hierarchicalKeyring, encryptResultA.getResult());
+ assert Arrays.equals(decryptResultA.getResult(), EXAMPLE_DATA);
+
+ final CryptoResult decryptResultB =
+ crypto.decryptData(hierarchicalKeyring, encryptResultB.getResult());
+ assert Arrays.equals(decryptResultB.getResult(), EXAMPLE_DATA);
+ }
+
+ public static void encryptAndDecryptWithKeyringThreadSafe(
+ 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 encryptionContextA = new HashMap<>();
+ encryptionContextA.put("tenant", "TenantA");
+ encryptionContextA.put("encryption", "context");
+ encryptionContextA.put("is not", "secret");
+ encryptionContextA.put("but adds", "useful metadata");
+ encryptionContextA.put("that can help you", "be confident that");
+ encryptionContextA.put("the data you are handling", "is what you think it is");
+
+ // Create encryption context for TenantB
+ Map encryptionContextB = new HashMap<>();
+ encryptionContextB.put("tenant", "TenantB");
+ encryptionContextB.put("encryption", "context");
+ encryptionContextB.put("is not", "secret");
+ encryptionContextB.put("but adds", "useful metadata");
+ encryptionContextB.put("that can help you", "be confident that");
+ encryptionContextB.put("the data you are handling", "is what you think it is");
+
+ final int numThreads = 1000;
+ final ConcurrentHashMap sharedMap = new ConcurrentHashMap<>();
+ AtomicInteger counter = new AtomicInteger(0);
+
+ ExecutorService executor = Executors.newFixedThreadPool(numThreads);
+
+ for (int i = 0; i < numThreads; i++) {
+ final int threadNumber = i;
+ executor.execute(
+ () -> {
+ // Encrypt the data for encryptionContextA & encryptionContextB
+ final CryptoResult encryptResultA =
+ crypto.encryptData(hierarchicalKeyring, EXAMPLE_DATA, encryptionContextA);
+ final CryptoResult encryptResultB =
+ crypto.encryptData(hierarchicalKeyring, EXAMPLE_DATA, encryptionContextB);
+
+ // Decrypt your encrypted data using the same keyring you used on encrypt.
+ final CryptoResult decryptResultA =
+ crypto.decryptData(hierarchicalKeyring, encryptResultA.getResult());
+ assert Arrays.equals(decryptResultA.getResult(), EXAMPLE_DATA);
+
+ final CryptoResult decryptResultB =
+ crypto.decryptData(hierarchicalKeyring, encryptResultB.getResult());
+ assert Arrays.equals(decryptResultB.getResult(), EXAMPLE_DATA);
+
+ // Increment the counter
+ counter.incrementAndGet();
+ });
+ }
+
+ executor.shutdown();
+
+ while (!executor.isTerminated()) {
+ // Wait for all threads to finish.
+ }
+
+ System.out.println("All threads have completed.");
+
+ // Ensure thread safety by checking the map's size
+ if (counter.get() == numThreads) {
+ System.out.println("Thread safety maintained.");
+ } else {
+ System.out.println("Thread safety not maintained.");
+ }
+ }
+
+ public static void main(final String[] args) {
+ if (args.length <= 0) {
+ throw new IllegalArgumentException(
+ "To run this example, include the keyStoreTableName, logicalKeyStoreName, and kmsKeyId in args");
+ }
+ final String keyStoreTableName = args[0];
+ final String logicalKeyStoreName = args[1];
+ final String kmsKeyId = args[2];
+ encryptAndDecryptWithKeyring(keyStoreTableName, logicalKeyStoreName, kmsKeyId);
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/CreateBranchKeyId.java b/src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/CreateBranchKeyId.java
new file mode 100644
index 00000000..3c680a5f
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/CreateBranchKeyId.java
@@ -0,0 +1,45 @@
+// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.amazonaws.crypto.examples.keyrings.hierarchical;
+
+import static com.amazonaws.encryptionsdk.kms.KMSTestFixtures.TEST_KEYSTORE_KMS_KEY_ID;
+import static com.amazonaws.encryptionsdk.kms.KMSTestFixtures.TEST_KEYSTORE_NAME;
+import static com.amazonaws.encryptionsdk.kms.KMSTestFixtures.TEST_LOGICAL_KEYSTORE_NAME;
+
+import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
+import software.amazon.awssdk.services.kms.KmsClient;
+import software.amazon.cryptography.keystore.KeyStore;
+import software.amazon.cryptography.keystore.model.CreateKeyInput;
+import software.amazon.cryptography.keystore.model.CreateKeyOutput;
+import software.amazon.cryptography.keystore.model.KMSConfiguration;
+import software.amazon.cryptography.keystore.model.KeyStoreConfig;
+
+public class CreateBranchKeyId {
+ public static String createBranchKeyId() {
+ // Create an AWS KMS Configuration to use with your KeyStore.
+ // The KMS Configuration MUST have the right access to the resources in the KeyStore.
+ final KMSConfiguration kmsConfig =
+ KMSConfiguration.builder().kmsKeyArn(TEST_KEYSTORE_KMS_KEY_ID).build();
+
+ // Configure your KeyStore resource.
+ // This SHOULD be the same configuration that you used
+ // to initially create and populate your KeyStore.
+ final KeyStoreConfig keystoreConfig =
+ KeyStoreConfig.builder()
+ .ddbClient(DynamoDbClient.create())
+ .ddbTableName(TEST_KEYSTORE_NAME)
+ .logicalKeyStoreName(TEST_LOGICAL_KEYSTORE_NAME)
+ .kmsClient(KmsClient.create())
+ .kmsConfiguration(kmsConfig)
+ .build();
+
+ // Create a KeyStore
+ final KeyStore keystore = KeyStore.builder().KeyStoreConfig(keystoreConfig).build();
+
+ // Create a branch key identifier with the AWS KMS Key configured in the KeyStore Configuration.
+ final CreateKeyOutput branchKeyId = keystore.CreateKey(CreateKeyInput.builder().build());
+
+ return branchKeyId.branchKeyIdentifier();
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/ExampleBranchKeyIdSupplier.java b/src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/ExampleBranchKeyIdSupplier.java
new file mode 100644
index 00000000..07e99abb
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/ExampleBranchKeyIdSupplier.java
@@ -0,0 +1,44 @@
+// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.amazonaws.crypto.examples.keyrings.hierarchical;
+
+import software.amazon.cryptography.materialproviders.IBranchKeyIdSupplier;
+import software.amazon.cryptography.materialproviders.model.GetBranchKeyIdInput;
+import software.amazon.cryptography.materialproviders.model.GetBranchKeyIdOutput;
+
+import java.util.Map;
+
+// Use the encryption contexts to define friendly names for each branch key
+public class ExampleBranchKeyIdSupplier implements IBranchKeyIdSupplier {
+ private static String branchKeyIdForTenantA;
+ private static String branchKeyIdForTenantB;
+
+ public ExampleBranchKeyIdSupplier(String tenant1Id, String tenant2Id) {
+ this.branchKeyIdForTenantA = tenant1Id;
+ this.branchKeyIdForTenantB = tenant2Id;
+ }
+
+ @Override
+ public GetBranchKeyIdOutput GetBranchKeyId(GetBranchKeyIdInput input) {
+
+ Map encryptionContext = input.encryptionContext();
+
+ if (!encryptionContext.containsKey("tenant")) {
+ throw new IllegalArgumentException(
+ "EncryptionContext invalid, does not contain expected tenant key value pair.");
+ }
+
+ String tenantKeyId = encryptionContext.get("tenant");
+ String branchKeyId;
+
+ if (tenantKeyId.equals("TenantA")) {
+ branchKeyId = branchKeyIdForTenantA;
+ } else if (tenantKeyId.equals("TenantB")) {
+ branchKeyId = branchKeyIdForTenantB;
+ } else {
+ throw new IllegalArgumentException("Item does not contain valid tenant ID");
+ }
+ return GetBranchKeyIdOutput.builder().branchKeyId(branchKeyId).build();
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/VersionBranchKeyId.java b/src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/VersionBranchKeyId.java
new file mode 100644
index 00000000..8803ae2c
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/keyrings/hierarchical/VersionBranchKeyId.java
@@ -0,0 +1,43 @@
+// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.amazonaws.crypto.examples.keyrings.hierarchical;
+
+import static com.amazonaws.encryptionsdk.kms.KMSTestFixtures.TEST_KEYSTORE_KMS_KEY_ID;
+import static com.amazonaws.encryptionsdk.kms.KMSTestFixtures.TEST_KEYSTORE_NAME;
+import static com.amazonaws.encryptionsdk.kms.KMSTestFixtures.TEST_LOGICAL_KEYSTORE_NAME;
+
+import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
+import software.amazon.awssdk.services.kms.KmsClient;
+import software.amazon.cryptography.keystore.KeyStore;
+import software.amazon.cryptography.keystore.model.KMSConfiguration;
+import software.amazon.cryptography.keystore.model.KeyStoreConfig;
+import software.amazon.cryptography.keystore.model.VersionKeyInput;
+
+public class VersionBranchKeyId {
+ public static void versionBranchKeyId(String branchKeyId) {
+ // Create an AWS KMS Configuration to use with your KeyStore.
+ // The KMS Configuration MUST have the right access to the resources in the KeyStore.
+ final KMSConfiguration kmsConfig =
+ KMSConfiguration.builder().kmsKeyArn(TEST_KEYSTORE_KMS_KEY_ID).build();
+
+ // Configure your KeyStore resource.
+ // This SHOULD be the same configuration that you used
+ // to initially create and populate your KeyStore.
+ final KeyStoreConfig keystoreConfig =
+ KeyStoreConfig.builder()
+ .ddbClient(DynamoDbClient.create())
+ .ddbTableName(TEST_KEYSTORE_NAME)
+ .logicalKeyStoreName(TEST_LOGICAL_KEYSTORE_NAME)
+ .kmsClient(KmsClient.create())
+ .kmsConfiguration(kmsConfig)
+ .build();
+
+ // Create a KeyStore
+ final KeyStore keystore = KeyStore.builder().KeyStoreConfig(keystoreConfig).build();
+
+ // To version a branch key you MUST have access to kms:ReEncrypt* and
+ // kms:GenerateDataKeyWithoutPlaintext
+ keystore.VersionKey(VersionKeyInput.builder().branchKeyIdentifier(branchKeyId).build());
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/BasicEncryptionExample.java b/src/examples/java/com/amazonaws/crypto/examples/v2/BasicEncryptionExample.java
similarity index 98%
rename from src/examples/java/com/amazonaws/crypto/examples/BasicEncryptionExample.java
rename to src/examples/java/com/amazonaws/crypto/examples/v2/BasicEncryptionExample.java
index bed6c681..053d7df6 100644
--- a/src/examples/java/com/amazonaws/crypto/examples/BasicEncryptionExample.java
+++ b/src/examples/java/com/amazonaws/crypto/examples/v2/BasicEncryptionExample.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/BasicMultiRegionKeyEncryptionExample.java b/src/examples/java/com/amazonaws/crypto/examples/v2/BasicMultiRegionKeyEncryptionExample.java
similarity index 99%
rename from src/examples/java/com/amazonaws/crypto/examples/BasicMultiRegionKeyEncryptionExample.java
rename to src/examples/java/com/amazonaws/crypto/examples/v2/BasicMultiRegionKeyEncryptionExample.java
index dd6e7a35..58e9c0e7 100644
--- a/src/examples/java/com/amazonaws/crypto/examples/BasicMultiRegionKeyEncryptionExample.java
+++ b/src/examples/java/com/amazonaws/crypto/examples/v2/BasicMultiRegionKeyEncryptionExample.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 com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CommitmentPolicy;
diff --git a/src/examples/java/com/amazonaws/crypto/examples/DiscoveryDecryptionExample.java b/src/examples/java/com/amazonaws/crypto/examples/v2/DiscoveryDecryptionExample.java
similarity index 99%
rename from src/examples/java/com/amazonaws/crypto/examples/DiscoveryDecryptionExample.java
rename to src/examples/java/com/amazonaws/crypto/examples/v2/DiscoveryDecryptionExample.java
index 167bc90f..f6ac45bc 100644
--- a/src/examples/java/com/amazonaws/crypto/examples/DiscoveryDecryptionExample.java
+++ b/src/examples/java/com/amazonaws/crypto/examples/v2/DiscoveryDecryptionExample.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/DiscoveryMultiRegionDecryptionExample.java b/src/examples/java/com/amazonaws/crypto/examples/v2/DiscoveryMultiRegionDecryptionExample.java
similarity index 99%
rename from src/examples/java/com/amazonaws/crypto/examples/DiscoveryMultiRegionDecryptionExample.java
rename to src/examples/java/com/amazonaws/crypto/examples/v2/DiscoveryMultiRegionDecryptionExample.java
index 529b1192..30b195ea 100644
--- a/src/examples/java/com/amazonaws/crypto/examples/DiscoveryMultiRegionDecryptionExample.java
+++ b/src/examples/java/com/amazonaws/crypto/examples/v2/DiscoveryMultiRegionDecryptionExample.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 com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CommitmentPolicy;
diff --git a/src/examples/java/com/amazonaws/crypto/examples/EscrowedEncryptExample.java b/src/examples/java/com/amazonaws/crypto/examples/v2/EscrowedEncryptExample.java
similarity index 99%
rename from src/examples/java/com/amazonaws/crypto/examples/EscrowedEncryptExample.java
rename to src/examples/java/com/amazonaws/crypto/examples/v2/EscrowedEncryptExample.java
index e04c35d0..403642db 100644
--- a/src/examples/java/com/amazonaws/crypto/examples/EscrowedEncryptExample.java
+++ b/src/examples/java/com/amazonaws/crypto/examples/v2/EscrowedEncryptExample.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.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
diff --git a/src/examples/java/com/amazonaws/crypto/examples/FileStreamingExample.java b/src/examples/java/com/amazonaws/crypto/examples/v2/FileStreamingExample.java
similarity index 99%
rename from src/examples/java/com/amazonaws/crypto/examples/FileStreamingExample.java
rename to src/examples/java/com/amazonaws/crypto/examples/v2/FileStreamingExample.java
index 7399cba2..a9ae1360 100644
--- a/src/examples/java/com/amazonaws/crypto/examples/FileStreamingExample.java
+++ b/src/examples/java/com/amazonaws/crypto/examples/v2/FileStreamingExample.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.io.FileInputStream;
import java.io.FileOutputStream;
diff --git a/src/examples/java/com/amazonaws/crypto/examples/MultipleCmkEncryptExample.java b/src/examples/java/com/amazonaws/crypto/examples/v2/MultipleCmkEncryptExample.java
similarity index 99%
rename from src/examples/java/com/amazonaws/crypto/examples/MultipleCmkEncryptExample.java
rename to src/examples/java/com/amazonaws/crypto/examples/v2/MultipleCmkEncryptExample.java
index cae7f81c..07d8cd33 100644
--- a/src/examples/java/com/amazonaws/crypto/examples/MultipleCmkEncryptExample.java
+++ b/src/examples/java/com/amazonaws/crypto/examples/v2/MultipleCmkEncryptExample.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/RestrictRegionExample.java b/src/examples/java/com/amazonaws/crypto/examples/v2/RestrictRegionExample.java
similarity index 99%
rename from src/examples/java/com/amazonaws/crypto/examples/RestrictRegionExample.java
rename to src/examples/java/com/amazonaws/crypto/examples/v2/RestrictRegionExample.java
index 91d1f379..900fcd93 100644
--- a/src/examples/java/com/amazonaws/crypto/examples/RestrictRegionExample.java
+++ b/src/examples/java/com/amazonaws/crypto/examples/v2/RestrictRegionExample.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/SetCommitmentPolicyExample.java b/src/examples/java/com/amazonaws/crypto/examples/v2/SetCommitmentPolicyExample.java
similarity index 99%
rename from src/examples/java/com/amazonaws/crypto/examples/SetCommitmentPolicyExample.java
rename to src/examples/java/com/amazonaws/crypto/examples/v2/SetCommitmentPolicyExample.java
index e0dec906..b66f465f 100644
--- a/src/examples/java/com/amazonaws/crypto/examples/SetCommitmentPolicyExample.java
+++ b/src/examples/java/com/amazonaws/crypto/examples/v2/SetCommitmentPolicyExample.java
@@ -1,12 +1,7 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
-package com.amazonaws.crypto.examples;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Map;
+package com.amazonaws.crypto.examples.v2;
import com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CommitmentPolicy;
@@ -14,6 +9,11 @@
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKey;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.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 > long estimateCiphertextSize(
final MasterKeyProvider provider,
final int plaintextSize,
@@ -270,10 +303,31 @@ public > long estimateCiphertextSize(
new DefaultCryptoMaterialsManager(provider), plaintextSize, encryptionContext);
}
+ /**
+ * Returns the best estimate for the output length of encrypting a plaintext with the provided
+ * {@code plaintextSize} and {@code encryptionContext}. The actual ciphertext may be shorter.
+ *
+ * This method is equivalent to calling {@link
+ * #estimateCiphertextSize(ICryptographicMaterialsManager, int, Map)} with a {@link
+ * ICryptographicMaterialsManager} based on the given keyring.
+ */
+ public > long estimateCiphertextSize(
+ final IKeyring keyring,
+ final int plaintextSize,
+ final Map encryptionContext) {
+ CreateDefaultCryptographicMaterialsManagerInput input =
+ CreateDefaultCryptographicMaterialsManagerInput.builder().keyring(keyring).build();
+ return estimateCiphertextSize(
+ materialProviders_.CreateDefaultCryptographicMaterialsManager(input),
+ plaintextSize,
+ encryptionContext);
+ }
+
/**
* Returns the best estimate for the output length of encrypting a plaintext with the provided
* {@code plaintextSize} and {@code encryptionContext}. The actual ciphertext may be shorter.
*/
+ @Deprecated
public long estimateCiphertextSize(
CryptoMaterialsManager materialsManager,
final int plaintextSize,
@@ -294,7 +348,37 @@ public long estimateCiphertextSize(
final MessageCryptoHandler cryptoHandler =
new EncryptionHandler(
getEncryptionFrameSize(),
- checkAlgorithm(materialsManager.getMaterialsForEncrypt(request)),
+ checkAlgorithm(new CMMHandler(materialsManager).getMaterialsForEncrypt(request)),
+ commitmentPolicy_);
+
+ return cryptoHandler.estimateOutputSize(plaintextSize);
+ }
+
+ /**
+ * Returns the best estimate for the output length of encrypting a plaintext with the provided
+ * {@code plaintextSize} and {@code encryptionContext}. The actual ciphertext may be shorter.
+ */
+ public long estimateCiphertextSize(
+ ICryptographicMaterialsManager materialsManager,
+ final int plaintextSize,
+ final Map encryptionContext) {
+ EncryptionMaterialsRequest request =
+ EncryptionMaterialsRequest.newBuilder()
+ .setContext(encryptionContext)
+ .setRequestedAlgorithm(getEncryptionAlgorithm())
+ // We're not actually encrypting any data, so don't consume any bytes from the cache's
+ // limits. We do need to
+ // pass /something/ though, or the cache will be bypassed (as it'll assume this is a
+ // streaming encrypt of
+ // unknown size).
+ .setPlaintextSize(0)
+ .setCommitmentPolicy(commitmentPolicy_)
+ .build();
+
+ final MessageCryptoHandler cryptoHandler =
+ new EncryptionHandler(
+ getEncryptionFrameSize(),
+ checkAlgorithm(new CMMHandler(materialsManager).getMaterialsForEncrypt(request)),
commitmentPolicy_);
return cryptoHandler.estimateOutputSize(plaintextSize);
@@ -304,20 +388,98 @@ public long estimateCiphertextSize(
* Returns the equivalent to calling {@link #estimateCiphertextSize(MasterKeyProvider, int, Map)}
* with an empty {@code encryptionContext}.
*/
+ @Deprecated
public > long estimateCiphertextSize(
final MasterKeyProvider provider, final int plaintextSize) {
return estimateCiphertextSize(provider, plaintextSize, EMPTY_MAP);
}
+ /**
+ * Returns the equivalent to calling {@link #estimateCiphertextSize(IKeyring, int, Map)} with an
+ * empty {@code encryptionContext}.
+ */
+ public > long estimateCiphertextSize(
+ final IKeyring keyring, final int plaintextSize) {
+ return estimateCiphertextSize(keyring, plaintextSize, EMPTY_MAP);
+ }
+
/**
* Returns the equivalent to calling {@link #estimateCiphertextSize(CryptoMaterialsManager, int,
* Map)} with an empty {@code encryptionContext}.
*/
+ @Deprecated
public long estimateCiphertextSize(
final CryptoMaterialsManager materialsManager, final int plaintextSize) {
return estimateCiphertextSize(materialsManager, plaintextSize, EMPTY_MAP);
}
+ /**
+ * Returns the equivalent to calling {@link
+ * #estimateCiphertextSize(ICryptographicMaterialsManager, int, Map)} with an empty {@code
+ * encryptionContext}.
+ */
+ public long estimateCiphertextSize(
+ final ICryptographicMaterialsManager materialsManager, final int plaintextSize) {
+ return estimateCiphertextSize(materialsManager, plaintextSize, EMPTY_MAP);
+ }
+
+ /**
+ * Returns the equivalent to calling {@link #encryptData(IKeyring, byte[], Map)} with an empty
+ * {@code encryptionContext}.
+ */
+ public > CryptoResult encryptData(
+ final IKeyring keyring, final byte[] plaintext) {
+ return encryptData(keyring, plaintext, EMPTY_MAP);
+ }
+
+ /**
+ * Returns an encrypted form of {@code plaintext} that has been protected with {@link DataKey
+ * DataKeys} that are in turn protected by {@link IKeyring Keyrings} provided by {@code keyring}.
+ *
+ * This method is equivalent to calling {@link #encryptData(ICryptographicMaterialsManager,
+ * byte[], Map)}
+ */
+ public CryptoResult encryptData(
+ final IKeyring keyring, final byte[] plaintext, final Map encryptionContext) {
+ Utils.assertNonNull(keyring, "keyring");
+ return encryptData(createDefaultCMM(keyring), plaintext, encryptionContext);
+ }
+
+ /**
+ * Returns the equivalent to calling {@link #encryptData(ICryptographicMaterialsManager, byte[],
+ * Map)} with an empty {@code encryptionContext}.
+ */
+ public CryptoResult encryptData(
+ final ICryptographicMaterialsManager materialsManager, final byte[] plaintext) {
+ return encryptData(materialsManager, plaintext, EMPTY_MAP);
+ }
+
+ /**
+ * Returns an encrypted form of {@code plaintext} that has been protected with {@link DataKey
+ * DataKeys} that are in turn protected by the given CryptoMaterialsProvider.
+ */
+ public CryptoResult encryptData(
+ final ICryptographicMaterialsManager materialsManager,
+ final byte[] plaintext,
+ final Map encryptionContext) {
+ Utils.assertNonNull(materialsManager, "materialsManager");
+
+ EncryptionMaterialsRequest request =
+ EncryptionMaterialsRequest.newBuilder()
+ .setContext(encryptionContext)
+ .setRequestedAlgorithm(getEncryptionAlgorithm())
+ .setPlaintext(plaintext)
+ .setCommitmentPolicy(commitmentPolicy_)
+ .build();
+ CMMHandler cmmHandler = new CMMHandler(materialsManager);
+ EncryptionMaterialsHandler encryptionMaterials =
+ checkMaxEncryptedDataKeys(checkAlgorithm(cmmHandler.getMaterialsForEncrypt(request)));
+ final MessageCryptoHandler cryptoHandler =
+ new EncryptionHandler(getEncryptionFrameSize(), encryptionMaterials, commitmentPolicy_);
+
+ return encryptData(cryptoHandler, plaintext);
+ }
+
/**
* Returns an encrypted form of {@code plaintext} that has been protected with {@link DataKey
* DataKeys} that are in turn protected by {@link MasterKey MasterKeys} provided by {@code
@@ -326,10 +488,12 @@ public long estimateCiphertextSize(
* This method is equivalent to calling {@link #encryptData(CryptoMaterialsManager, byte[],
* Map)} using a {@link DefaultCryptoMaterialsManager} based on the given provider.
*/
+ @Deprecated
public > CryptoResult encryptData(
final MasterKeyProvider provider,
final byte[] plaintext,
final Map encryptionContext) {
+ Utils.assertNonNull(provider, "provider");
//noinspection unchecked
return (CryptoResult)
encryptData(new DefaultCryptoMaterialsManager(provider), plaintext, encryptionContext);
@@ -339,6 +503,7 @@ public > CryptoResult encryptData(
* Returns an encrypted form of {@code plaintext} that has been protected with {@link DataKey
* DataKeys} that are in turn protected by the given CryptoMaterialsProvider.
*/
+ @Deprecated
public CryptoResult encryptData(
CryptoMaterialsManager materialsManager,
final byte[] plaintext,
@@ -351,11 +516,18 @@ public > CryptoResult encryptData(
.setCommitmentPolicy(commitmentPolicy_)
.build();
- EncryptionMaterials encryptionMaterials =
- checkMaxEncryptedDataKeys(checkAlgorithm(materialsManager.getMaterialsForEncrypt(request)));
+ EncryptionMaterialsHandler encryptionMaterials =
+ checkMaxEncryptedDataKeys(
+ checkAlgorithm(
+ new EncryptionMaterialsHandler(materialsManager.getMaterialsForEncrypt(request))));
final MessageCryptoHandler cryptoHandler =
new EncryptionHandler(getEncryptionFrameSize(), encryptionMaterials, commitmentPolicy_);
+ return encryptData(cryptoHandler, plaintext);
+ }
+
+ private > CryptoResult encryptData(
+ MessageCryptoHandler cryptoHandler, byte[] plaintext) {
final int outSizeEstimate = cryptoHandler.estimateOutputSize(plaintext.length);
final byte[] out = new byte[outSizeEstimate];
int outLen =
@@ -365,13 +537,18 @@ public > CryptoResult encryptData(
final byte[] outBytes = Utils.truncate(out, outLen);
//noinspection unchecked
- return new CryptoResult(outBytes, cryptoHandler.getMasterKeys(), cryptoHandler.getHeaders());
+ return new CryptoResult(
+ outBytes,
+ cryptoHandler.getMasterKeys(),
+ cryptoHandler.getHeaders(),
+ cryptoHandler.getEncryptionContext());
}
/**
* Returns the equivalent to calling {@link #encryptData(MasterKeyProvider, byte[], Map)} with an
* empty {@code encryptionContext}.
*/
+ @Deprecated
public > CryptoResult encryptData(
final MasterKeyProvider provider, final byte[] plaintext) {
return encryptData(provider, plaintext, EMPTY_MAP);
@@ -381,6 +558,7 @@ public > CryptoResult encryptData(
* Returns the equivalent to calling {@link #encryptData(CryptoMaterialsManager, byte[], Map)}
* with an empty {@code encryptionContext}.
*/
+ @Deprecated
public CryptoResult encryptData(
final CryptoMaterialsManager materialsManager, final byte[] plaintext) {
return encryptData(materialsManager, plaintext, EMPTY_MAP);
@@ -429,7 +607,8 @@ public > CryptoResult encryptString(
return new CryptoResult<>(
Utils.encodeBase64String(ctBytes.getResult()),
ctBytes.getMasterKeys(),
- ctBytes.getHeaders());
+ ctBytes.getHeaders(),
+ ctBytes.getEncryptionContext());
}
/**
@@ -471,11 +650,10 @@ public > CryptoResult encryptString(
* usable {@link DataKey} in the ciphertext and then decrypts the ciphertext using that {@code
* DataKey}.
*/
+ @Deprecated
public > CryptoResult decryptData(
final MasterKeyProvider provider, final byte[] ciphertext) {
- return decryptData(
- Utils.assertNonNull(provider, "provider"),
- new ParsedCiphertext(ciphertext, maxEncryptedDataKeys_));
+ return decryptData(provider, new ParsedCiphertext(ciphertext, maxEncryptedDataKeys_));
}
/**
@@ -486,15 +664,15 @@ public > CryptoResult decryptData(
* @param ciphertext the ciphertext to attempt to decrypt.
* @return the {@link CryptoResult} with the decrypted data.
*/
+ @Deprecated
public CryptoResult decryptData(
final CryptoMaterialsManager materialsManager, final byte[] ciphertext) {
- return decryptData(
- Utils.assertNonNull(materialsManager, "materialsManager"),
- new ParsedCiphertext(ciphertext, maxEncryptedDataKeys_));
+ return decryptData(materialsManager, new ParsedCiphertext(ciphertext, maxEncryptedDataKeys_));
}
/** @see #decryptData(MasterKeyProvider, byte[]) */
@SuppressWarnings("unchecked")
+ @Deprecated
public > CryptoResult decryptData(
final MasterKeyProvider provider, final ParsedCiphertext ciphertext) {
Utils.assertNonNull(provider, "provider");
@@ -503,6 +681,7 @@ public > CryptoResult decryptData(
}
/** @see #decryptData(CryptoMaterialsManager, byte[]) */
+ @Deprecated
public CryptoResult decryptData(
final CryptoMaterialsManager materialsManager, final ParsedCiphertext ciphertext) {
Utils.assertNonNull(materialsManager, "materialsManager");
@@ -515,6 +694,11 @@ public > CryptoResult decryptData(
SignaturePolicy.AllowEncryptAllowDecrypt,
maxEncryptedDataKeys_);
+ return decryptData(cryptoHandler, ciphertext);
+ }
+
+ private CryptoResult decryptData(
+ final MessageCryptoHandler cryptoHandler, final ParsedCiphertext ciphertext) {
final byte[] ciphertextBytes = ciphertext.getCiphertext();
final int contentLen = ciphertextBytes.length - ciphertext.getOffset();
final int outSizeEstimate = cryptoHandler.estimateOutputSize(contentLen);
@@ -531,7 +715,119 @@ public > CryptoResult decryptData(
final byte[] outBytes = Utils.truncate(out, outLen);
//noinspection unchecked
- return new CryptoResult(outBytes, cryptoHandler.getMasterKeys(), cryptoHandler.getHeaders());
+ return new CryptoResult(
+ outBytes,
+ cryptoHandler.getMasterKeys(),
+ cryptoHandler.getHeaders(),
+ cryptoHandler.getEncryptionContext());
+ }
+
+ /**
+ * Decrypts the provided ciphertext by delegating to the provided materialsManager to obtain the
+ * decrypted {@link DataKey}.
+ *
+ * @param keyring the {@link IKeyring} to use for decryption operations.
+ * @param ciphertext the ciphertext to attempt to decrypt.
+ * @return the {@link CryptoResult} with the decrypted data.
+ */
+ public CryptoResult decryptData(final IKeyring keyring, final byte[] ciphertext) {
+ return decryptData(keyring, new ParsedCiphertext(ciphertext, maxEncryptedDataKeys_));
+ }
+
+ /**
+ * Decrypts the provided ciphertext by delegating to the provided materialsManager to obtain the
+ * decrypted {@link DataKey}.
+ *
+ * @param keyring the {@link IKeyring} to use for decryption operations.
+ * @param ciphertext the ciphertext to attempt to decrypt.
+ * @param encryptionContext The encryption context MUST contain a value for every key in the
+ * configured required encryption context keys during encryption with Required Encryption
+ * Context CMM.
+ * @return the {@link CryptoResult} with the decrypted data.
+ */
+ public CryptoResult decryptData(
+ final IKeyring keyring,
+ final byte[] ciphertext,
+ final Map encryptionContext) {
+ return decryptData(
+ keyring, new ParsedCiphertext(ciphertext, maxEncryptedDataKeys_), encryptionContext);
+ }
+
+ /** @see #decryptData(IKeyring, byte[]) */
+ public CryptoResult decryptData(
+ final IKeyring keyring, final ParsedCiphertext ciphertext) {
+ return decryptData(keyring, ciphertext, EMPTY_MAP);
+ }
+
+ /** @see #decryptData(IKeyring, byte[], Map) */
+ private CryptoResult decryptData(
+ IKeyring keyring, ParsedCiphertext ciphertext, Map encryptionContext) {
+ //noinspection unchecked
+ Utils.assertNonNull(keyring, "keyring");
+
+ return decryptData(createDefaultCMM(keyring), ciphertext, encryptionContext);
+ }
+
+ /**
+ * Decrypts the provided ciphertext by delegating to the provided materialsManager to obtain the
+ * decrypted {@link DataKey}.
+ *
+ * @param materialsManager the {@link ICryptographicMaterialsManager} to use for decryption
+ * operations.
+ * @param ciphertext the ciphertext to attempt to decrypt.
+ * @return the {@link CryptoResult} with the decrypted data.
+ */
+ public CryptoResult decryptData(
+ final ICryptographicMaterialsManager materialsManager, final byte[] ciphertext) {
+ return decryptData(materialsManager, new ParsedCiphertext(ciphertext, maxEncryptedDataKeys_));
+ }
+
+ /**
+ * Decrypts the provided ciphertext by delegating to the provided materialsManager to obtain the
+ * decrypted {@link DataKey}.
+ *
+ * @param materialsManager the {@link ICryptographicMaterialsManager} to use for decryption
+ * operations.
+ * @param ciphertext the ciphertext to attempt to decrypt.
+ * @param encryptionContext The encryption context MUST contain a value for every key in the
+ * configured required encryption context keys during encryption with Required Encryption
+ * Context CMM.
+ * @return the {@link CryptoResult} with the decrypted data.
+ */
+ public CryptoResult decryptData(
+ final ICryptographicMaterialsManager materialsManager,
+ final byte[] ciphertext,
+ final Map encryptionContext) {
+ return decryptData(
+ materialsManager,
+ new ParsedCiphertext(ciphertext, maxEncryptedDataKeys_),
+ encryptionContext);
+ }
+
+ /** @see #decryptData(ICryptographicMaterialsManager, byte[]) */
+ public CryptoResult decryptData(
+ final ICryptographicMaterialsManager materialsManager, final ParsedCiphertext ciphertext) {
+
+ return decryptData(materialsManager, ciphertext, EMPTY_MAP);
+ }
+
+ /** @see #decryptData(ICryptographicMaterialsManager, byte[]) */
+ public CryptoResult decryptData(
+ final ICryptographicMaterialsManager materialsManager,
+ final ParsedCiphertext ciphertext,
+ final Map encryptionContext) {
+ Utils.assertNonNull(materialsManager, "materialsManager");
+
+ final MessageCryptoHandler cryptoHandler =
+ DecryptionHandler.create(
+ materialsManager,
+ ciphertext,
+ commitmentPolicy_,
+ SignaturePolicy.AllowEncryptAllowDecrypt,
+ maxEncryptedDataKeys_,
+ encryptionContext);
+
+ return decryptData(cryptoHandler, ciphertext);
}
/**
@@ -581,7 +877,8 @@ public > CryptoResult decryptString(
return new CryptoResult(
new String(ptBytes.getResult(), StandardCharsets.UTF_8),
ptBytes.getMasterKeys(),
- ptBytes.getHeaders());
+ ptBytes.getHeaders(),
+ ptBytes.getEncryptionContext());
}
/**
@@ -591,6 +888,7 @@ public > CryptoResult decryptString(
* @see #encryptData(MasterKeyProvider, byte[], Map)
* @see javax.crypto.CipherOutputStream
*/
+ @Deprecated
public > CryptoOutputStream createEncryptingStream(
final MasterKeyProvider provider,
final OutputStream os,
@@ -600,6 +898,20 @@ public > CryptoOutputStream createEncryptingStream(
createEncryptingStream(new DefaultCryptoMaterialsManager(provider), os, encryptionContext);
}
+ /**
+ * Returns a {@link CryptoOutputStream} which encrypts the data prior to passing it onto the
+ * underlying {@link OutputStream}.
+ *
+ * @see #encryptData(IKeyring, byte[], Map)
+ * @see javax.crypto.CipherOutputStream
+ */
+ public > CryptoOutputStream createEncryptingStream(
+ final IKeyring keyring, final OutputStream os, final Map encryptionContext) {
+ //noinspection unchecked
+ return (CryptoOutputStream)
+ createEncryptingStream(createDefaultCMM(keyring), os, encryptionContext);
+ }
+
/**
* Returns a {@link CryptoOutputStream} which encrypts the data prior to passing it onto the
* underlying {@link OutputStream}.
@@ -607,32 +919,69 @@ public > CryptoOutputStream createEncryptingStream(
* @see #encryptData(MasterKeyProvider, byte[], Map)
* @see javax.crypto.CipherOutputStream
*/
+ @Deprecated
public CryptoOutputStream> createEncryptingStream(
final CryptoMaterialsManager materialsManager,
final OutputStream os,
final Map encryptionContext) {
return new CryptoOutputStream<>(
- os, getEncryptingStreamHandler(materialsManager, encryptionContext));
+ os, getEncryptingStreamHandler(new CMMHandler(materialsManager), encryptionContext));
+ }
+
+ /**
+ * Returns a {@link CryptoOutputStream} which encrypts the data prior to passing it onto the
+ * underlying {@link OutputStream}.
+ *
+ * @see #encryptData(IKeyring, byte[], Map)
+ * @see javax.crypto.CipherOutputStream
+ */
+ public CryptoOutputStream> createEncryptingStream(
+ final ICryptographicMaterialsManager materialsManager,
+ final OutputStream os,
+ final Map encryptionContext) {
+ return new CryptoOutputStream<>(
+ os, getEncryptingStreamHandler(new CMMHandler(materialsManager), encryptionContext));
}
/**
* Returns the equivalent to calling {@link #createEncryptingStream(MasterKeyProvider,
* OutputStream, Map)} with an empty {@code encryptionContext}.
*/
+ @Deprecated
public > CryptoOutputStream createEncryptingStream(
final MasterKeyProvider provider, final OutputStream os) {
return createEncryptingStream(provider, os, EMPTY_MAP);
}
+ /**
+ * Returns the equivalent to calling {@link #createEncryptingStream(IKeyring, OutputStream, Map)}
+ * with an empty {@code encryptionContext}.
+ */
+ public > CryptoOutputStream createEncryptingStream(
+ final IKeyring keyring, final OutputStream os) {
+ return createEncryptingStream(keyring, os, EMPTY_MAP);
+ }
+
/**
* Returns the equivalent to calling {@link #createEncryptingStream(CryptoMaterialsManager,
* OutputStream, Map)} with an empty {@code encryptionContext}.
*/
+ @Deprecated
public CryptoOutputStream> createEncryptingStream(
final CryptoMaterialsManager materialsManager, final OutputStream os) {
return createEncryptingStream(materialsManager, os, EMPTY_MAP);
}
+ /**
+ * Returns the equivalent to calling {@link
+ * #createEncryptingStream(ICryptographicMaterialsManager, OutputStream, Map)} with an empty
+ * {@code encryptionContext}.
+ */
+ public CryptoOutputStream> createEncryptingStream(
+ final ICryptographicMaterialsManager materialsManager, final OutputStream os) {
+ return createEncryptingStream(materialsManager, os, EMPTY_MAP);
+ }
+
/**
* Returns a {@link CryptoInputStream} which encrypts the data after reading it from the
* underlying {@link InputStream}.
@@ -640,6 +989,7 @@ public CryptoOutputStream> createEncryptingStream(
* @see #encryptData(MasterKeyProvider, byte[], Map)
* @see javax.crypto.CipherInputStream
*/
+ @Deprecated
public > CryptoInputStream createEncryptingStream(
final MasterKeyProvider provider,
final InputStream is,
@@ -649,6 +999,20 @@ public > CryptoInputStream createEncryptingStream(
createEncryptingStream(new DefaultCryptoMaterialsManager(provider), is, encryptionContext);
}
+ /**
+ * Returns a {@link CryptoInputStream} which encrypts the data after reading it from the
+ * underlying {@link InputStream}.
+ *
+ * @see #encryptData(IKeyring, byte[], Map)
+ * @see javax.crypto.CipherInputStream
+ */
+ public > CryptoInputStream createEncryptingStream(
+ final IKeyring keyring, final InputStream is, final Map encryptionContext) {
+ ICryptographicMaterialsManager materialsManager = createDefaultCMM(keyring);
+ //noinspection unchecked
+ return (CryptoInputStream) createEncryptingStream(materialsManager, is, encryptionContext);
+ }
+
/**
* Returns a {@link CryptoInputStream} which encrypts the data after reading it from the
* underlying {@link InputStream}.
@@ -656,12 +1020,30 @@ public > CryptoInputStream createEncryptingStream(
* @see #encryptData(MasterKeyProvider, byte[], Map)
* @see javax.crypto.CipherInputStream
*/
+ @Deprecated
public CryptoInputStream> createEncryptingStream(
CryptoMaterialsManager materialsManager,
final InputStream is,
final Map encryptionContext) {
final MessageCryptoHandler cryptoHandler =
- getEncryptingStreamHandler(materialsManager, encryptionContext);
+ getEncryptingStreamHandler(new CMMHandler(materialsManager), encryptionContext);
+
+ return new CryptoInputStream<>(is, cryptoHandler);
+ }
+
+ /**
+ * Returns a {@link CryptoInputStream} which encrypts the data after reading it from the
+ * underlying {@link InputStream}.
+ *
+ * @see #encryptData(IKeyring, byte[], Map)
+ * @see javax.crypto.CipherInputStream
+ */
+ public CryptoInputStream> createEncryptingStream(
+ ICryptographicMaterialsManager materialsManager,
+ final InputStream is,
+ final Map encryptionContext) {
+ final MessageCryptoHandler cryptoHandler =
+ getEncryptingStreamHandler(new CMMHandler(materialsManager), encryptionContext);
return new CryptoInputStream<>(is, cryptoHandler);
}
@@ -670,17 +1052,38 @@ public CryptoInputStream> createEncryptingStream(
* Returns the equivalent to calling {@link #createEncryptingStream(MasterKeyProvider,
* InputStream, Map)} with an empty {@code encryptionContext}.
*/
+ @Deprecated
public > CryptoInputStream createEncryptingStream(
final MasterKeyProvider provider, final InputStream is) {
return createEncryptingStream(provider, is, EMPTY_MAP);
}
/**
- * Returns the equivalent to calling {@link #createEncryptingStream(CryptoMaterialsManager,
+ * Returns the equivalent to calling {@link #createEncryptingStream(MasterKeyProvider,
* InputStream, Map)} with an empty {@code encryptionContext}.
*/
- public CryptoInputStream> createEncryptingStream(
- final CryptoMaterialsManager materialsManager, final InputStream is) {
+ public > CryptoInputStream createEncryptingStream(
+ final IKeyring keyring, final InputStream is) {
+ return createEncryptingStream(keyring, is, EMPTY_MAP);
+ }
+
+ /**
+ * Returns the equivalent to calling {@link #createEncryptingStream(CryptoMaterialsManager,
+ * InputStream, Map)} with an empty {@code encryptionContext}.
+ */
+ @Deprecated
+ public CryptoInputStream> createEncryptingStream(
+ final CryptoMaterialsManager materialsManager, final InputStream is) {
+ return createEncryptingStream(materialsManager, is, EMPTY_MAP);
+ }
+
+ /**
+ * Returns the equivalent to calling {@link
+ * #createEncryptingStream(ICryptographicMaterialsManager, InputStream, Map)} with an empty {@code
+ * encryptionContext}.
+ */
+ public CryptoInputStream> createEncryptingStream(
+ final ICryptographicMaterialsManager materialsManager, final InputStream is) {
return createEncryptingStream(materialsManager, is, EMPTY_MAP);
}
@@ -691,6 +1094,7 @@ public CryptoInputStream> createEncryptingStream(
* @see #decryptData(MasterKeyProvider, byte[])
* @see javax.crypto.CipherOutputStream
*/
+ @Deprecated
public > CryptoOutputStream createUnsignedMessageDecryptingStream(
final MasterKeyProvider provider, final OutputStream os) {
final MessageCryptoHandler cryptoHandler =
@@ -702,6 +1106,43 @@ public > CryptoOutputStream createUnsignedMessageDecry
return new CryptoOutputStream(os, cryptoHandler);
}
+ /**
+ * Returns a {@link CryptoOutputStream} which decrypts the data prior to passing it onto the
+ * underlying {@link OutputStream}. This version only accepts unsigned messages.
+ *
+ * @see #decryptData(IKeyring, byte[])
+ * @see javax.crypto.CipherOutputStream
+ */
+ public > CryptoOutputStream createUnsignedMessageDecryptingStream(
+ final IKeyring keyring, final OutputStream os) {
+ final MessageCryptoHandler cryptoHandler =
+ DecryptionHandler.create(
+ createDefaultCMM(keyring),
+ commitmentPolicy_,
+ SignaturePolicy.AllowEncryptForbidDecrypt,
+ maxEncryptedDataKeys_);
+ return new CryptoOutputStream(os, cryptoHandler);
+ }
+
+ /**
+ * Returns a {@link CryptoOutputStream} which decrypts the data prior to passing it onto the
+ * underlying {@link OutputStream}. This version only accepts unsigned messages.
+ *
+ * @see #decryptData(IKeyring, byte[], Map)
+ * @see javax.crypto.CipherOutputStream
+ */
+ public > CryptoOutputStream createUnsignedMessageDecryptingStream(
+ final IKeyring keyring, final OutputStream os, final Map encryptionContext) {
+ final MessageCryptoHandler cryptoHandler =
+ DecryptionHandler.create(
+ createDefaultCMM(keyring),
+ commitmentPolicy_,
+ SignaturePolicy.AllowEncryptForbidDecrypt,
+ maxEncryptedDataKeys_,
+ encryptionContext);
+ return new CryptoOutputStream(os, cryptoHandler);
+ }
+
/**
* Returns a {@link CryptoInputStream} which decrypts the data after reading it from the
* underlying {@link InputStream}. This version only accepts unsigned messages.
@@ -709,6 +1150,7 @@ public > CryptoOutputStream createUnsignedMessageDecry
* @see #decryptData(MasterKeyProvider, byte[])
* @see javax.crypto.CipherInputStream
*/
+ @Deprecated
public > CryptoInputStream createUnsignedMessageDecryptingStream(
final MasterKeyProvider provider, final InputStream is) {
final MessageCryptoHandler cryptoHandler =
@@ -720,6 +1162,43 @@ public > CryptoInputStream createUnsignedMessageDecryp
return new CryptoInputStream(is, cryptoHandler);
}
+ /**
+ * Returns a {@link CryptoInputStream} which decrypts the data after reading it from the
+ * underlying {@link InputStream}. This version only accepts unsigned messages.
+ *
+ * @see #decryptData(IKeyring, byte[])
+ * @see javax.crypto.CipherInputStream
+ */
+ public > CryptoInputStream createUnsignedMessageDecryptingStream(
+ final IKeyring keyring, final InputStream is) {
+ final MessageCryptoHandler cryptoHandler =
+ DecryptionHandler.create(
+ createDefaultCMM(keyring),
+ commitmentPolicy_,
+ SignaturePolicy.AllowEncryptForbidDecrypt,
+ maxEncryptedDataKeys_);
+ return new CryptoInputStream(is, cryptoHandler);
+ }
+
+ /**
+ * Returns a {@link CryptoInputStream} which decrypts the data after reading it from the
+ * underlying {@link InputStream}. This version only accepts unsigned messages.
+ *
+ * @see #decryptData(IKeyring, byte[], Map)
+ * @see javax.crypto.CipherInputStream
+ */
+ public > CryptoInputStream createUnsignedMessageDecryptingStream(
+ final IKeyring keyring, final InputStream is, final Map encryptionContext) {
+ final MessageCryptoHandler cryptoHandler =
+ DecryptionHandler.create(
+ createDefaultCMM(keyring),
+ commitmentPolicy_,
+ SignaturePolicy.AllowEncryptForbidDecrypt,
+ maxEncryptedDataKeys_,
+ encryptionContext);
+ return new CryptoInputStream(is, cryptoHandler);
+ }
+
/**
* Returns a {@link CryptoOutputStream} which decrypts the data prior to passing it onto the
* underlying {@link OutputStream}. This version only accepts unsigned messages.
@@ -727,6 +1206,7 @@ public > CryptoInputStream createUnsignedMessageDecryp
* @see #decryptData(CryptoMaterialsManager, byte[])
* @see javax.crypto.CipherOutputStream
*/
+ @Deprecated
public CryptoOutputStream> createUnsignedMessageDecryptingStream(
final CryptoMaterialsManager materialsManager, final OutputStream os) {
final MessageCryptoHandler cryptoHandler =
@@ -738,6 +1218,45 @@ public CryptoOutputStream> createUnsignedMessageDecryptingStream(
return new CryptoOutputStream(os, cryptoHandler);
}
+ /**
+ * Returns a {@link CryptoOutputStream} which decrypts the data prior to passing it onto the
+ * underlying {@link OutputStream}. This version only accepts unsigned messages.
+ *
+ * @see #decryptData(ICryptographicMaterialsManager, byte[])
+ * @see javax.crypto.CipherOutputStream
+ */
+ public CryptoOutputStream> createUnsignedMessageDecryptingStream(
+ final ICryptographicMaterialsManager materialsManager, final OutputStream os) {
+ final MessageCryptoHandler cryptoHandler =
+ DecryptionHandler.create(
+ materialsManager,
+ commitmentPolicy_,
+ SignaturePolicy.AllowEncryptForbidDecrypt,
+ maxEncryptedDataKeys_);
+ return new CryptoOutputStream(os, cryptoHandler);
+ }
+
+ /**
+ * Returns a {@link CryptoOutputStream} which decrypts the data prior to passing it onto the
+ * underlying {@link OutputStream}. This version only accepts unsigned messages.
+ *
+ * @see #decryptData(ICryptographicMaterialsManager, byte[], Map)
+ * @see javax.crypto.CipherOutputStream
+ */
+ public CryptoOutputStream> createUnsignedMessageDecryptingStream(
+ final ICryptographicMaterialsManager materialsManager,
+ final OutputStream os,
+ final Map encryptionContext) {
+ final MessageCryptoHandler cryptoHandler =
+ DecryptionHandler.create(
+ materialsManager,
+ commitmentPolicy_,
+ SignaturePolicy.AllowEncryptForbidDecrypt,
+ maxEncryptedDataKeys_,
+ encryptionContext);
+ return new CryptoOutputStream(os, cryptoHandler);
+ }
+
/**
* Returns a {@link CryptoInputStream} which decrypts the data after reading it from the
* underlying {@link InputStream}. This version only accepts unsigned messages.
@@ -745,6 +1264,7 @@ public CryptoOutputStream> createUnsignedMessageDecryptingStream(
* @see #encryptData(CryptoMaterialsManager, byte[], Map)
* @see javax.crypto.CipherInputStream
*/
+ @Deprecated
public CryptoInputStream> createUnsignedMessageDecryptingStream(
final CryptoMaterialsManager materialsManager, final InputStream is) {
final MessageCryptoHandler cryptoHandler =
@@ -756,6 +1276,45 @@ public CryptoInputStream> createUnsignedMessageDecryptingStream(
return new CryptoInputStream(is, cryptoHandler);
}
+ /**
+ * Returns a {@link CryptoInputStream} which decrypts the data after reading it from the
+ * underlying {@link InputStream}. This version only accepts unsigned messages.
+ *
+ * @see #encryptData(ICryptographicMaterialsManager, byte[])
+ * @see javax.crypto.CipherInputStream
+ */
+ public CryptoInputStream> createUnsignedMessageDecryptingStream(
+ final ICryptographicMaterialsManager materialsManager, final InputStream is) {
+ final MessageCryptoHandler cryptoHandler =
+ DecryptionHandler.create(
+ materialsManager,
+ commitmentPolicy_,
+ SignaturePolicy.AllowEncryptForbidDecrypt,
+ maxEncryptedDataKeys_);
+ return new CryptoInputStream(is, cryptoHandler);
+ }
+
+ /**
+ * Returns a {@link CryptoInputStream} which decrypts the data after reading it from the
+ * underlying {@link InputStream}. This version only accepts unsigned messages.
+ *
+ * @see #encryptData(ICryptographicMaterialsManager, byte[], Map)
+ * @see javax.crypto.CipherInputStream
+ */
+ public CryptoInputStream> createUnsignedMessageDecryptingStream(
+ final ICryptographicMaterialsManager materialsManager,
+ final InputStream is,
+ final Map encryptionContext) {
+ final MessageCryptoHandler cryptoHandler =
+ DecryptionHandler.create(
+ materialsManager,
+ commitmentPolicy_,
+ SignaturePolicy.AllowEncryptForbidDecrypt,
+ maxEncryptedDataKeys_,
+ encryptionContext);
+ return new CryptoInputStream(is, cryptoHandler);
+ }
+
/**
* Returns a {@link CryptoOutputStream} which decrypts the data prior to passing it onto the
* underlying {@link OutputStream}.
@@ -771,6 +1330,7 @@ public CryptoInputStream> createUnsignedMessageDecryptingStream(
* @see #createUnsignedMessageDecryptingStream(MasterKeyProvider, OutputStream)
* @see javax.crypto.CipherOutputStream
*/
+ @Deprecated
public > CryptoOutputStream createDecryptingStream(
final MasterKeyProvider provider, final OutputStream os) {
final MessageCryptoHandler cryptoHandler =
@@ -782,6 +1342,58 @@ public > CryptoOutputStream createDecryptingStream(
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(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 > CryptoOutputStream createDecryptingStream(
+ final IKeyring keyring, final OutputStream os) {
+ final MessageCryptoHandler cryptoHandler =
+ DecryptionHandler.create(
+ createDefaultCMM(keyring),
+ 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(IKeyring,
+ * byte[], Map) method instead, or
+ * #createUnsignedMessageDecryptingStream(IKeyring, OutputStream, Map) if you do
+ * not need to decrypt signed messages.
+ *
+ * @see #decryptData(IKeyring, byte[], Map)
+ * @see #createUnsignedMessageDecryptingStream(IKeyring, OutputStream, Map)
+ * @see javax.crypto.CipherOutputStream
+ */
+ public > CryptoOutputStream createDecryptingStream(
+ final IKeyring keyring, final OutputStream os, final Map encryptionContext) {
+ final MessageCryptoHandler cryptoHandler =
+ DecryptionHandler.create(
+ createDefaultCMM(keyring),
+ commitmentPolicy_,
+ SignaturePolicy.AllowEncryptAllowDecrypt,
+ maxEncryptedDataKeys_,
+ encryptionContext);
+ return new CryptoOutputStream(os, cryptoHandler);
+ }
+
/**
* Returns a {@link CryptoInputStream} which decrypts the data after reading it from the
* underlying {@link InputStream}.
@@ -796,6 +1408,7 @@ public > CryptoOutputStream createDecryptingStream(
* @see #createUnsignedMessageDecryptingStream(MasterKeyProvider, InputStream)
* @see javax.crypto.CipherInputStream
*/
+ @Deprecated
public > CryptoInputStream createDecryptingStream(
final MasterKeyProvider provider, final InputStream is) {
final MessageCryptoHandler cryptoHandler =
@@ -807,6 +1420,57 @@ public > CryptoInputStream createDecryptingStream(
return new CryptoInputStream(is, cryptoHandler);
}
+ /**
+ * Returns a {@link CryptoInputStream} which decrypts the data after reading it from the
+ * underlying {@link InputStream}.
+ *
+ * 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 > CryptoInputStream createDecryptingStream(
+ final IKeyring keyring, final InputStream is) {
+ final MessageCryptoHandler cryptoHandler =
+ DecryptionHandler.create(
+ createDefaultCMM(keyring),
+ commitmentPolicy_,
+ SignaturePolicy.AllowEncryptAllowDecrypt,
+ maxEncryptedDataKeys_);
+ return new CryptoInputStream(is, cryptoHandler);
+ }
+
+ /**
+ * Returns a {@link CryptoInputStream} which decrypts the data after reading it from the
+ * underlying {@link InputStream}.
+ *
+ * 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) method instead, or #createUnsignedMessageDecryptingStream(IKeyring,
+ * InputStream, Map) if you do not need to decrypt signed messages.
+ *
+ * @see #decryptData(IKeyring, byte[], Map)
+ * @see #createUnsignedMessageDecryptingStream(IKeyring, InputStream, Map)
+ * @see javax.crypto.CipherInputStream
+ */
+ public > CryptoInputStream createDecryptingStream(
+ final IKeyring keyring, final InputStream is, final Map encryptionContext) {
+ final MessageCryptoHandler cryptoHandler =
+ DecryptionHandler.create(
+ createDefaultCMM(keyring),
+ commitmentPolicy_,
+ SignaturePolicy.AllowEncryptAllowDecrypt,
+ maxEncryptedDataKeys_,
+ encryptionContext);
+ return new CryptoInputStream(is, cryptoHandler);
+ }
+
/**
* Returns a {@link CryptoOutputStream} which decrypts the data prior to passing it onto the
* underlying {@link OutputStream}.
@@ -822,6 +1486,7 @@ public > CryptoInputStream