Node.js और WebCrypto के बीच ईसीडीएसए हस्ताक्षर असंगत प्रतीत होते हैं?



cryptography ecdsa (1)

मैं हस्ताक्षर करने के लिए निम्न उदाहरण का उपयोग कर रहा हूं + Node.js में सत्यापन: https://github.com/nodejs/node-v0.x-archive/issues/6904 सत्यापन Node.js में सफल होता है लेकिन WebCrypto में विफल रहता है। इसी तरह, WebCrypto का उपयोग करने वाले एक संदेश को नोड। जेएस में सत्यापित करने में विफल रहता है।

यहां कोड है जिसे मैं वेबक्रिएप्टो- https://jsfiddle.net/aj49e8sj/ का उपयोग करके नोड। जेएस स्क्रिप्ट से निर्मित एक हस्ताक्षर को सत्यापित करने के लिए उपयोग किया था। क्रोम 54.0.2840.27 और फ़ायरफ़ॉक्स 48.0.2 दोनों में परीक्षण किया गया

// From https://github.com/nodejs/node-v0.x-archive/issues/6904
var keys = {
  priv: '-----BEGIN EC PRIVATE KEY-----\n' +
        'MHcCAQEEIF+jnWY1D5kbVYDNvxxo/Y+ku2uJPDwS0r/VuPZQrjjVoAoGCCqGSM49\n' +
        'AwEHoUQDQgAEurOxfSxmqIRYzJVagdZfMMSjRNNhB8i3mXyIMq704m2m52FdfKZ2\n' +
        'pQhByd5eyj3lgZ7m7jbchtdgyOF8Io/1ng==\n' +
        '-----END EC PRIVATE KEY-----\n',
  pub: '-----BEGIN PUBLIC KEY-----\n' +
       'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEurOxfSxmqIRYzJVagdZfMMSjRNNh\n' +
       'B8i3mXyIMq704m2m52FdfKZ2pQhByd5eyj3lgZ7m7jbchtdgyOF8Io/1ng==\n' +
       '-----END PUBLIC KEY-----\n'
};
var message = (new TextEncoder('UTF-8')).encode('hello');

// Algorithm used in Node.js script is ecdsa-with-SHA1, key generated with prime256v1
var algorithm = {
    name: 'ECDSA',
    namedCurve: 'P-256',
    hash: {
        name: 'SHA-1'
    }
};

// Signature from obtained via above Node.js script
var sig64 = 'MEUCIQDkAtiomagyHFi7dNfxMrzx/U0Gk/ZhmwCqaL3TimvlswIgPgeDqgZNqfR5/FZZASYsczUAhGSXjuycLhWnvk20qKc=';

// Decode base64 string into ArrayBuffer
var b64Decode = (str) => Uint8Array.from(atob(str), x => x.charCodeAt(0));

// Get base64 string from public key
const key64 = keys.pub.split('\n')
    .filter(x => x.length > 0 && !x.startsWith('-----'))
    .join('');

// Convert to buffers
var sig = b64Decode(sig64);
var keySpki = b64Decode(key64);

// Import and verify
// Want 'Verification result: true' but will get 'false'
var importKey = crypto.subtle.importKey('spki', keySpki, algorithm, true, ['verify'])
    .then(key => crypto.subtle.verify(algorithm, key, sig, message))
    .then(result => console.log('Verification result: ' + result));

SHA-1 की बजाय SHA-256 का उपयोग करते हुए इसी तरह की समस्या के साथ संबंधित प्रश्न: Node.js / crypto के साथ ECDSA हस्ताक्षर उत्पन्न करना

मैंने जिस चीज की जांच की है:

  • मैंने नोड.जेएस कुंजियों को डीकोड कर दिया और सत्यापित किया कि उन्हें वेब कैरीप्टो के माध्यम से उत्पन्न की गई कुंजी के समान ओआईडी है। यह मुझे बताता है कि मैं सही घटता का उपयोग कर रहा हूँ।
  • SHA-1 को स्पष्ट रूप से दोनों स्थानों में उपयोग करने के लिए हैश के रूप में पहचाना जाता है।
  • ईसीडीएसए को स्पष्ट रूप से दोनों नोड। जेएस और वेबक्रिप्टो में पहचाना गया है।

