2016-09-18 12 views
3

Node.jsで署名と検証に次の例を使用しています:https://github.com/nodejs/node-v0.x-archive/issues/6904。検証はNode.jsでは成功しますが、WebCryptoでは失敗します。同様に、WebCryptoを使用して署名されたメッセージは、Node.jsで検証できません。Node.jsとWebCryptoの間のECDSAシグネチャは互換性がないようですか?

ここでは、WebCrypto-https://jsfiddle.net/aj49e8sj/を使用してNode.jsスクリプトから生成された署名を検証するために使用したコードを示します。代わりに、SHA-1のSHA-256を使用して、同様の問題を持つ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)); 

クローム54.0.2840.27とFirefoxの両方でテスト関連の質問:私がチェックしたGenerating ECDSA signature with Node.js/crypto

もの:

  • 私はNode.jsキーをデコードし、WebCryptoで生成されたキーと同じOIDを持っていることを確認しました。これは正しい曲線を使用していることを示しています。
  • SHA-1は、両方の場所で使用するハッシュとして明示的に識別されます。
  • ECDSAは、Node.jsとWebCryptoの両方で明示的に識別されます。

Node.jsから受信した署名を正常に検証するにはどうすればよいのですか?その逆の場合 - WebCryptoから生成されたNode.jsの署名を検証しますか?あるいは、標準の実装が、互換性のないようなやり方で微妙に異なるのでしょうか?

編集:

  • WebCrypto署名(64バイト):uTaUWTfF + AjN3aPj0b5Z2d1HybUEpV/PHV/P9RtfKaGXtcYnbgfO43IRg46rznG3/WnWwJ2sV6mPOEnEPR0vWw ==
  • Node.jsの署名(71バイト):MEUCIQDkAtiomagyHFi7dNfxMrzx/U0Gk/ZhmwCqaL3TimvlswIgPgeDqgZNqfR5/FZZASYsczUAhGSXjuycLhWnvk20qKc =

検証されたNode.js署名はDERでエンコードされ、WebCrypto署名は暗号化されていません。

答えて

1

これらのライブラリのどちらも使用していないので、私は確かに言えませんが、シグネチャに同じエンコードタイプを使用しない可能性があります。 DSA/ECDSAには、IEEE P1363(Windowsで使用)とDER(OpenSSLで使用)という2つの主要フォーマットがあります。

"Windows"形式は、DSAの場合はQ、ECDSAの場合はP(WindowsはChar-2をサポートしていませんが、そうであればChar-2 ECDSAの場合M ))。次に、rsの両方に、その長さに達するまで0が左パッドされます。それは配列(整数としてDERの規則の下で符号化されている「OpenSSLの」フォーマットについて

// r 
000305 
// s 
810522 

:のsizeofでr = 0x305s = 0x810522の法的一例であるには小さすぎるで

(Q)は3バイトであります

  • のWi:

    // 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 
    

    や、コンパクトのように見える(r)は、INTEGER(S))、 ndows:000305810522

  • のOpenSSL:300A02020305020400810522

の "Windows" 形式も、常に、常に同じ長さです。 「OpenSSL」形式は通常約6バイト大きくなりますが、途中でバイトを取得または失う可能性があります。時には偶数、時には奇妙なこともあります。

sig64の値をBase64でデコードすると、DERエンコーディングが使用されていることが示されます。 WebCryptoでカップルの署名を生成する。いずれかが0x30で始まらない場合は、IEEE/DERの問題があります。

+0

お金で右に! Node.jsはOpenSSLをフードの下で使用しているので、その側のDERエンコーディングは意味があります。 WebCrypto仕様によれば、結果はrであり、連結されています。https://www.w3.org/TR/WebCryptoAPI/#ecdsa-operations – SiNiquity

関連する問題