Tink 線路格式

本頁說明 Tink 的金鑰和基本輸出內容的線路格式。這份文件適用於想在 Tink 中新增其他語言的密碼編譯人員,以及想使用線路相容模式的其他高階加密程式庫維護人員。不適合一般大眾。

金鑰組序列化

Tink 會使用 Google protobuf 序列化金鑰集。

  • 二進位序列化鍵集是 tink.proto 中定義的序列化鍵集 Proto。金鑰的 KeyData 值屬性是相應金鑰類型的序列化原型。
  • JSON 序列化鍵集是採用 JSON 格式序列化的鍵集 Proto。請注意,KeyData 值仍是二進位序列化 proto。
  • 加密金鑰組是序列化的 EncryptedKeyset proto,定義於 tink.proto。其中包含加密的二進位序列化金鑰集,以及一些未加密的 KeysetInfo 中繼資料 (選用)。

Tink 輸出內容前置字串

大多數 Tink 基本體都支援 5 位元組的輸出前置字元,包括:

  • 1 位元組版本:0x01
  • 4 位元組金鑰提示:這是所用金鑰的金鑰 ID。

部分舊版金鑰也可能支援版本位元組 0x00。

前置雜湊基本體 會使用版本位元 0xff,請參閱「外部 Mu ML-DSA 前置雜湊值」。

請注意,這些前置字元未通過驗證,因此不適合做為安全用途。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 只支援一項相關資料,這對應於 RFC 5297 中的單一元素清單。空白關聯資料是含有一個空白元素的清單,而不是空白清單。

串流 AEAD

請參閱「AES-CTR HMAC」和「AES-GCM-HKDF」。

信封式加密

信封式加密會使用 Tink 的 AEAD 基本體,以資料加密金鑰 DEK 加密資料。加密方式如下:

  • 系統會使用指定的金鑰範本 (或金鑰參數) 產生新的 DEK。
  • DEK 會序列化為位元組字串。金鑰類型 proto 的通訊協定緩衝區序列化格式。舉例來說,這是為 AES GCM 金鑰類型 DEK 定義的序列化 AesGcmKey 通訊協定緩衝區訊息,位於 aes_gcm.proto 中。如要瞭解如何序列化通訊協定緩衝區,請參閱通訊協定緩衝區序列化。
  • 序列化 DEK 會由外部供應商 (例如 GCP) 加密為 encrypted DEK。
  • DEK 會使用相關聯的資料將純文字加密為 ciphertext。因此 ciphertext 的格式與對應 DEK 的 AEAD 基本體完全相同。

信封加密的輸出格式如下:

encrypted DEK length || encrypted DEK || ciphertext

encrypted DEK length 為 4 個位元組,以 32 位元大端序整數形式儲存 encrypted DEK 的長度。

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 密碼套件包含下列三種基本元素。

  • 金鑰封裝機制 (KEM)
  • 金鑰衍生函式 (KDF)
  • 關聯資料的驗證加密 (AEAD)

HPKE 標準並未在 RFC 9180 第 10 節中定義一般線路格式。Tink 的 HPKE 實作項目會使用下列 encapsulated_key 和 encrypted_data 值。

  • encapsulated_key
    • 寄件者的序列化公開金鑰
    • 定義為 enc,請參閱 RFC 9180 第 4.1 節
    • 格式取決於使用的特定 HPKE KEM
  • encrypted_data
    • 密文和標記 (即 ciphertext || tag (不含 IV)
    • 定義為 ct,請參閱 RFC 9180 第 4 節
    • 格式取決於使用的特定 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 前置雜湊值

前置雜湊基本體會將訊息轉換為前置雜湊值,然後由 SignPrehash 基本體簽署。如 RFC 9881 所述,在「External 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 網域分隔符,第二個 0x00 是 (空白) 內容字串的長度。由於 tr 是從公開金鑰衍生而來,因此 mu 會以密碼編譯方式繫結至該金鑰,但檢查繫結需要原始訊息。
  • 5 位元組前置字元是 Tink 框架,不屬於 mu。這會將前置雜湊值與一個特定鍵建立關聯,因此 SignPrehash 會知道要使用哪個鍵簽署,並可拒絕沒有鍵的前置雜湊值。前置字串是純中繼資料,不會以加密方式繫結任何內容,任何人都可以重新編寫。

簽署作業會拒絕任何不完全是 69 個位元組的輸入內容、開頭不是 0xff 的輸入內容,或是金鑰 ID 與金鑰集中的啟用金鑰不符的輸入內容。