मैं Node.js से प्राप्त हस्ताक्षर को सफलतापूर्वक कैसे सत्यापित कर सकता हूं और इसके विपरीत- वेबक्रिप्टो से निर्मित नोड। जेएस में एक हस्ताक्षर सत्यापित करें? या ऐसे तरीके से अलग तरह से अलग तरह के मानक के कार्यान्वयन से उन्हें असंगत बना देता है?

संपादित करें:

  • वेबक्रिप्टो हस्ताक्षर (64 बाइट्स): uTaUWTfF + AjN3aPj0b5Z2d1HybUEpV / phv / P9RtfKaGXtcYnbgfO43IRg46rznG3 / WnWwJ2sV6mPOEnEPR0vWw ==
  • नोड। जेएस हस्ताक्षर (71 बाइट्स): MEUCIQDkAtiomagyHFi7dNfxMrzx / U0Gk / ZhmwCqaL3TimvlswIgPgeDqgZNqfR5 / FZZASYsczUAhGSXjuycLhWnvk20qKc =

सत्यापित नोड.जेएस हस्ताक्षर डीईआर एन्कोडेड है और वेबक्रिप्पोट्रू हस्ताक्षर नहीं है।


इन पुस्तकालयों में से किसी का उपयोग नहीं करने के बाद मैं कुछ के लिए नहीं कह सकता, लेकिन एक संभावना यह है कि वे हस्ताक्षर के लिए एक ही एन्कोडिंग प्रकार का उपयोग नहीं करते हैं डीएसए / ईसीडीएसए के लिए दो मुख्य प्रारूप हैं, आईईईई पी 1363 (विंडोज़ द्वारा उपयोग किया जाता है) और डीईआर (ओपनएसएसएल द्वारा उपयोग किया जाता है)।

"विन्डोज़" प्रारूप का प्रीसेट आकार होना चाहिए (डीएसए के लिए प्रश्न और ईसीडीएसए के लिए पी (विंडोज 2 का समर्थन नहीं करता है, लेकिन अगर यह संभवतः चार -2 ईसीडीएसए के लिए एम होना होता है)) है। फिर दोनों r और s बाएं पैड होते हैं 0 जब तक वे उस लंबाई से मिलते हैं

r = 0x305 का कानूनी उदाहरण होने के लिए और s = 0x810522 , आकार के साथ (क्यू) 3 बाइट्स होने के नाते:

// r
000305
// s
810522

"ओपनएसएसएल" प्रारूप के लिए इसे डीईआर के नियमों के तहत एन्क्लोड किया गया है, (अनुक्रम (आर), इन्टेजीर (एस)), जो दिखता है

// SEQUENCE
30
  // (length of payload)
  0A
  // INTEGER(r)
  02
    // (length of payload)
    02
    // note the leading 0x00 is omitted
    0305
  // INTEGER(s)
  02
    // (length of payload)
    04
    // Since INTEGER is a signed type, but this represented a positive number,
    // a 0x00 has to be inserted to keep the sign bit clear.
    00810522

या, कॉम्पैक्ट:

  • विंडोज: 000305810522
  • ओपनएसएसएल: 300A02020305020400810522

"विन्डोज़" स्वरूप हमेशा हमेशा ही रहता है, हमेशा एक ही लंबाई। "ओपनएसएसएल" प्रारूप आमतौर पर लगभग 6 बाइट्स बड़ा होता है, लेकिन बीच में एक बाइट हासिल या खो सकता है; इसलिए कभी-कभी यह कभी-कभी अजीब होता है।

Base64-decoding आपके sig64 मान से पता चलता है कि यह डीईआर एन्कोडिंग का उपयोग कर रहा है। WebCrypto के साथ कुछ हस्ताक्षर उत्पन्न करें; यदि कोई भी 0x30 साथ शुरू नहीं होता है तो आपके पास आईईईई / डीईआर समस्या है





webcryptoapi