Tink Wire-Format

Auf dieser Seite wird das Tink-Wire-Format für Schlüssel und die Ausgabe von Primitiven beschrieben. Die Dokumentation richtet sich an Kryptografen, die Tink zusätzliche Sprachen hinzufügen möchten, und an Maintainer anderer übergeordneter Kryptobibliotheken, die einen drahtkompatiblen Modus benötigen. Sie ist nicht für die breite Öffentlichkeit bestimmt.

Serialisierung von Schlüsselsätzen

Tink verwendet Google Protobuf, um seine Keysets zu serialisieren.

  • Ein binär serialisierter Schlüsselsatz ist ein serialisiertes Keyset-Proto, das in tink.proto definiert ist. Die Eigenschaft „KeyData“ eines Schlüssels ist ein serialisiertes Proto des entsprechenden Schlüsseltyps.
  • Ein JSON-serialisiertes Keyset ist ein Keyset-Proto, das im JSON-Format serialisiert wurde. Der KeyData-Wert ist weiterhin ein binär serialisiertes Proto.
  • Ein verschlüsselter Schlüsselsatz ist ein serialisiertes EncryptedKeyset-Proto, das in tink.proto definiert ist. Es enthält ein verschlüsseltes binär serialisiertes Keyset und optional einige unverschlüsselte KeysetInfo-Metadaten.

Tink-Ausgabepräfix

Die meisten Tink-Primitiven unterstützen ein 5-Byte-Ausgabepräfix, das aus Folgendem besteht:

  • 1-Byte-Version: 0x01
  • 4 Byte-Schlüsselhinweis: Dies ist die Schlüssel-ID des verwendeten Schlüssels.

Einige Legacy-Schlüssel unterstützen möglicherweise auch das Versionsbyte 0x00.

Dieses Präfix ist nicht authentifiziert und kann nicht für Sicherheitszwecke verwendet werden. Tink verwendet sie als Hinweis, um die Entschlüsselung oder Überprüfung zu beschleunigen.

AEAD

Im Allgemeinen formatiert Tink AEAD-Chiffretexte so:

prefix || IV || ciphertext || tag

sofern in der entsprechenden RFC nicht anders angegeben. prefix ist entweder leer oder ein 5‑Byte-Tink-Ausgabepräfix.

AES-CTR-HMAC

Bei AES-CTR-HMAC berechnet Tink den MAC mit zugehörigen Daten (AD) so:

AD || IV || ciphertext || bitlen(AD)

Dabei ist bitlen(AD) die Länge des AD in Bits, dargestellt als vorzeichenlose 64-Bit-Ganzzahl im Big-Endian-Format. Dieses HMAC-Schema folgt dem Entwurf für AES-CBC-HMAC von McGrew.

Deterministisches AEAD

Tink implementiert RFC 5297 für AES-SIV und platziert den Synthetic Initialization Vector (SIV) am Anfang des Chiffretexts. Das Primitive kann ein 5‑Byte-Tink-Ausgabepräfix hinzufügen.

Während RFC 5297 eine Liste zugehöriger Daten unterstützt, unterstützt Tink nur genau eine zugehörige Dateneinheit, was in RFC 5297 einer Liste mit einem Element entspricht. Leere zugeordnete Daten sind eine Liste mit einem leeren Element und nicht eine leere Liste.

Streaming-AEAD

Weitere Informationen finden Sie unter AES-CTR HMAC und AES-GCM-HKDF.

Umschlagverschlüsselung

