Help us understand the problem. What is going on with this article?

AWS Key Management Serviceでエンベロープ暗号化

More than 1 year has passed since last update.

はじめに

AWS Key Management Service (KMS) とは、データの暗号化に使用する暗号化キーを管理するためのマネージドサービスです。 KMS では、エンベロープ暗号化という暗号化方式を用いることでデータをセキュアに取り扱うことができます。

エンベロープ暗号化の Java での実装例について、日本語のドキュメントが少ないためまとめてみました。

エンベロープ暗号化とは

ざっくり説明すると、

  • データ
  • データを暗号化するための鍵(データキー)
  • 鍵を暗号化するための鍵(マスターキー)

を使い分けることでセキュアにしようよ、と言う仕組みのことを言います。

e076de0e-e74e-0f63-a339-f6d565b89743.png

一般的な暗号化方式では、平文のデータを何らかの鍵を使って暗号化することで保護します。このとき、この鍵がデータとセットで盗まれてしまうと、暗号を解かれてしまい、生のデータを見られてしまいます。そこで、データを暗号化した鍵を、別の鍵でさらに暗号化することでデータをより強固に保護しよう、というのがエンベロープ暗号化の考え方です。

KMS を使ったデータの暗号化は、以下の流れで実現できます。

  • KMS のコンソール画面でマスターキーを生成する
  • マスターキーからデータキーを生成する
  • データキーを使って平文のデータを暗号化する
  • データキーを暗号化する
  • 暗号化済みのデータキーと暗号化済みのデータを大切に保管する

実装例

エンベロープ暗号化の実現方法について、 Java での実装例を以下に示します。

なお、マスターキーは KMS のコンソール画面から事前に生成済み、という前提で話を進めます。マスターキーの生成手順については、AWS のマニュアルDevelopers.IO 等の記事を参考にしてください。

事前準備

KMS の利用にあたっては AWS から SDK が提供されています。ここでは Gradle を介してライブラリを使用する場合の例を示します。 build.gradle に以下の dependency を追加してください。

dependencies {
    compile "com.amazonaws:aws-java-sdk-kms:1.11.202"
}

暗号化

まずは、 AWS のアクセスキー、シークレットキーを使用して AWSKMSClient のインスタンスを生成します。

BasicAWSCredentials credentials = new BasicAWSCredentials("accessKey...", "SecretKey...");
AWSKMSClient client = (AWSKMSClient) AWSKMSClientBuilder.standard()
    .withRegion("ap-northeast-1")
    .withCredentials(new AWSStaticCredentialsProvider(credentials))
    .build();

生成したクライアントを使用して、データキーを生成します。 KeyId に KMS のコンソールから生成したマスターキーの ARN を指定して GenerateDataKeyRequest のインスタンスを生成し、 generateDataKey することでデータキーを取得できます。

GenerateDataKeyRequest generateDataKeyRequest = new GenerateDataKeyRequest()
    .withKeyId("arn:aws:kms:...")
    .withKeySpec(DataKeySpec.AES_128);
GenerateDataKeyResult dataKeyResult = client.generateDataKey(generateDataKeyRequest);

生成したデータキーを使って、平文のデータを暗号化します。ここでは AES を使って暗号化していますが、暗号化方式は任意のものをお使いください。

try {
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE,
                new SecretKeySpec(dataKeyResult.getPlaintext().array(), "AES"));
    String decriptedText = Base64.getEncoder()
        .encodeToString(cipher.doFinal("plainText...".getBytes()));
} catch (Exception e) {
    // do something.
}

生成された decriptedText と 暗号化済みのデータキー(dataKeyResult.getCiphertextBlob() で暗号化済みのものを取得できます)は、 Base64 で encode して、 yaml ファイル等に書き写して保管しておきましょう。

復号化

続いて、暗号化済みデータの復号化の手順です。復号化は、暗号化済みのデータキーから decryptRequest を生成することで行います。

DecryptRequest decryptRequest = new DecryptRequest()
    .withCiphertextBlob(ByteBuffer.wrap(Base64.getDecoder().decode("decryptedDatakey...".getBytes())));
ByteBuffer plainTextKey = client.decrypt(decryptRequest).getPlaintext();

ここまでの手順で、暗号化済みのデータキーを平文のデータキーに戻すことができました。続いて、手に入れたデータキーを用いて暗号化済みのデータを復号化します。

byte[] decodeBase64src = Base64.getDecoder().decode("decryptedText...");
try {
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, plainTextKey);
    String plainText = new String(cipher.doFinal(decodeBase64src));
} catch (Exception e) {
    // do something.
}

取り出した平文のデータキー( plainTextKey )は速やかに破棄しましょう。

plainTextKey.clear();

参考資料

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした