Google Tinkのガイド

  • link:/category/security-2/ [セキュリティ]

1. 前書き

現在、多くの開発者は暗号化技術を使用してユーザーデータを保護しています。
暗号化では、小さな実装エラーが深刻な結果をもたらす可能性があり、暗号化を正しく実装する方法を理解することは複雑で時間のかかる作業です。
*このチュートリアルでは、https://github.com/google/tink [Tink]について説明します。これは、安全で暗号化されたコードの実装に役立つ多言語のクロスプラットフォーム暗号化ライブラリです。*

2. 依存関係

MavenまたはGradleを使用してTinkをインポートできます。
チュートリアルでは、https://search.maven.org/search?q = g:com.google.crypto.tink%20AND%20a:tink&core = gav [TinkのMaven依存関係]を追加します。
<dependency>
    <groupId>com.google.crypto.tink</groupId>
    <artifactId>tink</artifactId>
    <version>1.2.2</version>
</dependency>
代わりにGradleを使用することもできますが:
dependencies {
  compile 'com.google.crypto.tink:tink:latest'
}

3. 初期化

  • Tink APIを使用する前に、それらを初期化する必要があります。*

    Tinkのすべてのプリミティブのすべての実装を使用する必要がある場合は、_TinkConfig.register()_メソッドを使用できます。
TinkConfig.register();
一方、たとえば、AEADプリミティブのみが必要な場合は、_AeadConfig.register()_メソッドを使用できます。
AeadConfig.register();
実装ごとにカスタマイズ可能な初期化も提供されます。

*4. Tink Primitives *

*ライブラリが使用する主なオブジェクトはプリミティブと呼ばれ、タイプによって異なる暗号化機能が含まれます。*
プリミティブには複数の実装を含めることができます。
原始的
実装
AEAD
AES-EAX、AES-GCM、AES-CTR-HMAC、KMSエンベロープ、CHACHA20-POLY1305
ストリーミングAEAD
AES-GCM-HKDF-ストリーミング、AES-CTR-HMAC-ストリーミング
確定的AEAD
AEAD:AES-SIV
MAC
HMAC-SHA2
デジタル署名
NIST曲線上のECDSA、ED25519
ハイブリッド暗号化
AEADおよびHKDFを使用するECIES(NaCl CryptoBox)
プリミティブを取得するには、対応するファクトリクラスの_getPrimitive()_メソッドを呼び出して、_KeysetHandle_を渡します。
Aead aead = AeadFactory.getPrimitive(keysetHandle);

4.1. KeysetHandle

暗号化機能を提供するには、各プリミティブにすべてのキーマテリアルとパラメーターを含むキー構造が必要です。
Tinkは、キーセットをいくつかの追加のパラメーターとメタデータでラップするオブジェクト(__KeysetHandle – __)を提供します。
したがって、プリミティブをインスタンス化する前に、__ KeysetHandle __objectを作成する必要があります。
KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES256_GCM);
そして、キーを生成した後、それを永続化したい場合があります。
String keysetFilename = "keyset.json";
CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withFile(new File(keysetFilename)));
その後、後でロードできます。
String keysetFilename = "keyset.json";
KeysetHandle keysetHandle = CleartextKeysetHandle.read(JsonKeysetReader.withFile(new File(keysetFilename)));

5. 暗号化

Tinkは、AEADアルゴリズムを適用する複数の方法を提供します。 見てみましょう。

* 5.1。 AEAD *

AEADは、関連データによる認証済み暗号化を提供します。つまり、*プレーンテキストを暗号化し、オプションで、認証する必要があるが暗号化しない関連データを提供できます*。
このアルゴリズムは、関連データの信頼性と整合性を保証しますが、機密性は保証しません。
以前に見たように、AEAD実装の1つでデータを暗号化するには、ライブラリを初期化し、_keysetHandle:_を作成する必要があります
AeadConfig.register();
KeysetHandle keysetHandle = KeysetHandle.generateNew(
  AeadKeyTemplates.AES256_GCM);
それが完了したら、プリミティブを取得して目的のデータを暗号化できます。
String plaintext = "baeldung";
String associatedData = "Tink";

Aead aead = AeadFactory.getPrimitive(keysetHandle);
byte[] ciphertext = aead.encrypt(plaintext.getBytes(), associatedData.getBytes());
次に、_decrypt()_メソッドを使用して_ciphertext_を復号化できます。
String decrypted = new String(aead.decrypt(ciphertext, associatedData.getBytes()));

* 5.2。 ストリーミングAEAD *

同様に、*暗号化されるデータが1ステップで処理するには大きすぎる場合、ストリーミングAEADプリミティブを使用できます*:
AeadConfig.register();
KeysetHandle keysetHandle = KeysetHandle.generateNew(
  StreamingAeadKeyTemplates.AES128_CTR_HMAC_SHA256_4KB);
