このページでは、鍵とプリミティブ出力の Tink のワイヤー形式について説明します。このドキュメントは、Tink に言語を追加したい暗号学者と、ワイヤー互換モードを必要とする他の高レベルの暗号ライブラリのメンテナを対象としています。一般の視聴者を対象としたものではありません。
鍵セットのシリアル化
Tink は Google protobuf を使用して鍵セットをシリアル化します。
- バイナリ シリアル化された鍵セットは、tink.proto で定義されたシリアル化された Keyset proto です。鍵の KeyData 値プロパティは、対応する鍵タイプのシリアル化された proto です。
- JSON シリアル化キーセットは、JSON 形式でシリアル化された Keyset proto です。KeyData の値は、シリアル化された バイナリ プロトのままです。
- 暗号化された鍵セットは、tink.proto で定義されたシリアル化された EncryptedKeyset proto です。暗号化されたバイナリ シリアル化キーセットと、必要に応じて暗号化されていない KeysetInfo メタデータが含まれています。
Tink 出力接頭辞
ほとんどの Tink プリミティブは、次の 5 バイトの出力接頭辞をサポートしています。
- 1 バイト バージョン:
0x01 - 4 バイトの鍵ヒント: 使用された鍵の鍵 ID です。
一部のレガシーキーは、バージョン バイト 0x00 もサポートしている場合があります。
この接頭辞は認証されておらず、セキュリティ目的で使用することはできません。Tink は、復号や検証を高速化するためのヒントとしてこれを使用します。
AEAD
通常、Tink は AEAD 暗号文を次のようにフォーマットします。
prefix || IV || ciphertext || tag
対応する RFC で特に指定されていない限り、prefix は空か、5 バイトの Tink 出力プレフィックスです。
AES-CTR-HMAC
AES-CTR-HMAC の場合、Tink は関連データ(AD)を使用して次のように MAC を計算します。
AD || IV || ciphertext || bitlen(AD)
ここで、bitlen(AD) は AD の長さをビット単位で表したもので、64 ビットのビッグ エンディアンの符号なし整数として表されます。この HMAC スキームは、Mcgrew の AES-CBC-HMAC のドラフトに準拠しています。
決定論的 AEAD
Tink は AES-SIV の RFC 5297 を実装し、合成初期化ベクトル(SIV)を暗号文の先頭に配置します。プリミティブは 5 バイトの Tink 出力接頭辞を追加する場合があります。
RFC 5297 は関連データのリストをサポートしていますが、Tink は 1 つの関連データのみをサポートしています。これは RFC 5297 の 1 つの要素を含むリストに対応しています。関連付けられたデータが空の場合、空のリストではなく、空の要素が 1 つ含まれるリストになります。
ストリーミング AEAD
AES-CTR HMAC と AES-GCM-HKDF をご覧ください。
エンベロープ暗号化
エンベロープ暗号化では、Tink の AEAD プリミティブを使用して、データ暗号鍵 DEK でデータを暗号化します。暗号化は次のように機能します。
- 指定された鍵テンプレート(または鍵パラメータ)を使用して、新しい
DEKが生成されます。 DEKはバイト文字列にシリアル化されます。鍵タイプの proto のプロトコル バッファ シリアル化のシリアル化形式。たとえば、これは、鍵タイプ AES GCM の DEK 用に aes_gcm.proto で定義されたシリアル化されたAesGcmKeyプロトコル バッファ メッセージです。プロトコル バッファをシリアル化する方法については、プロトコル バッファのシリアル化をご覧ください。- シリアル化された
DEKは、外部プロバイダ(GCP など)によってencrypted DEKに暗号化されます。 DEKは、関連付けられたデータを含む平文をciphertextに暗号化するために使用されます。したがって、ciphertextの形式は、DEKに対応する AEAD プリミティブとまったく同じです。
エンベロープ暗号化の出力形式は次のとおりです。
encrypted DEK length || encrypted DEK || ciphertext
encrypted DEK length は 4 バイトで、encrypted DEK の長さを 32 ビットのビッグエンディアン整数として保存します。
MAC
Tink は対応する RFC に準拠しています。プリミティブは、タグに 5 バイトの Tink 出力接頭辞を追加する場合があります。
PRF セット
Tink は対応する RFC に準拠しています。PRF の場合、鍵タイプは同じアルゴリズムの MAC 鍵タイプとは異なり、出力長が含まれていません。PRF セットキーは Tink 出力接頭辞を追加しません。これにより、出力が実際に PRF であることが保証されます。
ハイブリッド暗号化
Tink ハイブリッド暗号化の一般的なワイヤー形式は次のとおりです。
prefix || encapsulated_key || encrypted_data
prefix は空か、5 バイトの Tink 出力接頭辞です。各キータイプには、解析するバイト数と、encapsulated_key からそれらのバイトを解析する方法に関する情報が含まれています。
HPKE(ハイブリッド公開鍵暗号化)
Tink は、RFC 9180 で定義されている HPKE 標準に準拠しています。HPKE 暗号スイートには、次の 3 つのプリミティブが含まれています。
- 鍵カプセル化メカニズム(KEM)
- 鍵導出関数(KDF)
- 関連データを伴う認証付き暗号化(AEAD)
HPKE 標準では、RFC 9180 のセクション 10 で一般的なワイヤー形式を定義していません。Tink の HPKE 実装では、次の encapsulated_key 値と encrypted_data 値を使用します。
encapsulated_key- 送信者のシリアル化された公開鍵
- RFC 9180 のセクション 4.1 で
encとして定義されています - 使用される特定の HPKE KEM によって決定される形式
encrypted_data- 暗号テキストとタグ(つまり、
ciphertext || tag(IV なし) - RFC 9180 セクション 4 で
ctとして定義されています - 使用される特定の HPKE AEAD によって決定される形式
- 暗号テキストとタグ(つまり、
X25519 Diffie-Hellman ベースの KEM
X25519 DHKEM の場合、値 enc は送信者の 32 バイトの Diffie-Hellman 公開鍵です。
ECIES-AEAD-HKDF
Tink の ECIES-AEAD-HKDF 実装では、encapsulated_key は鍵カプセル化メカニズム(KEM)の出力、encrypted_data はデータ カプセル化メカニズム(DEM)の出力です。
KEM
キータイプに応じて、Tink は RFC 8422/ANSI.X9-62.2005 エンコード標準に従って、圧縮された楕円曲線ポイントと圧縮されていない楕円曲線ポイントを使用します。圧縮されていないポイントの場合、バイト 0x04 の後に、固定サイズの整数として x 座標と y 座標が続きます。圧縮された座標の場合、バイト 0x02 または 0x03 と、固定サイズの整数としての x 座標が使用されます。X25519 の場合、RFC 7748 の定義(固定サイズの整数としての x 座標)が使用されます。
DEM
encrypted_data の場合、Tink は AEAD と同じ形式を使用します。これには、IV の指定が含まれます。
鍵の派生
まず、共有ポイントの x 座標 x_ss が計算されます。AEAD の鍵は次のように設定されます。
HKDF(ikm = encapsulated_key || x_ss, salt = salt_of_key, info = context_info, length = dem_key_size)
ここで、encapsulated_key は KEM の完全な出力をバイトで表したものです。
デジタル署名
Tink は対応する RFC に準拠しています。プリミティブは、生成されたタグに 5 バイトの Tink 出力接頭辞を追加する場合があります。
ECDSA
鍵の EcdsaSignatureEncoding フィールドに応じて、ECDSA 署名の形式は IEEE P1363 または ASN.1 DER のいずれかになります。
IEEE P1363 署名の形式は r || s です。ここで、r と s はゼロパディングされ、曲線の順序と同じバイトサイズになります。たとえば、NIST P-256 曲線の場合、r と s は 32 バイトにゼロパディングされます。
DER 署名は ASN.1 を使用してエンコードされます。
ECDSA-Sig-Value :: = SEQUENCE { r INTEGER, s INTEGER }
具体的には、エンコードは次のようになります。
0x30 || totalLength || 0x02 || r's length || r || 0x02 || s's length || s
Tink は、DER 形式でエンコードされた ECDSA 署名のみを受け入れることで、署名検証のベスト プラクティスに従っています(BER 形式でエンコードされた署名は無効です)。
これにより、署名の可鍛性攻撃を防ぐことができます。この攻撃は、多くの場合、暗号通貨システムに影響します。
外部 Mu ML-DSA プリハッシュ値
Prehash プリミティブは、メッセージをプリハッシュ値に変換します。SignPrehash プリミティブは、このプリハッシュ値に署名します。RFC 9881 で説明されているように、外部 Mu モードの ML-DSA の場合、プリハッシュ値は 69 バイトで、次のレイアウトになります。
0xff || key_id (4 bytes, big-endian) || mu (64 bytes)
muは ML-DSA メッセージの代表値で、SHAKE256(tr || 0x00 || 0x00 || message, 64)として計算されます。ここで、trは公開鍵の 64 バイトのハッシュ、最初の0x00は純粋な ML-DSA の FIPS 204 ドメイン セパレータ、2 番目の0x00は(空の)コンテキスト文字列の長さです。trは公開鍵から導出されるため、muはその鍵に暗号的にバインドされます。ただし、バインディングを確認するには元のメッセージが必要です。- 5 バイトのプレフィックスは Tink のフレーミングであり、
muの一部ではありません。これにより、事前ハッシュ値が特定のキーに関連付けられるため、SignPrehash は署名に使用するキーを認識し、キーのない事前ハッシュ値を拒否できます。プレフィックスはプレーン メタデータであり、暗号的にバインドされません。誰でも書き換えることができます。
署名では、69 バイトでない入力、0xff で始まらない入力、キー ID がキーセット内の有効なキーと一致しない入力は拒否されます。