เราขอแนะนำให้ใช้ Primitive Prehash และ SignPrehash กับคีย์ ML_DSA_65 เมื่อ คีย์ส่วนตัวอยู่ในที่ที่ส่งข้อความไม่ได้
บางครั้งฝ่ายที่ถือคีย์การลงนามอาจรับข้อความเองไม่ได้ หรือไม่ควรรับข้อความเอง เนื่องจากคีย์อยู่ใน HSM หรือ KMS หรือข้อความมีขนาดใหญ่กว่าขีดจำกัดขนาดคำขอของผู้ลงนาม
Primitive Prehash และ SignPrehash แก้ปัญหานี้ด้วยการแบ่งการลงนามออกเป็น 2 ขั้นตอน คุณจะคำนวณค่าแฮชก่อนหน้าแบบย่อในตำแหน่งที่มีข้อความ โดยใช้เฉพาะคีย์สาธารณะ และส่งไปยังผู้ลงนาม ผู้ลงนามจะเปลี่ยนเป็นลายเซ็น โดยใช้คีย์ส่วนตัวโดยที่ไม่เห็นข้อความ เมื่อใช้ ML-DSA ในโหมด External Mu ซึ่งเป็นอัลกอริทึมที่ Tink รองรับ ค่าก่อนแฮชจะมีขนาด 69 ไบต์ ไม่ว่าข้อความจะมีขนาดเท่าใดก็ตาม
ลายเซ็นที่คุณได้รับกลับมาคือลายเซ็นปกติในข้อความต้นฉบับ ผู้ตรวจสอบใช้ ลายเซ็นดิจิทัลแบบปกติและไม่จำเป็นต้องทราบว่า มี 2 ขั้นตอนที่เกี่ยวข้อง
ก่อนเริ่มต้น
สร้างชุดคีย์ ML-DSA ที่คีย์มีข้อกำหนดรหัส ไม่ว่าจะเป็นตัวแปร TINK หรือ NO_PREFIX_WITH_PREHASH_ID หากไม่ต้องการคำนำหน้าเอาต์พุต
ในลายเซ็นที่ได้ มอบชุดคีย์ส่วนตัวให้ผู้ลงนามและมอบชุดคีย์สาธารณะที่เกี่ยวข้องให้ฝั่ง
การแฮชล่วงหน้า ผู้ลงนามควรมีคีย์ที่เปิดใช้สำหรับรหัสคีย์ทุกรายการที่ฝั่งการแฮชล่วงหน้าสร้างได้ ดูชุดคีย์
ขั้นตอนที่ 1: คำนวณค่าก่อนแฮช
เรียกใช้คำสั่งนี้ในตำแหน่งที่มีข้อความ โดยใช้เพียงชุดคีย์สาธารณะ
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 }
ขั้นตอนที่ 2: ส่งค่าก่อนแฮชไปยังผู้ลงนาม
ส่งค่าก่อนแฮชไปยังที่ใดก็ตามที่มีคีย์ส่วนตัว แม้จะไม่ใช่ความลับ แต่คุณต้องปกป้องความสมบูรณ์ของคีย์ในระหว่างการส่ง เนื่องจากผู้โจมตีที่สามารถแก้ไขคีย์ในระหว่างการส่งจะควบคุมสิ่งที่ได้รับการลงนามได้
ขั้นตอนที่ 3: ลงนามค่าก่อนแฮช
เรียกใช้คำสั่งนี้ในตำแหน่งที่มีคีย์ส่วนตัว
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 }
ขั้นตอนที่ 4: ยืนยันลายเซ็น
การยืนยันคือขั้นตอนลายเซ็นดิจิทัลปกติ ในข้อความเดิม ไม่ใช่ค่าก่อนแฮช
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 และ SignPrehash
Primitive Prehash และ SignPrehash จะแบ่งการคำนวณลายเซ็นดิจิทัล ออกเป็น 2 ขั้นตอน ดังนี้
- Prehash ต้องการเพียงคีย์สาธารณะ โดยจะเปลี่ยนข้อความที่มีความยาวเท่าใดก็ได้ ให้เป็นค่าก่อนแฮชแบบสั้นที่มีขนาดคงที่
- SignPrehash ต้องใช้คีย์ส่วนตัว โดยจะเปลี่ยนค่าก่อนแฮชเป็น ลายเซ็น
ลายเซ็นที่ออกมาคือลายเซ็นธรรมดาในข้อความต้นฉบับ
คุณยืนยันด้วย
ลายเซ็นดิจิทัล PublicKeyVerifyแบบปกติ และ
ผู้ยืนยันไม่จำเป็นต้องทราบหรือสนใจว่าลายเซ็นสร้างขึ้นใน
2 ขั้นตอน
ถือว่าค่าก่อนแฮชเป็นไบต์ทึบ โดยมีขนาดคงที่และมี รหัสของคีย์ที่ใช้คำนวณ แต่เลย์เอาต์เป็นส่วนหนึ่งของรูปแบบการส่งผ่านข้อมูลของ Tink และคุณไม่ควรแยกวิเคราะห์หรือสร้างด้วยตนเอง หากคุณกำลังพอร์ต Tink หรือต้องการรายละเอียดระดับไบต์ โปรดดูรูปแบบการส่งผ่านข้อมูลของ Tink
ใช้คู่ดั้งเดิมนี้ในกรณีต่อไปนี้
- คีย์การลงนามอยู่ในที่อื่น เช่น ใน HSM, ใน KMS หรืออยู่หลังขอบเขต RPC และคุณไม่ต้องการส่งข้อความทั้งหมด ข้ามขอบเขตนั้น
- ข้อความมีขนาดใหญ่ และโปรแกรมลงนามระยะไกลบังคับใช้ขีดจำกัดขนาดคำขอ
หากไม่ตรงกับกรณีใดกรณีหนึ่ง ให้ใช้ Primitive Digital Signature แบบธรรมดาแทน ซึ่งจะง่ายกว่า และใช้งานในทางที่ผิดได้ยากกว่า
ชุดคีย์
Primitive ทั้ง 2 รายการเลือกคีย์ต่างกัน ในลักษณะเดียวกับการลงนามและการยืนยันสำหรับ Primitive Digital Signature
Prehash.Computeจะใช้คีย์หลักของชุดคีย์สาธารณะเสมอ และ บันทึกรหัสของคีย์นั้นในค่าก่อนแฮช ซึ่งเป็นฝ่ายที่เลือก คีย์ที่จะใช้สร้างลายเซ็นSignPrehash.Signอ่านรหัสคีย์จากค่าก่อนแฮชและลงนามด้วยคีย์ที่เปิดใช้ที่ตรงกันของชุดคีย์ส่วนตัว ซึ่งเป็นด้านที่ทำตามตัวเลือกที่ผู้อื่นเลือกไว้แล้ว หากไม่มีคีย์ที่เปิดใช้ใน ชุดคีย์ที่มีรหัสดังกล่าว การเรียกจะล้มเหลว
คีย์ทุกรายการในชุดคีย์ SignPrehash ต้องมีข้อกำหนดรหัส ไม่เช่นนั้นการสร้าง Primitive จะล้มเหลว
การรับประกันความปลอดภัยขั้นต่ำ
- ลายเซ็นที่ได้จะมีคุณสมบัติเหมือนกับลายเซ็นที่สร้างโดย องค์ประกอบพื้นฐานลายเซ็นดิจิทัลที่มีคีย์ประเภทเดียวกัน
- Tink จะนำหน้าค่าก่อนแฮชด้วย 5 ไบต์ที่มีค่าพิเศษที่สงวนไว้
และรหัสของคีย์ที่ใช้คำนวณ
SignPrehashจะลงนามใน ค่าด้วยคีย์นั้นเท่านั้น ค่าจะผูกกับคีย์โดยใช้การเข้ารหัสหรือไม่นั้นขึ้นอยู่กับอัลกอริทึม สำหรับ External Mu ML-DSA จะผูกกัน ดูรูปแบบการเชื่อมต่อ Tink - ข้อความมีความยาวเท่าใดก็ได้
สิ่งที่ต้องระวัง
- ผู้ลงนามตรวจสอบสิ่งที่ตนลงนามไม่ได้ ทุกคนที่โทรหา
SignPrehashได้จะรับข้อความที่ลงนามโดยพลการได้ และผู้ลงนามจะไม่มีวิธีใช้ นโยบายกับเนื้อหาของข้อความ ปกป้องสิทธิ์เข้าถึงSignPrehashเหมือนกับที่คุณปกป้องสิทธิ์เข้าถึงPublicKeySign - ปกป้องค่าก่อนแฮชระหว่างการรับส่ง แม้จะไม่ใช่ข้อมูลลับ แต่ผู้โจมตี ที่แก้ไขข้อมูลนี้ในระหว่างการส่งได้จะควบคุมสิ่งที่ได้รับการลงนาม
เลือกประเภทคีย์
ML-DSA ในโหมด External Mu ตามที่อธิบายไว้ใน RFC 9881 เป็นอัลกอริทึมเดียวที่ Tink รองรับสำหรับ Prehash และ SignPrehash คุณควรใช้คีย์ ML-DSA มาตรฐานกับ Primitive เหล่านี้
เราขอแนะนำให้ใช้ ML_DSA_65 สำหรับกรณีการใช้งานส่วนใหญ่
คีย์ต้องมีข้อกำหนดรหัส เนื่องจากค่าก่อนแฮชทุกค่าจะขึ้นต้นด้วยคำนำหน้าที่มีรหัสของคีย์ที่ใช้คำนวณ เรายอมรับรูปแบบต่อไปนี้
TINK-- ลายเซ็นที่ได้จะขึ้นต้นด้วยเอาต์พุต 5 ไบต์ปกติของ TinkNO_PREFIX_WITH_PREHASH_ID-- ลายเซ็นที่ได้จะไม่มีคำนำหน้าเอาต์พุต ในขณะที่คีย์ยังคงมีรหัสที่ค่าก่อนแฮชต้องการ
ไม่รองรับคีย์ที่ใช้ตัวแปร NO_PREFIX (ดิบ) เนื่องจากไม่มีรหัสคีย์