StreamingAead streamingAead = StreamingAeadFactory.getPrimitive(keysetHandle);

FileChannel cipherTextDestination = new FileOutputStream("cipherTextFile").getChannel();
WritableByteChannel encryptingChannel =
  streamingAead.newEncryptingChannel(cipherTextDestination, associatedData.getBytes());

ByteBuffer buffer = ByteBuffer.allocate(CHUNK_SIZE);
InputStream in = new FileInputStream("plainTextFile");

while (in.available() > 0) {
    in.read(buffer.array());
    encryptingChannel.write(buffer);
}

encryptingChannel.close();
in.close();
基本的に、これを実現するには_WriteableByteChannel_が必要でした。
したがって、_cipherTextFile、_を復号化するには、_ReadableByteChannel_を使用します。
FileChannel cipherTextSource = new FileInputStream("cipherTextFile").getChannel();
ReadableByteChannel decryptingChannel =
  streamingAead.newDecryptingChannel(cipherTextSource, associatedData.getBytes());

OutputStream out = new FileOutputStream("plainTextFile");
int cnt = 1;
do {
    buffer.clear();
    cnt = decryptingChannel.read(buffer);
    out.write(buffer.array());
} while (cnt>0);

decryptingChannel.close();
out.close();

6. ハイブリッド暗号化

対称暗号化に加えて、Tinkはハイブリッド暗号化のためのいくつかのプリミティブを実装しています。
*ハイブリッド暗号化により、対称キーの効率と非対称キーの利便性を得ることができます。*
簡単に言うと、対称キーを使用してプレーンテキストを暗号化し、公開キーを使用して対称キーのみを暗号化します。*
これは、送信者のID信頼性ではなく、機密性のみを提供することに注意してください。
それでは、_HybridEncrypt_と_HybridDecrypt:_の使用方法を見てみましょう。
TinkConfig.register();

KeysetHandle privateKeysetHandle = KeysetHandle.generateNew(
  HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256);
KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle();

String plaintext = "baeldung";
String contextInfo = "Tink";

HybridEncrypt hybridEncrypt = HybridEncryptFactory.getPrimitive(publicKeysetHandle);
HybridDecrypt hybridDecrypt = HybridDecryptFactory.getPrimitive(privateKeysetHandle);

byte[] ciphertext = hybridEncrypt.encrypt(plaintext.getBytes(), contextInfo.getBytes());
byte[] plaintextDecrypted = hybridDecrypt.decrypt(ciphertext, contextInfo.getBytes());
_contextInfo_は、コンテキストからの暗黙のパブリックデータであり、_null_または空にするか、AEAD暗号化の「関連データ」入力またはHKDFの「CtxInfo」入力として使用できます。
_ciphertext_を使用すると、_contextInfo_の整合性をチェックできますが、その機密性または信頼性はチェックできません。

7. メッセージ認証コード

  • Tinkはメッセージ認証コードまたはMACもサポートしています。*

    MACは、メッセージの認証に使用できる数バイトのブロックです。
    MACを作成し、その信頼性を検証する方法を見てみましょう。
TinkConfig.register();

KeysetHandle keysetHandle = KeysetHandle.generateNew(
  MacKeyTemplates.HMAC_SHA256_128BITTAG);

String data = "baeldung";

Mac mac = MacFactory.getPrimitive(keysetHandle);

byte[] tag = mac.computeMac(data.getBytes());
mac.verifyMac(tag, data.getBytes());
データが本物ではない場合、_verifyMac()_メソッドは_GeneralSecurityException._をスローします。

8. デジタル署名

暗号化APIと同様に、Tinkはデジタル署名をサポートしています。
*デジタル署名を実装するために、ライブラリはデータの署名に_PublicKeySign_プリミティブを使用し、検証に_PublickeyVerify_を使用します:*
TinkConfig.register();

KeysetHandle privateKeysetHandle = KeysetHandle.generateNew(SignatureKeyTemplates.ECDSA_P256);
KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle();

String data = "baeldung";

PublicKeySign signer = PublicKeySignFactory.getPrimitive(privateKeysetHandle);
PublicKeyVerify verifier = PublicKeyVerifyFactory.getPrimitive(publicKeysetHandle);

byte[] signature = signer.sign(data.getBytes());
verifier.verify(signature, data.getBytes());
以前の暗号化方法と同様に、署名が無効の場合、_GeneralSecurityException._が発生します

9. 結論

この記事では、Java実装を使用してGoogle Tinkライブラリを紹介しました。
データの暗号化と復号化に使用する方法と、その整合性と信頼性を保護する方法を見てきました。 さらに、デジタル署名APIを使用してデータに署名する方法を見てきました。
いつものように、サンプルコードはhttps://github.com/eugenp/tutorials/tree/master/libraries-security[GitHub上]で入手できます。