Zalecamy używanie elementów Prehash i SignPrehash z kluczem ML_DSA_65, gdy klucz prywatny znajduje się w miejscu, z którego nie można wysłać wiadomości.
Czasami podmiot, który ma klucz podpisywania, nie może lub nie powinien otrzymać samej wiadomości: klucz znajduje się w module HSM lub KMS albo wiadomość jest większa niż limit rozmiaru żądania osoby podpisującej.
Funkcje Prehash i SignPrehash rozwiązują ten problem, dzieląc podpisywanie na 2 etapy. Obliczasz krótką wartość prehash, w której znajduje się wiadomość, używając tylko klucza publicznego, i wysyłasz ją do osoby podpisującej. Podpisujący przekształca go w podpis za pomocą klucza prywatnego, nie widząc wiadomości. W przypadku ML-DSA w trybie External Mu (algorytm obsługiwany przez Tink) wartość prehash ma 69 bajtów niezależnie od rozmiaru wiadomości.
Otrzymana sygnatura jest zwykłą sygnaturą oryginalnej wiadomości: weryfikatorzy używają zwykłego prymitywu podpisu cyfrowego i nie muszą mieć potrzeby dostępu do informacji, że proces składał się z 2 etapów.
Zanim zaczniesz
Utwórz zestaw kluczy ML-DSA, którego klucze mają wymaganie dotyczące identyfikatora – wariant TINK lub NO_PREFIX_WITH_PREHASH_ID, jeśli nie chcesz, aby wynikowy podpis miał prefiks wyjściowy. Przekaż osobie podpisującej zestaw kluczy prywatnych, a osobie przeprowadzającej wstępne haszowanie – odpowiedni zestaw kluczy publicznych. Osoba podpisująca powinna mieć włączony klucz dla każdego identyfikatora klucza, który może wygenerować strona wstępnego haszowania. Więcej informacji znajdziesz w sekcji Zestawy kluczy.
Krok 1. Oblicz wartość przed haszowaniem
Uruchom to w miejscu, w którym znajduje się wiadomość. Wymagany jest tylko publiczny zbiór kluczy.
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 }
Krok 2. Wyślij wartość prehash do osoby podpisującej
Wyślij wartość wstępnego haszowania do podmiotu, który ma klucz prywatny. Nie jest to tajemnica, ale musisz chronić jego integralność podczas przesyłania: atakujący, który może go zmodyfikować w trakcie przesyłania, kontroluje to, co zostanie podpisane.
Krok 3. Podpisz wartość prehash
Uruchom to w miejscu, w którym znajduje się klucz prywatny.
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 }
Krok 4. Weryfikacja podpisu
Weryfikacja to zwykły proces podpisu cyfrowego w przypadku oryginalnej wiadomości, a nie wartości prehash.
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 i SignPrehash
Funkcje Prehash i SignPrehash dzielą obliczanie podpisu cyfrowego na 2 etapy:
- Prehash wymaga tylko klucza publicznego. Przekształca wiadomość o dowolnej długości w krótką wartość prehash o stałym rozmiarze.
- Funkcja SignPrehash wymaga klucza prywatnego. Przekształca ona wartość przed haszowaniem w sygnaturę.
Wynikowy podpis jest zwykłym podpisem oryginalnej wiadomości. Weryfikujesz ją za pomocą zwykłego prymitywu podpisu cyfrowego PublicKeyVerify, a weryfikatorzy nie muszą wiedzieć ani się przejmować tym, że podpis został utworzony w 2 krokach.
Traktuj wartość wstępnego haszowania jako nieprzejrzyste bajty. Ma stały rozmiar i zawiera identyfikator klucza, dla którego został obliczony, ale jego układ jest częścią formatu przesyłania Tink, więc nie należy go samodzielnie analizować ani tworzyć. Jeśli przenosisz Tink lub potrzebujesz szczegółów na poziomie bajtów, zapoznaj się z formatem Tink.
Używaj tej pary elementów podstawowych, gdy:
- Klucz podpisu znajduje się w innym miejscu, np. w module HSM, w KMS lub za granicą RPC, i nie chcesz przesyłać pełnej wiadomości przez tę granicę.
- Wiadomość jest duża, a zdalny podpisujący wymusza limit rozmiaru żądania.
Jeśli żadna z tych sytuacji nie ma miejsca, użyj prostego elementu Digital Signature. Jest on prostszy i trudniej go niewłaściwie użyć.
Zbiory kluczy
Te 2 typy kluczy wybierają klucze w inny sposób, podobnie jak w przypadku podpisywania i weryfikacji w typie Podpis cyfrowy:
Prehash.Computezawsze używa klucza podstawowego w zbiorze kluczy publicznych i zapisuje identyfikator tego klucza w wartości przed haszowaniem. To strona, która wybiera klucz, za pomocą którego zostanie utworzony podpis.SignPrehash.Signodczytuje identyfikator klucza z wartości wstępnego haszowania i podpisuje go za pomocą pasującego włączonego klucza z zestawu kluczy prywatnych. Jest to strona, która podąża za wyborem dokonanym przez inną osobę. Jeśli w zestawie kluczy nie ma włączonego klucza z tym identyfikatorem, wywołanie się nie powiedzie.
Każdy klucz w zestawie kluczy SignPrehash musi mieć wymaganie dotyczące identyfikatora. W przeciwnym razie utworzenie elementu podstawowego się nie powiedzie.
Minimalne gwarancje bezpieczeństwa
- Wynikowy podpis ma takie same właściwości jak podpis wygenerowany przez funkcję pierwotną Digital Signature z tym samym typem klucza.
- Tink dodaje do wartości przed haszowaniem 5 bajtów zawierających specjalną wartość zarezerwowaną i identyfikator klucza, dla którego została obliczona.
SignPrehashpodpisuje wartość tylko tym kluczem. To, czy wartość jest kryptograficznie powiązana z tym kluczem, zależy od algorytmu. W przypadku zewnętrznego algorytmu Mu ML-DSA tak jest. Więcej informacji znajdziesz w formacie przesyłania Tink. - Wiadomości mogą mieć dowolną długość.
Na co zwracać uwagę
- Osoba podpisująca nie może sprawdzić, co podpisuje. Każda osoba, która może dzwonić na numer
SignPrehash, może uzyskać podpis dowolnej wiadomości, a osoba podpisująca nie ma możliwości zastosowania zasad do treści wiadomości. Chroń dostęp doSignPrehashdokładnie tak samo, jak chronisz dostęp doPublicKeySign. - Chroń wartość przed zaszyfrowaniem podczas przesyłania. Nie jest to tajne, ale atakujący, który może je zmodyfikować w trakcie przesyłania, kontroluje, co zostanie podpisane.
Wybierz typ klucza
ML-DSA w trybie External Mu, zgodnie z opisem w RFC 9881, to jedyny algorytm obsługiwany przez Tink w przypadku funkcji Prehash i SignPrehash. W przypadku tych elementów pierwotnych należy używać standardowego klucza ML-DSA.
W większości przypadków zalecamy używanie ML_DSA_65.
Klucz musi mieć wymaganie dotyczące identyfikatora, ponieważ każda wartość wstępnie zaszyfrowana zaczyna się od prefiksu zawierającego identyfikator klucza, dla którego została obliczona. Akceptujemy te warianty:
TINK– wynikowy podpis zaczyna się od zwykłego 5-bajtowego prefiksu wyjściowego Tink.NO_PREFIX_WITH_PREHASH_ID– wynikowy podpis nie zawiera prefiksu wyjściowego, a klucz nadal ma identyfikator, którego potrzebuje wartość przed haszowaniem.
Klucze, które używają wariantu NO_PREFIX (surowego), nie są obsługiwane, ponieważ nie mają identyfikatora klucza.