Bei der Umschlagverschlüsselung werden die Daten mit einem Datenverschlüsselungsschlüssel DEK mithilfe der AEAD-Primitiven von Tink verschlüsselt. Die Verschlüsselung funktioniert so:

  • Ein neues DEK wird mit einer bestimmten Schlüsselvorlage (oder Schlüsselparametern) generiert.
  • Der DEK wird in einen Bytestring serialisiert. Das Serialisierungsformat der Protokollzwischenspeicherserialisierung des Schlüsseltypprotokolls. Dies ist beispielsweise eine serialisierte AesGcmKey-Protokollpuffernachricht, die in aes_gcm.proto für den DEK des Schlüsseltyps AES GCM definiert ist. Informationen zum Serialisieren eines Protokollpuffers finden Sie unter Protokollpufferserialisierung.
  • Die serialisierte DEK wird von einem externen Anbieter (z. B. GCP) in eine encrypted DEK verschlüsselt.
  • Die DEK wird verwendet, um den Klartext mit den zugehörigen Daten in ciphertext zu verschlüsseln. ciphertext hat also genau dasselbe Format wie das AEAD-Primitive, das DEK entspricht.

Das Ausgabeformat der Umschlagverschlüsselung sieht so aus:

encrypted DEK length || encrypted DEK || ciphertext

encrypted DEK length ist 4 Byte lang und speichert die Länge von encrypted DEK als 32-Bit-Big-Endian-Ganzzahl.

MAC

Tink folgt den entsprechenden RFCs. Bei Primitives kann dem Tag ein 5‑Byte-Tink-Ausgabepräfix hinzugefügt werden.

PRF-Gruppe

Tink folgt den entsprechenden RFCs. Beachten Sie, dass sich der Schlüsseltyp für PRF vom MAC-Schlüsseltyp desselben Algorithmus dadurch unterscheidet, dass die Ausgabelänge nicht enthalten ist. PRF-Schlüssel haben nie ein Tink-Ausgabepräfix. So wird sichergestellt, dass die Ausgabe tatsächlich eine PRF ist.

Hybridverschlüsselung

Das allgemeine Wire-Format für die hybride Verschlüsselung von Tink ist das folgende:

prefix || encapsulated_key || encrypted_data

prefix ist entweder leer oder ein 5‑Byte-Tink-Ausgabepräfix. Jeder Schlüsseltyp enthält die Informationen dazu, wie viele Byte geparst werden müssen und wie diese Byte aus encapsulated_key geparst werden.

HPKE (Hybrid Public Key Encryption)

Tink folgt dem in RFC 9180 definierten HPKE-Standard. Eine HPKE-Chiffriersuite umfasst die folgenden drei Primitiven.

  • Mechanismus für die Schlüsselkapselung (Key Encapsulation Mechanism, KEM)
  • Schlüsselableitungsfunktion (Key Derivation Function, KDF)
  • Authentifizierte Verschlüsselung mit verknüpften Daten (Authenticated Encryption with Associated Data, AEAD)

Der HPKE-Standard definiert kein allgemeines Wire-Format in RFC 9180, Abschnitt 10. In der HPKE-Implementierung von Tink werden die folgenden encapsulated_key- und encrypted_data-Werte verwendet.

  • encapsulated_key
    • Serialisierter öffentlicher Schlüssel des Absenders
    • Definiert als enc in RFC 9180, Abschnitt 4.1
    • Das Format wird durch den verwendeten HPKE-KEM bestimmt.
  • encrypted_data
    • Geheimtext und Tag (d.h. ciphertext || tag ohne die unabhängige Variable)
    • Als ct in RFC 9180, Abschnitt 4 definiert
    • Das Format wird durch das verwendete HPKE-AEAD bestimmt.
Auf X25519 Diffie-Hellman basierendes KEM

Bei X25519-DHKEMs ist der Wert enc der 32‑Byte-Diffie-Hellman-öffentliche Schlüssel des Absenders.

ECIES-AEAD-HKDF

In der ECIES-AEAD-HKDF-Implementierung von Tink ist encapsulated_key die Ausgabe des Key Encapsulation Mechanism (KEM) und encrypted_data die Ausgabe des Data Encapsulation Mechanism (DEM).

KEM

