Prehash और SignPrehash

Prehash और SignPrehash प्रिमिटिव, डिजिटल सिग्नेचर की कंप्यूटिंग को दो चरणों में बांटते हैं:

  1. प्रीहैश के लिए सिर्फ़ सार्वजनिक कुंजी की ज़रूरत होती है. यह किसी भी लंबाई के मैसेज को, तय साइज़ वाली छोटी प्रीहैश वैल्यू में बदलता है.
  2. SignPrehash के लिए, private कुंजी की ज़रूरत होती है. यह प्रीहैश वैल्यू को सिग्नेचर में बदलता है.

इस तरह से जनरेट किया गया हस्ताक्षर, ओरिजनल मैसेज पर किया गया सामान्य हस्ताक्षर होता है. इसकी पुष्टि, सामान्य डिजिटल सिग्नेचर PublicKeyVerify प्रिमिटिव से की जाती है. साथ ही, पुष्टि करने वालों को यह जानने की ज़रूरत नहीं होती कि हस्ताक्षर दो चरणों में बनाया गया था.

प्रीहैश वैल्यू को ओपेक बाइट के तौर पर मानें. इसका साइज़ तय होता है. इसमें उस कुंजी का आईडी होता है जिसके लिए इसे कंप्यूट किया गया था. हालांकि, इसका लेआउट, Tink के वायर फ़ॉर्मैट का हिस्सा होता है. इसलिए, आपको इसे खुद से पार्स या कंस्ट्रक्ट नहीं करना चाहिए. अगर आपको Tink को पोर्ट करना है या बाइट-लेवल की जानकारी चाहिए, तो Tink वायर फ़ॉर्मैट देखें.

इन प्रिमिटिव का इस्तेमाल तब करें, जब:

  • हस्ताक्षर करने की कुंजी किसी दूसरी जगह पर मौजूद है. उदाहरण के लिए, एचएसएम, केएमएस या आरपीसी बाउंड्री के पीछे. साथ ही, आपको पूरा मैसेज उस बाउंड्री के पार नहीं भेजना है.
  • मैसेज का साइज़ बहुत बड़ा है. साथ ही, रिमोट हस्ताक्षर करने वाले व्यक्ति ने अनुरोध के साइज़ की सीमा तय की है.

अगर इनमें से कोई भी लागू नहीं होता है, तो इसके बजाय सामान्य डिजिटल सिग्नेचर प्रिमिटिव का इस्तेमाल करें: यह ज़्यादा आसान है और इसका गलत इस्तेमाल करना मुश्किल है.

कीसेट

दोनों प्रिमिटिव, कुंजियों को अलग-अलग तरीके से चुनते हैं. ठीक उसी तरह जैसे साइनिंग और पुष्टि करने की सुविधा, डिजिटल सिग्नेचर प्रिमिटिव के लिए काम करती है:

  • Prehash.Compute हमेशा सार्वजनिक पासकोड सेट की प्राइमरी कुंजी का इस्तेमाल करता है. साथ ही, उस कुंजी के आईडी को प्रीहैश वैल्यू में रिकॉर्ड करता है. यह वह पक्ष होता है जो यह चुनता है कि हस्ताक्षर किस कुंजी से किया जाएगा.
  • SignPrehash.Sign, प्रीहैश वैल्यू से कुंजी आईडी को पढ़ता है और निजी पासकोड के सेट की मैच करने वाली चालू की गई कुंजी से साइन करता है. यह वह पक्ष है जो किसी और व्यक्ति के पहले से किए गए फ़ैसले को फ़ॉलो करता है. अगर चालू किए गए किसी भी कीसेट में वह आईडी नहीं है, तो कॉल नहीं किया जा सकेगा.

SignPrehash के हर कीसेट में आईडी होना ज़रूरी है. ऐसा न होने पर, प्रिमिटिव नहीं बन पाएगा.

