Nous recommandons les primitives Prehash et SignPrehash avec une clé ML_DSA_65 lorsque la clé privée se trouve à un emplacement où le message ne peut pas être envoyé.
Il arrive parfois que la partie qui détient la clé de signature ne puisse pas (ou ne doive pas) recevoir le message lui-même : la clé se trouve dans un HSM ou un KMS, ou le message est plus volumineux que la limite de taille de la requête du signataire.
Les primitives Prehash et SignPrehash résolvent ce problème en divisant la signature en deux étapes. Vous calculez une courte valeur de préhash où se trouve le message, en utilisant uniquement la clé publique, et vous l'envoyez au signataire. Le signataire la transforme en signature à l'aide de la clé privée, sans jamais voir le message. Avec ML-DSA en mode Mu externe (l'algorithme que Tink prend en charge ici), la valeur de préhachage est de 69 octets, quelle que soit la taille du message.
La signature que vous recevez est une signature ordinaire sur le message d'origine : les vérificateurs utilisent la primitive Signature numérique habituelle et n'ont pas besoin de savoir que deux étapes ont été nécessaires.
Avant de commencer
Créez un keyset ML-DSA dont les clés ont une exigence d'ID : la variante TINK ou NO_PREFIX_WITH_PREHASH_ID si vous ne souhaitez pas de préfixe de sortie sur la signature résultante. Donnez au signataire le keyset privé et au côté préhachage le keyset public correspondant. Le signataire doit disposer d'une clé activée pour chaque ID de clé que le côté préhachage peut produire. Pour en savoir plus, consultez Ensembles de clés.
Étape 1 : Calculer la valeur pré-hachée
Exécutez cette commande à l'endroit où se trouve le message. Elle n'a besoin que du keyset public.
C++
#include "tink/keyset_handle.h" #include "tink/signature/config_2026.h" #include "tink/signature/prehash.h" absl::StatusOr<std::unique_ptr<crypto::tink::Prehash>> prehasher = public_handle.GetPrimitive<crypto::tink::Prehash>( crypto::tink::ConfigSignature2026()); if (!prehasher.ok()) return prehasher.status(); absl::StatusOr<std::string> prehash = (*prehasher)->Compute(message); if (!prehash.ok()) return prehash.status();
Go
import "github.com/tink-crypto/tink-go/v2/signprehash" prehasher, err := signprehash.NewPrehash(publicHandle) if err != nil { return err } prehash, err := prehasher.ComputePrehash(message) if err != nil { return err }
Étape 2 : Envoyez la valeur préhachée au signataire
Envoyez la valeur préhashée à l'entité qui détient la clé privée. Il n'est pas secret, mais vous devez protéger son intégrité en transit : un pirate informatique qui peut le modifier en vol contrôle ce qui est signé.
Étape 3 : Signer la valeur préhachée
Exécutez cette commande à l'emplacement de la clé privée.
C++
#include "tink/keyset_handle.h" #include "tink/signature/config_2026.h" #include "tink/signature/sign_prehash.h" absl::StatusOr<std::unique_ptr<crypto::tink::SignPrehash>> signer = private_handle.GetPrimitive<crypto::tink::SignPrehash>( crypto::tink::ConfigSignature2026()); if (!signer.ok()) return signer.status(); absl::StatusOr<std::string> signature = (*signer)->Sign(prehash); if (!signature.ok()) return signature.status();
Go
import "github.com/tink-crypto/tink-go/v2/signprehash" signer, err := signprehash.NewPrehashSigner(privateHandle) if err != nil { return err } sig, err := signer.SignPrehash(prehash) if err != nil { return err }
Étape 4 : Vérifiez la signature
La validation est le flux de signature numérique ordinaire sur le message d'origine, et non sur la valeur préhachée.
C++
absl::StatusOr<std::unique_ptr<crypto::tink::PublicKeyVerify>> verifier = public_handle.GetPrimitive<crypto::tink::PublicKeyVerify>( crypto::tink::ConfigSignature2026()); if (!verifier.ok()) return verifier.status(); absl::Status verified = (*verifier)->Verify(signature, message);
Go
import "github.com/tink-crypto/tink-go/v2/signature" verifier, err := signature.NewVerifier(publicHandle) if err != nil { return err } if err := verifier.Verify(sig, message); err != nil { return err }
Prehash et SignPrehash
Les primitives Prehash et SignPrehash divisent le calcul d'une signature numérique en deux étapes :
- Prehash n'a besoin que de la clé publique. Il transforme un message de longueur arbitraire en une valeur préhachée courte et de taille fixe.
- SignPrehash a besoin de la clé privée. Elle transforme une valeur préhachée en signature.
La signature obtenue est une signature ordinaire du message d'origine. Vous le validez avec la primitive Digital Signature PublicKeyVerify habituelle, et les validateurs n'ont pas besoin de savoir (ni de se soucier) que la signature a été produite en deux étapes.
Traitez la valeur prehash comme des octets opaques. Il a une taille fixe et porte l'ID de la clé pour laquelle il a été calculé, mais sa mise en page fait partie du format filaire de Tink. Vous ne devez pas l'analyser ni le construire vous-même. Si vous portez Tink ou avez besoin d'informations au niveau des octets, consultez Format filaire Tink.
Utilisez cette paire de primitives lorsque :
- La clé de signature se trouve ailleurs, par exemple dans un HSM, dans un KMS ou derrière une limite RPC, et vous ne souhaitez pas envoyer le message complet au-delà de cette limite.
- Le message est volumineux et le signataire à distance applique une limite de taille de requête.
Si aucune de ces conditions ne s'applique, utilisez plutôt la primitive Signature numérique simple, qui est plus facile à utiliser et moins susceptible d'être mal employée.
Collections de clés
Les deux primitives sélectionnent les clés différemment, de la même manière que la signature et la validation le font pour la primitive Signature numérique :
Prehash.Computeutilise toujours la clé primaire du keyset de clés publiques et enregistre l'ID de cette clé dans la valeur préhachée. C'est le côté qui choisit la clé avec laquelle la signature sera effectuée.SignPrehash.Signlit l'ID de clé à partir de la valeur préhachée et signe avec la clé activée correspondante du keyset de clés privées. Il s'agit du côté qui suit un choix déjà fait par quelqu'un d'autre. Si aucune clé activée dans le trousseau de clés ne possède cet ID, l'appel échoue.
Chaque clé d'un trousseau de clés SignPrehash doit avoir une exigence d'ID. Sinon, la création de la primitive échoue.
Garanties de sécurité minimales
- La signature obtenue présente les mêmes propriétés qu'une signature produite par la primitive Digital Signature avec le même type de clé.
- Tink ajoute un préfixe à la valeur préhachée avec cinq octets contenant une valeur réservée spéciale et l'ID de la clé pour laquelle elle a été calculée.
SignPrehashsigne la valeur uniquement avec cette clé. La question de savoir si la valeur est cryptographiquement liée à cette clé dépend de l'algorithme. Pour External Mu ML-DSA, c'est le cas. Pour en savoir plus, consultez Format fil Tink. - Les messages peuvent avoir une longueur arbitraire.
Éléments à surveiller
- Le signataire ne peut pas inspecter ce qu'il signe. Toute personne pouvant appeler
SignPrehashpeut obtenir un message arbitraire signé, et le signataire n'a aucun moyen d'appliquer une règle au contenu du message. Protégez l'accès àSignPrehashexactement comme vous le feriez pourPublicKeySign. - Protégez la valeur du préhash en transit. Il n'est pas secret, mais un pirate informatique qui peut le modifier en cours de transmission contrôle ce qui est signé.
Choisir un type de clé
Le mode External Mu de ML-DSA, tel que décrit dans la RFC 9881, est le seul algorithme que Tink accepte pour Prehash et SignPrehash. Vous devez utiliser une clé ML-DSA standard avec ces primitives.
Nous recommandons ML_DSA_65 pour la plupart des cas d'utilisation.
La clé doit avoir une exigence d'ID, car chaque valeur préhachée commence par un préfixe contenant l'ID de la clé pour laquelle elle a été calculée. Les variantes suivantes sont acceptées :
TINK: la signature obtenue commence par le préfixe de sortie habituel de Tink (5 octets).NO_PREFIX_WITH_PREHASH_ID: la signature obtenue ne comporte aucun préfixe de sortie, tandis que la clé conserve l'ID dont la valeur préhachée a besoin.
Les clés qui utilisent la variante NO_PREFIX (brute) ne sont pas acceptées, car elles n'ont pas d'ID de clé.