मुझे रिमोट साइनर की मदद से डेटा पर हस्ताक्षर करना है

हमारा सुझाव है कि जब निजी कुंजी ऐसी जगह पर हो जहां मैसेज नहीं भेजा जा सकता, तब ML_DSA_65 कुंजी के साथ Prehash और SignPrehash प्रिमिटिव का इस्तेमाल करें.

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

Prehash और SignPrehash प्रिमिटिव, हस्ताक्षर करने की प्रोसेस को दो चरणों में बांटकर इस समस्या को हल करती हैं. सिग्नेचर करने वाले व्यक्ति को, मैसेज की छोटी प्रीहैश वैल्यू भेजी जाती है. यह वैल्यू सिर्फ़ सार्वजनिक पासकोड का इस्तेमाल करके कैलकुलेट की जाती है. हस्ताक्षर करने वाला व्यक्ति, मैसेज को देखे बिना निजी कुंजी का इस्तेमाल करके, उसे हस्ताक्षर में बदल देता है. External Mu मोड में एमएल-डीएसए का इस्तेमाल करने पर, प्रीहैश वैल्यू 69 बाइट होती है. इस मोड में, Tink एल्गोरिदम काम करता है. मैसेज का साइज़ चाहे जो भी हो, प्रीहैश वैल्यू हमेशा 69 बाइट ही रहेगी.

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

शुरू करने से पहले

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

पहला चरण: प्रीहैश वैल्यू का हिसाब लगाना

इस फ़ंक्शन को मैसेज में कहीं भी चलाया जा सकता है. इसके लिए, सिर्फ़ सार्वजनिक पासकोड सेट की ज़रूरत होती है.

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

ऐप पर जाएं

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
}

दूसरा चरण: हस्ताक्षर करने वाले व्यक्ति को प्रीहैश वैल्यू भेजना

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

तीसरा चरण: प्रीहैश वैल्यू पर हस्ताक्षर करना

इसे उस जगह पर चलाएं जहां निजी कुंजी मौजूद है.

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

ऐप पर जाएं

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
}

चौथा चरण: हस्ताक्षर की पुष्टि करना

पुष्टि करने की प्रोसेस, ओरिजनल मैसेज पर डिजिटल हस्ताक्षर करने की सामान्य प्रोसेस है. यह प्रीहैश वैल्यू पर नहीं की जाती.

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

ऐप पर जाएं

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

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 में बताया गया है. यह प्रीहैश और SignPrehash के लिए, Tink के साथ काम करने वाला एकमात्र एल्गोरिदम है. आपको इन प्रिमिटिव के साथ स्टैंडर्ड एमएल-डीएसए पासकोड का इस्तेमाल करना चाहिए.

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

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

  • TINK -- the resulting signature starts with Tink's usual 5-byte output prefix.
  • NO_PREFIX_WITH_PREHASH_ID -- इस हस्ताक्षर में कोई आउटपुट प्रीफ़िक्स नहीं है. हालांकि, कुंजी में अब भी वह आईडी है जिसकी ज़रूरत प्रीहैश वैल्यू को होती है.

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