0
0

【Java初心者】Google Tinkを使ったAEADテキスト暗号化

Last updated at Posted at 2024-01-08

暗号を安全に使用するために

Google Tinkのサイト( https://github.com/google/tink )のIntroductionには

あなたのアプリケーションで暗号を使用することは、暗闇でチェーンソーを投げるような感覚になるはずはありません。Tinkは、Googleの暗号学者やセキュリティエンジニアのグループによって書かれた暗号ライブラリです。これは、Googleの製品チームと協力し、実装の弱点を修正し、暗号のバックグラウンドがなくても安全に使用できるシンプルなAPIを提供するために生まれました。

と書かれています。「暗闇でチェーンソー」という表現はユニークですが、暗号の知識がなくても安全に使用できるAPIを作るという思想は素晴らしいと思います。

AEADとは

Wikipediaにはこうあります( https://ja.wikipedia.org/wiki/%E8%AA%8D%E8%A8%BC%E4%BB%98%E3%81%8D%E6%9A%97%E5%8F%B7 )

認証付き暗号(AE: Authenticated Encryption あるいは AEAD: Authenticated Encryption with Associated Data) とは、データの秘匿性、完全性、および認証性を同時に提供する暗号利用モードである。利用の容易な API ひとつでこうした特性が提供されるうえ、復号すると同時に完全性も検証される。

共通鍵暗号方式ではありますが、データの暗号化による「秘匿性」と、復号時に元のデータとの不整合がないことの両方を満たす方式です。

Javaで書いてみました

Tinkは、バージョンアップのたびに、APIが変わり、以前書いたコードが非推奨となることが多いため、その都度ドキュメントを見ながら修正しています。

以下に示すコードはtink-1.12.0.jarを用いています。依存ライブラリーとして protobuf-java と gson が必要です。

package sample2024;

import com.google.crypto.tink.Aead;
import com.google.crypto.tink.CleartextKeysetHandle;
import com.google.crypto.tink.InsecureSecretKeyAccess;
import com.google.crypto.tink.JsonKeysetReader;
import com.google.crypto.tink.KeyTemplates;
import com.google.crypto.tink.KeysetHandle;
import com.google.crypto.tink.TinkJsonProtoKeysetFormat;
import com.google.crypto.tink.aead.AeadConfig;
import java.io.IOException;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.util.Base64;

public class AeadTest {

    public static void main(String[] args) {
        try {
            String plainText = "こんにちは"; // 平文テキスト
            String password = "password"; // パスワード
            AeadConfig.register();
            System.out.println("AEAD秘密鍵を生成");
            KeysetHandle privateAeadKeysetHandle = KeysetHandle.generateNew(KeyTemplates.get("AES128_GCM"));
            // 秘密鍵の本体
            String serializedKeyset
                    = TinkJsonProtoKeysetFormat.serializeKeyset(privateAeadKeysetHandle, InsecureSecretKeyAccess.get());
            //
            // 秘密鍵をファイルに保存する場合(セキュリティー上推奨されていません)
            // String aeadKey = "aead_priv.key";
            // Path aeadKeyFile = Paths.get(aeadKey);
            // Files.write(aeadKeyFile, serializedKeyset.getBytes(UTF_8));
            //
            // 秘密鍵をファイルから読み込む(セキュリティー上推奨されていません)
            // serializedKeyset = Files.readString(aeadKeyFile, UTF_8);

            System.out.println("AEAD暗号化します");
            System.out.println("平文:" + plainText);
            KeysetHandle keysetHandle = CleartextKeysetHandle.read(
                    JsonKeysetReader.withString(serializedKeyset));
            Aead aead = keysetHandle.getPrimitive(Aead.class);
            byte[] ciphertext = aead.encrypt(plainText.getBytes(), password.getBytes());
            // Base64でエンコードする
            String AeadEncrypt = Base64.getEncoder().encodeToString(ciphertext);
            System.out.println("AEAD暗号化データ:" + AeadEncrypt);

            System.out.println("AEAD復号化します");

            KeysetHandle dkeysetHandle = CleartextKeysetHandle.read(
                    JsonKeysetReader.withString(serializedKeyset));
            Aead daead = dkeysetHandle.getPrimitive(Aead.class);
            String AeadDecrypt = new String(daead.decrypt(
                    Base64.getDecoder().decode(AeadEncrypt), password.getBytes()));

            System.out.println("AEAD復号化データ:" + AeadDecrypt);
        } catch (IOException | GeneralSecurityException e) {
            System.err.println(e.getMessage());
        }
    }
}

実行結果

AEAD秘密鍵を生成
AEAD暗号化します
平文:こんにちは
AEAD暗号化データ:AVhtWzgUhjHe1Vls0HVPgp7Ajzm+0jDmDeTeKC1iqPx3pwoiuUVMFBKPzogagGAe
AEAD復号化します
AEAD復号化データ:こんにちは
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0