当前位置: 首页 > 面试题库 >

Node.js和WebCrypto之间的ECDSA签名似乎不兼容?

苗冯浩
2023-03-14
问题内容

我正在使用以下示例在Node.js中进行签名和验证:https
:
//github.com/nodejs/node-v0.x-archive/issues/6904。验证在Node.js中成功,但在WebCrypto中失败。同样,使用WebCrypto签名的消息无法在Node.js中验证。

这是我用来验证使用WebCrypto- https:
//jsfiddle.net/aj49e8sj/从Node.js脚本生成的签名的代码。已在Chrome 54.0.2840.27和Firefox
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-256而不是SHA-1的类似问题的相关问题:使用Node.js /
crypto生成ECDSA签名

我检查过的事情:

  • 我解码了Node.js密钥,并验证了它们与通过WebCrypto生成的密钥具有相同的OID。这告诉我我使用了正确的曲线。
  • SHA-1被明确标识为要在两个位置使用的哈希。
  • 在Node.js和WebCrypto中都明确标识了ECDSA。

我如何才能成功验证从Node.js收到的签名,反之亦然-验证从WebCrypto生成的Node.js中的签名?还是以使它们不兼容的方式使标准的实现细微不同?

编辑:

  • WebCrypto签名(64字节):uTaUWTfF + AjN3aPj0b5Z2d1HybUEpV / phv / P9RtfKaGXtcYnbgfO43IRg46rznG3 / WnWwJ2sV6mPOEnEPR0vWw ==
  • Node.js签名(71字节):MEUCIQDkAtiomagyHFi7dNfxMrzx / U0Gk / ZhmwCqaL3TimvlswIgPgeDqgZNqfR5 / FZZASYsczUAhGSXjuycLhWnvk20qKc =

已验证的Node.js签名是DER编码的,而WebCrypto签名不是。


问题答案:

我不能肯定地说没有使用这两个库中的任何一个,但是一种可能性是它们没有为签名使用相同的编码类型。对于DSA / ECDSA,有两种主要格式,IEEEP1363(Windows使用)和DER(OpenSSL使用)。

“ Windows”格式应具有预设的大小(由DS的Q值和ECDSA的P值决定(Windows不支持Char-2,但如果是的话,Char-2ECDSA则可能为M))。然后将rs都用左填充,0直到它们达到该长度。

在太小是合法例如r = 0x305s = 0x810522用的sizeof(Q)是3个字节:

// r
000305
// s
810522

对于“ OpenSSL”格式,它按照DER规则编码为SEQUENCE(INTEGER(r),INTEGER(s)),看起来像

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

或者,紧凑地:

  • Windows: 000305810522
  • OpenSSL: 300A02020305020400810522

“ Windows”格式始终为偶数,且长度始终相同。“ OpenSSL”格式通常大约大6个字节,但是中间可能会增加或丢失一个字节;所以有时候甚至是奇怪

Base64解码您的sig64值表明它正在使用DER编码。使用WebCrypto生成几个签名;如果没有开始,0x30那么您就有IEEE /DER问题。



 类似资料:
  • 我有代码使用为ECDSA签名生成串联(r-s)签名和JWK格式的密钥: 似乎有效。我也有使用来实现相同目标的代码: 这两者都返回128字节的缓冲区;并且它们可以交叉验证(例如,我可以用< code>SubtleCrypto验证< code > JSR sign 签名,反之亦然)。然而,当我在Node.js 模块中使用< code>Sign类时,我似乎得到了完全不同的东西。 在这里,我得到了一个可变

  • 我已经在Java中生成了一个ECDSA签名,我希望从中获得R和S值,以便获得COSE编码的签名。根据我的理解,我生成的签名是DER编码的(默认情况下使用bouncyCastle)。当我使用P-256曲线(SHA256withECDSA)时,我正确地检索了R和S值。 当我使用其他曲线(P-521、P-384)时,从一种编码到另一种编码的签名解析有一些问题。

  • 我正试图将Cucumber JVM 2与诱惑2结合使用,但我遇到了一个麻烦。当我尝试运行Maven项目时,会出现以下错误: 我正在尝试使用cucumber选项指定诱惑插件,如下所示: jvm声明的定义如下所示: 所以问题是诱惑的2cucumberJVM适配器是否与cucumberJVM 2兼容?或者我应该用别的东西? PS:在我的pom中,我使用以下依赖项: 任何帮助都非常感谢。谢谢。

  • 问题内容: ECDSA算法中256位EC密钥的签名长度将是多少?我想验证签名长度是否相同。如果某个机构可以帮助我设置一个EC钥匙,那将是很棒的。 问题答案: 这取决于您如何对签名进行编码。这是OpenSSL的代码段,用于测量DER格式的ECDSA签名的长度。 以prime256曲线上的EC_KEY作为参数的上述函数的结果是 sig_len在哪里。 您需要使用位EC密钥的字节来进行DER编码的ECD

  • 我们有一个运行在java 7上的服务器端进程:java-version:java version“1.7.0”java(TM)SE运行时环境(build 1.7.0-b147)java HotSpot(TM)64位服务器VM(build 21.0-b17,混合模式) 它接受来自我们自己开发的java应用程序(通过正确签名的JNLP启动)的SSL连接。 通常情况下,不管客户机应用程序是运行在Java

  • 我想创建一个签名并使用openssl验证它。我想有我的签名的十六进制输出。 这是我的密码 我得到这个错误: 如果我在创建签名的过程中删除了-hex,它就可以工作了。