Je nach Schlüsseltyp verwendet Tink komprimierte und unkomprimierte Elliptik-Kurvenpunkte gemäß den RFC 8422-/ANSI.X9-62.2005-Codierungsstandards. Bei nicht komprimierten Punkten folgt auf das Byte 0x04 die x- und die y-Koordinate als Ganzzahlen mit fester Größe. Für komprimierte Koordinaten werden das Byte 0x02 oder 0x03 und die x-Koordinate als Ganzzahl mit fester Größe verwendet. Für X25519 wird die RFC 7748-Definition verwendet (x-Koordinate als Ganzzahl mit fester Größe).

DEM

Für encrypted_data verwendet Tink dasselbe Format wie für AEAD. Dazu gehört auch die Angabe eines IV.

Schlüsselableitung

Zuerst wird die x-Koordinate x_ss des gemeinsamen Punkts berechnet. Der Schlüssel für die AEAD wird dann auf Folgendes festgelegt:

HKDF(ikm = encapsulated_key || x_ss, salt = salt_of_key, info = context_info, length = dem_key_size)

Dabei ist encapsulated_key die vollständige KEM-Ausgabe als Byte.

Digitale Signaturen

Tink folgt den entsprechenden RFCs. Primitiven kann dem generierten Tag ein 5‑Byte-Tink-Ausgabepräfix hinzugefügt werden.

ECDSA

Abhängig vom EcdsaSignatureEncoding-Feld im Schlüssel ist das Format einer ECDSA-Signatur entweder IEEE P1363 oder ASN.1 DER.

Das Format der IEEE P1363-Signatur ist r || s, wobei r und s mit Nullen aufgefüllt werden und dieselbe Größe in Byte wie die Ordnung der Kurve haben. Bei der NIST P-256-Kurve werden r und s beispielsweise mit Nullen auf 32 Byte aufgefüllt.

Die DER-Signatur wird mit ASN.1 codiert:

ECDSA-Sig-Value :: = SEQUENCE { r INTEGER, s INTEGER }

Die Codierung ist:

0x30 || totalLength || 0x02 || r's length || r || 0x02 || s's length || s

Tink folgt den Best Practices für die Signaturprüfung und akzeptiert nur DER-codierte ECDSA-Signaturen (alternative BER-codierte Signaturen sind ungültig).

So lassen sich Angriffe auf die Signatur vermeiden, die häufig Kryptowährungssysteme betreffen.

Externe Mu ML-DSA-Prehash-Werte

Das Primitive Prehash wandelt eine Nachricht in einen Prehash-Wert um, der dann vom Primitive „SignPrehash“ signiert wird. Für ML-DSA im Modus External Mu, wie in RFC 9881 beschrieben, hat der Prehash-Wert eine Länge von 69 Byte und das folgende Layout:

0xff || key_id (4 bytes, big-endian) || mu (64 bytes)
  • mu ist die ML-DSA-Nachricht, die als SHAKE256(tr || 0x00 || 0x00 || message, 64) berechnet wird, wobei tr der 64-Byte-Hash des öffentlichen Schlüssels ist, das erste 0x00 der FIPS 204-Domänentrenner für reines ML-DSA ist und das zweite 0x00 die Länge des (leeren) Kontextstrings ist. Da tr aus dem öffentlichen Schlüssel abgeleitet wird, ist mu kryptografisch an diesen Schlüssel gebunden. Die Prüfung der Bindung erfordert jedoch die ursprüngliche Nachricht.
  • Das 5‑Byte-Präfix ist Tink-Framing und nicht Teil von mu. Er ordnet den Prehash-Wert einem bestimmten Schlüssel zu, sodass SignPrehash weiß, mit welchem Schlüssel signiert werden soll, und einen Prehash-Wert ablehnen kann, für den kein Schlüssel vorhanden ist. Das Präfix ist eine einfache Metadateninformation und ist nicht kryptografisch gebunden. Jeder kann es neu schreiben.

Beim Signieren wird jede Eingabe abgelehnt, die nicht genau 69 Byte lang ist, nicht mit 0xff beginnt oder deren Schlüssel-ID nicht mit einem aktivierten Schlüssel im Keyset übereinstimmt.