Die Primitiven „Prehash“ und „SignPrehash“ teilen die Berechnung einer digitalen Signatur in zwei Schritte auf:
- Für Prehash ist nur der öffentliche Schlüssel erforderlich. Sie wandelt eine Nachricht beliebiger Länge in einen kurzen Prehash-Wert mit fester Größe um.
- Für SignPrehash ist der private-Schlüssel erforderlich. Sie wandelt einen Prehash-Wert in eine Signatur um.
Die resultierende Signatur ist eine gewöhnliche Signatur für die ursprüngliche Nachricht. Sie wird mit dem regulären Digital Signature-PublicKeyVerify-Primitive überprüft. Prüfer müssen nicht wissen oder sich darum kümmern, dass die Signatur in zwei Schritten erstellt wurde.
Den Prehash-Wert als undurchsichtige Bytes behandeln. Es hat eine feste Größe und enthält die ID des Schlüssels, für den es berechnet wurde. Das Layout ist jedoch Teil des Wire-Formats von Tink. Sie sollten es nicht selbst parsen oder erstellen. Wenn Sie Tink portieren oder Details auf Byte-Ebene benötigen, lesen Sie den Abschnitt Tink-Wire-Format.
Verwenden Sie dieses Primitive-Paar, wenn:
- Der Signierschlüssel befindet sich an einem anderen Ort, z. B. in einem HSM, in einem KMS oder hinter einer RPC-Grenze, und Sie möchten nicht die gesamte Nachricht über diese Grenze hinweg übertragen.
- Die Nachricht ist groß und der Remote-Signierer erzwingt eine Beschränkung der Anforderungsgröße.
Wenn keines der beiden zutrifft, verwenden Sie stattdessen das einfache Primitive Digital Signature. Es ist einfacher und es ist schwieriger, es zu missbrauchen.
Schlüsselsätze
Die beiden Primitiven wählen Schlüssel unterschiedlich aus, so wie das Signieren und die Überprüfung für das Digital Signature-Primitiv funktionieren:
Prehash.Computeverwendet immer den primären Schlüssel des öffentlichen Schlüsselsatzes und zeichnet die ID dieses Schlüssels im Prehash-Wert auf. Es ist die Seite, die auswählt, mit welchem Schlüssel die Signatur erstellt wird.SignPrehash.Signliest die Schlüssel-ID aus dem Prehash-Wert und signiert mit dem passenden aktivierten Schlüssel des privaten Schlüsselsets. Es ist die Seite, die einer Entscheidung folgt, die jemand anderes bereits getroffen hat. Wenn kein aktivierter Schlüssel im Keyset diese ID hat, schlägt der Aufruf fehl.
Jeder Schlüssel in einem SignPrehash-Schlüsselsatz muss eine ID-Anforderung haben. Andernfalls schlägt das Erstellen des Primitivs fehl.
Minimale Sicherheitsgarantien
- Die resultierende Signatur hat dieselben Eigenschaften wie eine Signatur, die mit dem Primitiv Digital Signature mit demselben Schlüsseltyp erstellt wurde.
- Tink stellt dem Prehash-Wert 5 Bytes voran, die einen speziellen reservierten Wert und die ID des Schlüssels enthalten, für den er berechnet wurde.
SignPrehashsigniert den Wert nur mit diesem Schlüssel. Ob der Wert kryptografisch an diesen Schlüssel gebunden ist, hängt vom Algorithmus ab. Bei External Mu ML-DSA ist das der Fall (siehe Tink-Wire-Format). - Nachrichten können eine beliebige Länge haben.
Worauf Sie achten sollten
- Der Unterzeichner kann nicht prüfen, was er unterzeichnet. Jeder, der
SignPrehashanrufen kann, kann eine beliebige Nachricht signieren lassen. Der Unterzeichner hat keine Möglichkeit, eine Richtlinie auf den Inhalt der Nachricht anzuwenden. Schützen Sie den Zugriff aufSignPrehashgenauso wie den Zugriff aufPublicKeySign. - Prehash-Wert bei der Übertragung schützen Es ist nicht geheim, aber ein Angreifer, der es während der Übertragung ändern kann, steuert, was signiert wird.
Schlüsseltyp auswählen
ML-DSA im External Mu-Modus, wie in RFC 9881 beschrieben, ist der einzige Algorithmus, den Tink für Prehash und SignPrehash unterstützt. Sie sollten einen Standard-ML-DSA-Schlüssel mit diesen Primitiven verwenden.
Wir empfehlen ML_DSA_65 für die meisten Anwendungsfälle.
Für den Schlüssel muss eine ID-Anforderung gelten, da jeder Prehash-Wert mit einem Präfix beginnt, das die ID des Schlüssels enthält, für den er berechnet wurde. Die folgenden Varianten sind zulässig:
TINK– Die resultierende Signatur beginnt mit dem üblichen 5‑Byte-Ausgabepräfix von Tink.NO_PREFIX_WITH_PREHASH_ID: Die resultierende Signatur hat kein Ausgabepräfix, während der Schlüssel weiterhin die ID hat, die für den Prehash-Wert erforderlich ist.
Schlüssel, die die NO_PREFIX-Variante (roh) verwenden, werden nicht unterstützt, da sie keine Schlüssel-ID haben.
Beispiele
In den folgenden Beispielen wird eine Nachricht in zwei Schritten signiert und die resultierende Signatur dann mit dem normalen Digital Signature-Primitive überprüft.
Zur besseren Lesbarkeit werden sie als ein Block dargestellt. In einer echten Bereitstellung werden die beiden Schritte an unterschiedlichen Stellen ausgeführt. Eine detaillierte Anleitung finden Sie unter I want to sign data with a remote signer.
C++
#include "tink/keyset_handle.h" #include "tink/public_key_verify.h" #include "tink/signature/config_2026.h" #include "tink/signature/prehash.h" #include "tink/signature/sign_prehash.h" using ::crypto::tink::ConfigSignature2026; using ::crypto::tink::Prehash; using ::crypto::tink::PublicKeyVerify; using ::crypto::tink::SignPrehash; // 1. Wherever the message is: compute the prehash value. This needs only // the public keyset. absl::StatusOr<std::unique_ptr<Prehash>> prehasher = public_handle.GetPrimitive<Prehash>(ConfigSignature2026()); if (!prehasher.ok()) return prehasher.status(); absl::StatusOr<std::string> prehash = (*prehasher)->Compute(message); if (!prehash.ok()) return prehash.status(); // 2. Wherever the private key is: turn the prehash value into a signature. absl::StatusOr<std::unique_ptr<SignPrehash>> signer = private_handle.GetPrimitive<SignPrehash>(ConfigSignature2026()); if (!signer.ok()) return signer.status(); absl::StatusOr<std::string> signature = (*signer)->Sign(*prehash); if (!signature.ok()) return signature.status(); // 3. Anywhere: verify the signature over the original message. absl::StatusOr<std::unique_ptr<PublicKeyVerify>> verifier = public_handle.GetPrimitive<PublicKeyVerify>(ConfigSignature2026()); if (!verifier.ok()) return verifier.status(); absl::Status verified = (*verifier)->Verify(*signature, message);
Ok
import ( "github.com/tink-crypto/tink-go/v2/signature" "github.com/tink-crypto/tink-go/v2/signprehash" ) // 1. Wherever the message is: compute the prehash value. This needs only // the public keyset. prehasher, err := signprehash.NewPrehash(publicHandle) if err != nil { return err } prehash, err := prehasher.ComputePrehash(message) if err != nil { return err } // 2. Wherever the private key is: turn the prehash value into a signature. signer, err := signprehash.NewPrehashSigner(privateHandle) if err != nil { return err } sig, err := signer.SignPrehash(prehash) if err != nil { return err } // 3. Anywhere: verify the signature over the original message. verifier, err := signature.NewVerifier(publicHandle) if err != nil { return err } if err := verifier.Verify(sig, message); err != nil { return err }
Weitere Informationen
- Daten mit einem Remote-Signer signieren – eine Schritt-für-Schritt-Anleitung für den zweistufigen Ablauf.
- Digitale Signatur: Signieren und Verifizieren in einem einzigen Schritt, wenn der Unterzeichner die Nachricht sehen kann.
- Unterstützte primitive Schlüsseltypen nach Sprache
- Tink-Wire-Format: Das Byte-Level-Layout eines Prehash-Werts für die Portierung von Tink in eine andere Sprache.