Các nguyên tắc Prehash và SignPrehash chia quá trình tính toán chữ ký số thành hai bước:
- Prehash chỉ cần khoá công khai. Hàm này chuyển đổi một thông báo có độ dài bất kỳ thành một giá trị tiền băm ngắn, có kích thước cố định.
- SignPrehash cần khoá riêng tư. Thao tác này chuyển đổi giá trị tiền băm thành chữ ký.
Chữ ký nhận được là chữ ký thông thường trên thông báo gốc. Bạn xác minh chữ ký đó bằng nguyên tắc cơ bản Chữ ký số PublicKeyVerify thông thường và người xác minh không cần phải biết (hoặc quan tâm) đến việc chữ ký được tạo trong hai bước.
Coi giá trị tiền băm là các byte không rõ ràng. Khoá này có kích thước cố định và mang mã nhận dạng của khoá mà khoá được tính toán, nhưng bố cục của khoá là một phần của định dạng truyền dữ liệu của Tink và bạn không nên tự phân tích cú pháp hoặc tạo khoá. Nếu bạn đang chuyển Tink hoặc cần thông tin chi tiết ở cấp độ byte, hãy xem Định dạng truyền dữ liệu của Tink.
Hãy sử dụng cặp thành phần cơ bản này khi:
- Khoá ký nằm ở một nơi khác, chẳng hạn như trong HSM, trong KMS hoặc sau ranh giới RPC và bạn không muốn gửi toàn bộ thông báo qua ranh giới đó.
- Thông báo có kích thước lớn và trình ký từ xa áp dụng giới hạn kích thước yêu cầu.
Nếu không có trường hợp nào trong số này áp dụng, hãy sử dụng nguyên tắc cơ bản Chữ ký số đơn giản: nguyên tắc này đơn giản hơn và khó bị sử dụng sai mục đích hơn.
Bộ khoá
Hai nguyên hàm này chọn khoá theo cách khác nhau, giống như cách ký và xác minh đối với nguyên hàm Chữ ký số:
Prehash.Computeluôn sử dụng khoá chính của bộ khoá công khai và ghi lại mã nhận dạng của khoá đó trong giá trị tiền băm. Đây là bên chọn khoá mà chữ ký sẽ được tạo.SignPrehash.Signđọc mã khoá từ giá trị tiền băm và ký bằng khoá đã bật khớp của bộ khoá riêng tư. Đó là bên tuân theo lựa chọn mà người khác đã đưa ra. Nếu không có khoá nào được bật trong keyset có mã nhận dạng đó, thì lệnh gọi sẽ không thành công.
Mọi khoá trong một bộ khoá SignPrehash đều phải có yêu cầu về mã nhận dạng, nếu không, việc tạo nguyên thuỷ sẽ không thành công.
Đảm bảo an ninh tối thiểu
- Chữ ký kết quả có các thuộc tính tương tự như chữ ký do nguyên tắc cơ bản Chữ ký số tạo ra với cùng loại khoá.
- Tink thêm 5 byte vào giá trị tiền băm, trong đó có một giá trị đặc biệt được dành riêng và mã nhận dạng của khoá mà giá trị đó được tính toán.
SignPrehashchỉ ký giá trị bằng khoá đó. Việc giá trị có được liên kết theo phương pháp mã hoá với khoá đó hay không phụ thuộc vào thuật toán; đối với External Mu ML-DSA, giá trị này được liên kết, hãy xem định dạng truyền dữ liệu Tink. - Tin nhắn có thể có độ dài tuỳ ý.
Những điều cần chú ý
- Người ký không thể kiểm tra nội dung mà họ ký. Bất kỳ ai có thể gọi
SignPrehashđều có thể nhận được một thông báo tuỳ ý đã ký và người ký không có cách nào áp dụng chính sách cho nội dung thông báo. Bảo vệ quyền truy cập vàoSignPrehashgiống như cách bạn bảo vệ quyền truy cập vàoPublicKeySign. - Bảo vệ giá trị được băm trước trong quá trình truyền. Đây không phải là bí mật, nhưng kẻ tấn công có thể sửa đổi nó trong quá trình truyền dữ liệu sẽ kiểm soát nội dung được ký.
Chọn loại khoá
ML-DSA ở chế độ External Mu (Mu bên ngoài), như mô tả trong RFC 9881, là thuật toán duy nhất mà Tink hỗ trợ cho Prehash và SignPrehash. Bạn nên sử dụng khoá ML-DSA tiêu chuẩn với các thành phần cơ bản này.
Bạn nên dùng ML_DSA_65 cho hầu hết các trường hợp sử dụng.
Khoá phải có yêu cầu về mã nhận dạng, vì mọi giá trị tiền băm đều bắt đầu bằng một tiền tố chứa mã nhận dạng của khoá mà giá trị đó được tính toán. Các biến thể sau được chấp nhận:
TINK– chữ ký kết quả bắt đầu bằng tiền tố đầu ra 5 byte thông thường của Tink.NO_PREFIX_WITH_PREHASH_ID– chữ ký kết quả không có tiền tố đầu ra, trong khi khoá vẫn có mã nhận dạng mà giá trị tiền xử lý cần.
Không được hỗ trợ các khoá sử dụng biến thể NO_PREFIX (thô) vì các khoá này không có mã khoá.
Ví dụ
Các ví dụ sau đây ký một thông báo theo hai bước, sau đó xác minh chữ ký kết quả bằng nguyên tắc cơ bản Chữ ký số thông thường.
Các thông tin này được hiển thị dưới dạng một khối để dễ đọc. Trong quá trình triển khai thực tế, hai bước này sẽ chạy ở những nơi khác nhau; hãy xem phần Tôi muốn ký dữ liệu bằng một trình ký từ xa để biết hướng dẫn từng bước.
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);
Go
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 }
Chủ đề có liên quan
- Tôi muốn ký dữ liệu bằng một trình ký từ xa – hướng dẫn từng bước về quy trình gồm 2 bước.
- Chữ ký số – ký và xác minh trong một bước duy nhất, khi người ký có thể xem thư.
- Các loại khoá nguyên thuỷ được hỗ trợ theo ngôn ngữ
- Định dạng Tink wire – bố cục ở cấp độ byte của giá trị tiền băm, để chuyển Tink sang một ngôn ngữ khác.