

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

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

이 주제에서는 AWS Encryption SDK for Java를 설치 및 사용하는 방법을 설명합니다. 를 사용한 프로그래밍에 대한 자세한 내용은 GitHub의 [aws-encryption-sdk-java](https://github.com/aws/aws-encryption-sdk-java/) 리포지토리를 AWS Encryption SDK for Java참조하세요. API 설명서를 보려면 AWS Encryption SDK for Java용 [Javadoc](https://aws.github.io/aws-encryption-sdk-java/)을 참조하세요.

**Topics**
+ [사전 조건](#java-prerequisites)
+ [설치](#java-installation)
+ [예제](java-example-code.md)

## 사전 조건
<a name="java-prerequisites"></a>

를 설치하기 전에 다음 사전 조건이 있는지 AWS Encryption SDK for Java확인합니다.

**Java 개발 환경**  
Java 8 이상이 필요합니다. Oracle 웹 사이트에서 [Java SE 다운로드](https://www.oracle.com/java/technologies/downloads/)로 이동한 다음 Java SE Development Kit(JDK)를 다운로드하여 설치합니다.  
Oracle JDK를 사용하는 경우 [Java Cryptography Extension(JCE) Unlimited Strength Jurisdiction Policy File](http://www.oracle.com/java/technologies/javase-jce8-downloads.html)도 다운로드하여 설치해야 합니다.

**Bouncy Castle**  
에는 [Bouncy Castle](https://www.bouncycastle.org/download/bouncy-castle-java/)이 AWS Encryption SDK for Java 필요합니다.  
+ AWS Encryption SDK for Java 버전 1.6.1 이상에서는 Bouncy Castle을 사용하여 암호화 객체를 직렬화하고 역직렬화합니다. 이 요구 사항을 충족하기 위해 Bouncy Castle 또는 [Bouncy Castle FIPS](https://www.bouncycastle.org/about/bouncy-castle-fips-faq/)를 사용할 수 있습니다. Bouncy Castle FIPS 설치 및 구성에 대한 도움말은 [BC FIPS 설명서](https://www.bouncycastle.org/documentation/), 특히 **사용 설명서** 및 **보안 정책** PDF를 참조하세요.
+ 이전 버전의 에서는 Java용 Bouncy Castle의 암호화 API를 AWS Encryption SDK for Java 사용합니다. 이 요구 사항은 비 FIPS Bouncy Castle만 만족합니다.
Bouncy Castle이 없는 경우 [Java용 Bouncy Castle 다운로드](https://bouncycastle.org/download/bouncy-castle-java/)로 이동하여 JDK에 해당하는 공급자 파일을 다운로드합니다. [Apache Maven](https://maven.apache.org/)을 사용하여 표준 Bouncy Castle 공급자([bcprov-ext-jdk15on](https://mvnrepository.com/artifact/org.bouncycastle/bcprov-ext-jdk15on))용 아티팩트 또는 Bouncy Castle FIPS([bc-fips](https://mvnrepository.com/artifact/org.bouncycastle/bc-fips))용 아티팩트를 가져올 수 있습니다.

**AWS SDK for Java**  
의 버전 3.*x*에는 AWS KMS 키링을 사용하지 AWS SDK for Java 2.x않더라도가 AWS Encryption SDK for Java 필요합니다.  
버전 2.*x* 이하 AWS Encryption SDK for Java 에서는가 필요하지 않습니다 AWS SDK for Java. 그러나 [AWS Key Management Service](https://aws.amazon.com/kms/) (AWS KMS)를 마스터 키 공급자로 사용하려면 AWS SDK for Java 가 필요합니다. AWS Encryption SDK for Java 버전 2.4.0부터는 1.x 및 2.x용 AWS SDK for Java. AWS Encryption SDK code 버전 AWS SDK for Java 1.x 및 2.x를 모두 AWS Encryption SDK for Java 지원하며 상호 운용할 수 있습니다. 예를 들어, AWS SDK for Java 가1.x를 지원하는 AWS Encryption SDK 코드로 데이터를 암호화하고가 지원하는 코드 AWS SDK for Java 2.x (또는 그 반대)를 사용하여 복호화할 수 있습니다. 2.4.0 AWS Encryption SDK for Java 이전 버전의는 AWS SDK for Java 1.x만 지원합니다. 버전 업데이트에 대한 자세한 내용은 섹션을 AWS Encryption SDK참조하세요[마이그레이션 AWS Encryption SDK](migration.md).  
 AWS Encryption SDK for Java 코드를 AWS SDK for Java 1.x에서 로 업데이트할 때 [`AWSKMS` 인터페이스](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/kms/package-summary.html) in AWS SDK for Java 1.x에 대한 참조를 [`KmsClient` 인터페이스](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kms/package-summary.html) in에 대한 참조로 AWS SDK for Java 2.x바꿉니다 AWS SDK for Java 2.x. AWS Encryption SDK for Java 는 [`KmsAsyncClient` 인터페이스를](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kms/KmsAsyncClient.html) 지원하지 않습니다. 또한 `kms` 네임스페이스 대신 `kmssdkv2` 네임스페이스의 AWS KMS관련 객체를 사용하도록 코드를 업데이트하세요.  
를 설치하려면 Apache Maven을 AWS SDK for Java사용합니다.  
+ [전체 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) `pom.xml` 파일에 선언하세요.
+  AWS SDK for Java 1.x의 AWS KMS 모듈에 대해서만 종속성을 생성하려면 [특정 모듈 지정](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-project-maven.html#modules-dependencies) 지침을 따르고를 `artifactId`로 설정합니다`aws-java-sdk-kms`.
+  AWS SDK for Java 2.x의 AWS KMS 모듈에 대해서만 종속성을 생성하려면 [특정 모듈 지정](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup-project-maven.html#modules-dependencies) 지침을 따르세요. `groupId`를 `software.amazon.awssdk`로, `artifactId`를 `kms`로 설정합니다.
자세한 내용은 AWS SDK for Java 2.x 개발자 안내서[의 AWS SDK for Java 1.x와 2.x의 차이점](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration-whats-different.html)을 참조하세요.  
 AWS Encryption SDK 개발자 안내서의 Java 예제에서는를 사용합니다 AWS SDK for Java 2.x.

## 설치
<a name="java-installation"></a>

 AWS Encryption SDK for Java의 최신 버전을 설치합니다.

**참고**  
2.0.0 AWS Encryption SDK for Java 이전의 모든 버전은 [end-of-support 단계에](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle) 있습니다.  
코드나 데이터를 변경하지 않고 버전 2.0.*x* 이상에서 AWS Encryption SDK for Java 의 최신 버전으로 안전하게 업데이트할 수 있습니다. 그러나 버전 2.0.*x*에 도입된 [새로운 보안 기능](about-versions.md#version-2)은 이하 버전과 호환되지 않습니다. 1.7.*x* 이하 버전에서 2.0.*x* 이상 버전으로 업데이트하려면 먼저 AWS Encryption SDK의 최신 1.*x* 버전으로 업데이트해야 합니다. 자세한 내용은 [마이그레이션 AWS Encryption SDK](migration.md)을 참조하세요.

다음과 같은 AWS Encryption SDK for Java 방법으로를 설치할 수 있습니다.

**직접**  
를 설치하려면 [aws-encryption-sdk-java](https://github.com/aws/aws-encryption-sdk-java/) GitHub 리포지토리를 AWS Encryption SDK for Java복제하거나 다운로드합니다.

**Apache Maven 사용**  
 AWS Encryption SDK for Java 는 다음 종속성 정의와 함께 [Apache Maven](https://maven.apache.org/)을 통해 사용할 수 있습니다.  

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

SDK를 설치한 후에는 이 가이드의 [예제 Java 코드](java-example-code.md)와 [GitHub의 Javadoc](https://aws.github.io/aws-encryption-sdk-java/)을 살펴보는 것부터 시작하세요.

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

다음 예제에서는를 사용하여 데이터를 암호화하고 복호화 AWS Encryption SDK for Java 하는 방법을 보여줍니다. 이 예제에서는 버전 3.*x* 이상을 사용하는 방법을 보여줍니다 AWS Encryption SDK for Java. 의 버전 3.*x*에는가 AWS Encryption SDK for Java 필요합니다 AWS SDK for Java 2.x. 의 버전 3.*x*는 [마스터 키 공급자](concepts.md#master-key-provider)를 키링으로 AWS Encryption SDK for Java 대체합니다. [키링 및 마스터 키 공급자](concepts.md#keyring) 이하 버전을 사용하는 예제의 경우 GitHub의 [aws-encryption-sdk-java](https://github.com/aws/aws-encryption-sdk-java/) 리포지토리의 [릴리스](https://github.com/aws/aws-encryption-sdk-java/releases) 목록에서 해당하는 릴리스를 찾을 수 있습니다.

**Topics**
+ [문자열](#java-example-strings)
+ [바이트 스트림](#java-example-streams)
+ [여러 마스터 키 공급자를 사용하는 바이트 스트림](#java-example-multiple-providers)

## 문자열 암호화 및 복호화
<a name="java-example-strings"></a>

다음 예제에서는의 버전 3.*x* AWS Encryption SDK for Java 를 사용하여 문자열을 암호화하고 복호화하는 방법을 보여줍니다. 문자열을 사용하기 전에 바이트 배열로 변환하세요.

이 예제에서는 [AWS KMS 키링](use-kms-keyring.md)을 사용합니다. AWS KMS 키링으로 암호화할 때 키 ID, 키 ARN, 별칭 이름 또는 별칭 ARN을 사용하여 KMS 키를 식별할 수 있습니다. 복호화할 때 키 ARN을 사용하여 KMS 키를 식별해야 합니다.

`encryptData()` 메서드를 호출하면 사이퍼텍스트, 암호화된 데이터 키 및 암호화 컨텍스트를 포함하는 [암호화된 메시지](concepts.md#message)(`CryptoResult`)가 반환됩니다. `CryptoResult` 객체에서 `getResult`를 호출하면 `decryptData()` 메서드에 전달할 수 있는 [암호화된 메시지](message-format.md)의 base-64 인코딩 문자열 버전이 반환됩니다.

마찬가지로 `decryptData()`를 호출할 때 반환되는 `CryptoResult` 객체에는 일반 텍스트 메시지와 AWS KMS key ID가 포함됩니다. 애플리케이션이 일반 텍스트를 반환하기 전에 암호화된 메시지의 AWS KMS key ID와 암호화 컨텍스트가 예상한 것인지 확인합니다.

```
// 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);
  }
}
```

## 바이트 스트림 암호화 및 복호화
<a name="java-example-streams"></a>

다음 예제에서는를 사용하여 바이트 스트림을 암호화하고 복호화 AWS Encryption SDK 하는 방법을 보여줍니다.

이 예제에서는 [원시 AES 키링](use-raw-aes-keyring.md)을 사용합니다.

암호화할 때 이 예제에서는 `AwsCrypto.builder() .withEncryptionAlgorithm()` 메서드를 사용하여 [디지털 서명](concepts.md#digital-sigs)이 없는 알고리즘 제품군을 지정합니다. 이 예제에서는 복호화할 때 사이퍼텍스트에 서명이 없는지 확인하기 위해 `createUnsignedMessageDecryptingStream()` 메서드를 사용합니다. 디지털 서명이 있는 사이퍼텍스트가 발생하면 `createUnsignedMessageDecryptingStream()` 메서드가 실패합니다.

디지털 서명이 포함된 기본 알고리즘 제품군으로 암호화하는 경우 다음 예제와 같이 `createDecryptingStream()` 메서드를 대신 사용하세요.

```
// 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");
    }
}
```

## 다중 키 링을 사용하여 바이트 스트림 암호화 및 복호화
<a name="java-example-multiple-providers"></a>

다음 예제에서는 [다중 키 링](use-multi-keyring.md)과 AWS Encryption SDK 함께를 사용하는 방법을 보여줍니다. 다중 키링을 사용하여 데이터를 암호화하는 경우 해당 키링의 모든 래핑 키로 해당 데이터를 복호화할 수 있습니다. 이 예제에서는 [AWS KMS 키링](use-kms-keyring.md)과 [Raw RSA 키링](use-raw-rsa-keyring.md)을 하위 키링으로 사용합니다.

이 예제는 [디지털 서명](concepts.md#digital-sigs)이 포함된 [기본 알고리즘 제품군](supported-algorithms.md)을 사용하여 암호화합니다. 스트리밍할 때는 무결성 검사 후 디지털 서명을 확인하기 전에 일반 텍스트를 AWS Encryption SDK 릴리스합니다. 서명이 확인될 때까지 일반 텍스트를 사용하지 않도록 이 예제에서는 일반 텍스트를 버퍼링하고 복호화 및 확인이 완료될 때만 디스크에 씁니다.

```
// 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());

    }
}
```