

# AWS Encryption SDK for Java
<a name="java"></a>

This topic explains how to install and use the AWS Encryption SDK for Java. For details about programming with the AWS Encryption SDK for Java, see the [aws-encryption-sdk-java](https://github.com/aws/aws-encryption-sdk-java/) repository on GitHub. For API documentation, see the [Javadoc](https://aws.github.io/aws-encryption-sdk-java/) for the AWS Encryption SDK for Java.

**Topics**
+ [

## Prerequisites
](#java-prerequisites)
+ [

## Installation
](#java-installation)
+ [Examples](java-example-code.md)

## Prerequisites
<a name="java-prerequisites"></a>

Before you install the AWS Encryption SDK for Java, be sure you have the following prerequisites.

**A Java development environment**  
You will need Java 8 or later. On the Oracle website, go to [Java SE Downloads](https://www.oracle.com/java/technologies/downloads/), and then download and install the Java SE Development Kit (JDK).  
If you use the Oracle JDK, you must also download and install the [Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files](http://www.oracle.com/java/technologies/javase-jce8-downloads.html).

**Bouncy Castle**  
The AWS Encryption SDK for Java requires [Bouncy Castle](https://www.bouncycastle.org/download/bouncy-castle-java/).   
+ AWS Encryption SDK for Java versions 1.6.1 and later use Bouncy Castle to serialize and deserialize cryptographic objects. You can use Bouncy Castle or [Bouncy Castle FIPS](https://www.bouncycastle.org/about/bouncy-castle-fips-faq/) to satisfy this requirement. For help installing and configuring Bouncy Castle FIPS, see [BC FIPS Documentation](https://www.bouncycastle.org/documentation/), especially the **User Guides** and **Security Policy** PDFs.
+ Earlier versions of the AWS Encryption SDK for Java use Bouncy Castle's cryptography API for Java. This requirement is satisfied only by non-FIPS Bouncy Castle.
If you don't have Bouncy Castle, go to [Download Bouncy Castle for Java](https://bouncycastle.org/download/bouncy-castle-java/) to download the provider file that corresponds to your JDK. You can also use [Apache Maven](https://maven.apache.org/) to get the artifact for the standard Bouncy Castle provider ([bcprov-ext-jdk15on](https://mvnrepository.com/artifact/org.bouncycastle/bcprov-ext-jdk15on)) or the artifact for Bouncy Castle FIPS ([bc-fips](https://mvnrepository.com/artifact/org.bouncycastle/bc-fips)).

**AWS SDK for Java**  
Version 3.*x* of the AWS Encryption SDK for Java requires the AWS SDK for Java 2.x, even if you don't use AWS KMS keyrings.  
Version 2.*x* or earlier of the AWS Encryption SDK for Java does not require the AWS SDK for Java. However, the AWS SDK for Java is required to use [AWS Key Management Service](https://aws.amazon.com/kms/) (AWS KMS) as a master key provider. Beginning in the AWS Encryption SDK for Java version 2.4.0, the AWS Encryption SDK for Java supports both version 1.x and 2.x of the AWS SDK for Java. AWS Encryption SDK code for the AWS SDK for Java 1.x and 2.x are interoperable. For example, you can encrypt data with AWS Encryption SDK code that supports AWS SDK for Java 1.x and decrypt it using code that supports AWS SDK for Java 2.x (or vice versa). Versions of the AWS Encryption SDK for Java earlier than 2.4.0 support only AWS SDK for Java 1.x. For information about updating your version of the AWS Encryption SDK, see [Migrating your AWS Encryption SDK](migration.md).  
When updating your AWS Encryption SDK for Java code from the AWS SDK for Java 1.x to AWS SDK for Java 2.x, replace references to the [`AWSKMS` interface](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/kms/package-summary.html) in AWS SDK for Java 1.x with references to the [`KmsClient` interface](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kms/package-summary.html) in AWS SDK for Java 2.x. The AWS Encryption SDK for Java does not support the [`KmsAsyncClient` interface](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kms/KmsAsyncClient.html). Also, update your code to use the AWS KMS-related objects in the `kmssdkv2` namespace, instead of the `kms` namespace.   
To install the AWS SDK for Java, use Apache Maven.   
+ To [import the entire AWS SDK for Java](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup-project-maven.html#build-the-entire-sdk-into-your-project) as a dependency, declare it in your `pom.xml` file.
+ To create a dependency only for the AWS KMS module in AWS SDK for Java 1.x, follow the instructions for [specifying particular modules](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-project-maven.html#modules-dependencies), and set the `artifactId` to `aws-java-sdk-kms`.
+ To create a dependency only for the AWS KMS module in AWS SDK for Java 2.x, follow the instructions for [specifying particular modules](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup-project-maven.html#modules-dependencies). Set the `groupId` to `software.amazon.awssdk` and the `artifactId` to `kms`.
For more changes, see [What's different between the AWS SDK for Java 1.x and 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration-whats-different.html) in the AWS SDK for Java 2.x Developer Guide.  
Java examples in the AWS Encryption SDK Developer Guide use the AWS SDK for Java 2.x.

## Installation
<a name="java-installation"></a>

Install the latest version of the AWS Encryption SDK for Java.

**Note**  
All versions of the AWS Encryption SDK for Java earlier than 2.0.0 are in the [end-of-support phase](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle).  
You can safely update from version 2.0.*x* and later to the latest version of the AWS Encryption SDK for Java without any code or data changes. However, [ new security features](about-versions.md#version-2) introduced in version 2.0.*x* are not backward-compatible. To update from versions earlier than 1.7.*x* to version 2.0.*x* and later, you must first update to the latest 1.*x* version of the AWS Encryption SDK. For details, see [Migrating your AWS Encryption SDK](migration.md).

You can install the AWS Encryption SDK for Java in the following ways.

**Manually**  
To install the AWS Encryption SDK for Java, clone or download the [aws-encryption-sdk-java](https://github.com/aws/aws-encryption-sdk-java/) GitHub repository.

**Using Apache Maven**  
The AWS Encryption SDK for Java is available through [Apache Maven](https://maven.apache.org/) with the following dependency definition.  

```
<dependency>
  <groupId>com.amazonaws</groupId>
  <artifactId>aws-encryption-sdk-java</artifactId>
  <version>3.0.0</version>
</dependency>
```

After you install the SDK, get started by looking at the [example Java code](java-example-code.md) in this guide and the [Javadoc on GitHub](https://aws.github.io/aws-encryption-sdk-java/).

# AWS Encryption SDK for Java examples
<a name="java-example-code"></a>

The following examples show you how to use the AWS Encryption SDK for Java to encrypt and decrypt data. These examples show how to use version 3.*x* and later of the AWS Encryption SDK for Java. Version 3.*x* of the AWS Encryption SDK for Java requires the AWS SDK for Java 2.x. Version 3.*x* of the AWS Encryption SDK for Java replaces [master key providers](concepts.md#master-key-provider) with [keyrings](concepts.md#keyring). For examples that use earlier versions, find your release in the [Releases](https://github.com/aws/aws-encryption-sdk-java/releases) list of the [aws-encryption-sdk-java](https://github.com/aws/aws-encryption-sdk-java/) repository on GitHub.

**Topics**
+ [Strings](#java-example-strings)
+ [Byte streams](#java-example-streams)
+ [Byte streams with multiple master key providers](#java-example-multiple-providers)

## Encrypting and decrypting strings
<a name="java-example-strings"></a>

The following example shows you how to use version 3.*x* of the AWS Encryption SDK for Java to encrypt and decrypt strings. Before using the string, convert it into a byte array.

This example uses an [AWS KMS keyring](use-kms-keyring.md). When you encrypt with an AWS KMS keyring, you can use a key ID, key ARN, alias name, or alias ARN to identify the KMS keys. When decrypting, you must use a key ARN to identify KMS keys.

When you call the `encryptData()` method, it returns an [encrypted message](concepts.md#message) (`CryptoResult`) that includes the ciphertext, the encrypted data keys, and the encryption context. When you call `getResult` on the `CryptoResult` object, it returns a base-64-encoded string version of the [encrypted message](message-format.md) that you can pass to the `decryptData()` method.

Similarly, when you call `decryptData()`, the `CryptoResult` object it returns contains the plaintext message and an AWS KMS key ID. Before your application returns the plaintext, verify that the AWS KMS key ID and the encryption context in the encrypted message are the ones that you expect.

```
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package com.amazonaws.crypto.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;

/**
 * Encrypts and then decrypts data using an AWS KMS Keyring.
 *
 * <p>Arguments:
 *
 * <ol>
 *   <li>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
 * </ol>
 */
public class BasicEncryptionKeyringExample {

  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 means this client only encrypts using committing algorithm suites and enforces
    // that the 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.
    // This example creates a multi keyring, which automatically creates the KMS client.
    final MaterialProviders materialProviders =
        MaterialProviders.builder()
            .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
            .build();
    final CreateAwsKmsMultiKeyringInput keyringInput =
        CreateAwsKmsMultiKeyringInput.builder().generator(keyArn).build();
    final IKeyring kmsKeyring = materialProviders.CreateAwsKmsMultiKeyring(keyringInput);

    // 3. Create an encryption context
    // We recommend using an encryption context whenever possible
    // 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<String, String> encryptionContext =
        Collections.singletonMap("ExampleContextKey", "ExampleContextValue");

    // 4. Encrypt the data
    final CryptoResult<byte[], ?> encryptResult =
        crypto.encryptData(kmsKeyring, EXAMPLE_DATA, encryptionContext);
    final byte[] ciphertext = encryptResult.getResult();

    // 5. Decrypt the data
    final CryptoResult<byte[], ?> 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);
  }
}
```

## Encrypting and decrypting byte streams
<a name="java-example-streams"></a>

The following example shows you how to use the AWS Encryption SDK to encrypt and decrypt byte streams.

This example uses a [Raw AES keyring](use-raw-aes-keyring.md).

When encrypting, this example uses the `AwsCrypto.builder() .withEncryptionAlgorithm()` method to specify an algorithm suite without [digital signatures](concepts.md#digital-sigs). When decrypting, to ensure that the ciphertext is unsigned, this example uses the `createUnsignedMessageDecryptingStream()` method. The `createUnsignedMessageDecryptingStream()` method, fails if it encounters a ciphertext with a digital signature. 

If you're encrypting with the default algorithm suite, which includes digital signatures, use the `createDecryptingStream()` method instead, as shown in the next example.

```
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package com.amazonaws.crypto.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;


/**
 * <p>
 * Encrypts and then decrypts a file under a random key.
 *
 * <p>
 * Arguments:
 * <ol>
 * <li>Name of file containing plaintext data to encrypt
 * </ol>
 *
 * <p>
 * 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();
        IKeyring keyring = materialProviders.CreateRawAesKeyring(keyringInput);

        // Instantiate the SDK.
        // This builds the AwsCrypto client with the RequireEncryptRequireDecrypt commitment policy,
        // which means this client only encrypts using committing algorithm suites and enforces
        // that the 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 example encrypts 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 the ciphertext
        Map<String, String> context = Collections.singletonMap("Example", "FileStreaming");

        // 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<JceMasterKey> 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 the data was encrypted using an unsigned algorithm suite, use the recommended
        // createUnsignedMessageDecryptingStream method, which only accepts unsigned messages.
        in = new FileInputStream(srcFile + ".encrypted");
        CryptoInputStream<JceMasterKey> 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");
    }
}
```

## Encrypting and decrypting byte streams with a multi-keyring
<a name="java-example-multiple-providers"></a>

The following example shows you how to use the AWS Encryption SDK with a [multi-keyring](use-multi-keyring.md). When you use a multi-keyring to encrypt data, any of the wrapping keys in any of its keyrings can decrypt that data. This example uses an [AWS KMS keyring](use-kms-keyring.md) and a [Raw RSA keyring](use-raw-rsa-keyring.md) as the child keyrings.

This example encrypts with the [default algorithm suite](supported-algorithms.md), which includes a [digital signature](concepts.md#digital-sigs). When streaming, the AWS Encryption SDK releases plaintext after integrity checks, but before it has verified the digital signature. To avoid using the plaintext until the signature is verified, this example buffers the plaintext, and writes it to disk only when decryption and verification are complete. 

```
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package com.amazonaws.crypto.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;

/**
 * <p>
 * Encrypts a file using both AWS KMS Key and an asymmetric key pair.
 *
 * <p>
 * Arguments:
 * <ol>
 * <li>Key ARN: For help finding the Amazon Resource Name (ARN) of your AWS KMS key,
 *   see 'Viewing Keys' at http://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html
 *
 * <li>Name of file containing plaintext data to encrypt
 * </ol>
 * <p>
 * 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.
 * <p>
 * The sample encrypts data under both an AWS KMS key and an "escrowed" RSA key pair
 * so that either key alone can decrypt it. You might commonly use the AWS KMS key for decryption. However,
 * at any time, you can use the private RSA key to decrypt the ciphertext independent of AWS KMS.
 * <p>
 * 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 key and the escrowed public key
        // 1. Instantiate the SDK
        // This builds the AwsCrypto client with the RequireEncryptRequireDecrypt commitment policy,
        // which means this client only encrypts using committing algorithm suites and enforces
        // that the 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.
        // This example creates a multi keyring, which automatically creates the KMS client.
        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. Encrypt the file
        // To simplify this code example, we omit the encryption context. Production code should always 
        // use an encryption context. 
        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 key and the escrow public key. 

        // 1. Instantiate the SDK.
        // This builds the AwsCrypto client with the RequireEncryptRequireDecrypt commitment policy,
        // which means this client only encrypts using committing algorithm suites and enforces
        // that the 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.
        // This example creates a multi keyring, which automatically creates the KMS client.
        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 this code example, we omit the encryption context. Production code should always 
        // use an encryption context. 
        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 this code example, we omit the encryption context. Production code should always 
        // use an encryption context. 
        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());

    }
}
```