सुरक्षा से जुड़ी कम से कम गारंटी

  • नतीजे के तौर पर मिले हस्ताक्षर में वही प्रॉपर्टी होती हैं जो एक ही तरह की कुंजी के साथ डिजिटल सिग्नेचर प्रिमिटिव से जनरेट किए गए हस्ताक्षर में होती हैं.
  • Tink, प्रीहैश वैल्यू में 5 बाइट का प्रीफ़िक्स जोड़ता है. इसमें खास रिज़र्व की गई वैल्यू और उस कुंजी का आईडी होता है जिसके लिए इसे कंप्यूट किया गया था. SignPrehash सिर्फ़ उस कुंजी की मदद से वैल्यू पर हस्ताक्षर करता है. वैल्यू, उस कुंजी से क्रिप्टोग्राफ़िक तौर पर जुड़ी है या नहीं, यह एल्गोरिदम पर निर्भर करता है. External Mu ML-DSA के लिए, यह जुड़ी होती है. इसके बारे में जानने के लिए, Tink वायर फ़ॉर्मैट देखें.
  • मैसेज की लंबाई कितनी भी हो सकती है.

ध्यान रखने लायक बातें

  • हस्ताक्षर करने वाला व्यक्ति, उस कॉन्टेंट की जांच नहीं कर सकता जिस पर उसे हस्ताक्षर करना है. SignPrehash को कॉल करने वाला कोई भी व्यक्ति, किसी भी मैसेज पर हस्ताक्षर कर सकता है. हस्ताक्षर करने वाले व्यक्ति के पास, मैसेज के कॉन्टेंट पर नीति लागू करने का कोई तरीका नहीं होता. SignPrehash के ऐक्सेस को ठीक उसी तरह सुरक्षित रखें जिस तरह PublicKeySign के ऐक्सेस को सुरक्षित रखा जाता है.
  • ट्रांज़िट में प्रीहैश वैल्यू को सुरक्षित रखें. यह कोई सीक्रेट नहीं है. हालांकि, हमलावर इसे फ़्लाइट में बदल सकता है. इससे यह कंट्रोल किया जा सकता है कि किस चीज़ पर हस्ताक्षर किए गए हैं.

कुंजी का टाइप चुनें

External Mu मोड में एमएल-डीएसए, आरएफ़सी 9881 में बताए गए तरीके के मुताबिक, प्रीहैश और साइनप्रीहैश के लिए Tink का इस्तेमाल किया जा सकता है. आपको इन प्रिमिटिव के साथ स्टैंडर्ड एमएल-डीएसए पासकोड का इस्तेमाल करना चाहिए.

हम ज़्यादातर मामलों में, ML_DSA_65 का इस्तेमाल करने का सुझाव देते हैं.

कुंजी में आईडी की ज़रूरत होती है, क्योंकि हर प्रीहैश वैल्यू ऐसे प्रीफ़िक्स से शुरू होती है जिसमें उस कुंजी का आईडी होता है जिसके लिए उसे कंप्यूट किया गया था. इन वैरिएंट को स्वीकार किया जाता है:

  • TINK -- इससे मिलने वाला सिग्नेचर, Tink के सामान्य 5-बाइट आउटपुट प्रीफ़िक्स से शुरू होता है.
  • NO_PREFIX_WITH_PREHASH_ID -- इस हस्ताक्षर में कोई आउटपुट प्रीफ़िक्स नहीं है. हालांकि, कुंजी में अब भी वह आईडी है जिसकी ज़रूरत प्रीहैश वैल्यू को होती है.

NO_PREFIX (रॉ) वैरिएंट का इस्तेमाल करने वाली कुंजियों के साथ काम नहीं करता, क्योंकि उनमें कुंजी आईडी नहीं होता.

उदाहरण

यहां दिए गए उदाहरणों में, दो चरणों में मैसेज पर हस्ताक्षर करने और फिर सामान्य डिजिटल हस्ताक्षर प्रिमिटिव की मदद से, नतीजे के तौर पर मिले हस्ताक्षर की पुष्टि करने का तरीका बताया गया है.

इन्हें पढ़ने में आसानी हो, इसलिए एक ब्लॉक के तौर पर दिखाया जाता है. असल डिप्लॉयमेंट में, ये दोनों चरण अलग-अलग जगहों पर पूरे किए जाते हैं. चरण-दर-चरण निर्देशों के लिए, मुझे रिमोट हस्ताक्षर करने वाले व्यक्ति के खाते से डेटा पर हस्ताक्षर करने हैं लेख पढ़ें.

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);

ऐप पर जाएं

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
}