NodeJS:无法登录 nodeJS 10.14.2

NodeJS: Can't sign in nodeJS 10.14.2

我阅读了以下内容https://nodejs.org/api/crypto.html#crypto_class_sign并尝试复制代码:

sign.js

const crypto = require('crypto');

const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
  namedCurve: 'sect239k1'
});

const sign = crypto.createSign('SHA256');
sign.write('some data to sign');
sign.end();
const signature = sign.sign(privateKey, 'hex');

const verify = crypto.createVerify('SHA256');
verify.write('some data to sign');
verify.end();
console.log(verify.verify(publicKey, signature));
// Prints: true or false

但它抛出一个错误

>> node sign.js  
internal/crypto/keygen.js:73
    throw new ERR_INVALID_OPT_VALUE('publicKeyEncoding', publicKeyEncoding);
    ^

TypeError [ERR_INVALID_OPT_VALUE]: The value "undefined" is invalid for option "publicKeyEncoding"
    at parseKeyEncoding (internal/crypto/keygen.js:73:11)
    at check (internal/crypto/keygen.js:240:7)
    at Object.generateKeyPairSync (internal/crypto/keygen.js:53:16)
    at Object.<anonymous> (/Users/norfeldt/Desktop/AsymEnc/sign.js:3:42)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)

更新

我做了以下更改(按照@ottomeister 的建议)

const crypto = require('crypto')

const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
  namedCurve: 'sect239k1',
  publicKeyEncoding: { type: 'spki', format: 'der' },
  privateKeyEncoding: { type: 'pkcs8', format: 'der' },
})

const sign = crypto.createSign('SHA256')
sign.write('some data to sign')
sign.end()
const signature = sign.sign(privateKey, 'hex')

const verify = crypto.createVerify('SHA256')
verify.write('some data to sign')
verify.end()
console.log(verify.verify(publicKey, signature))
// Prints: true or false

但它现在抛出一个新错误

internal/crypto/sig.js:80
  var ret = this._handle.sign(key, passphrase, rsaPadding, pssSaltLength);

Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
    at Sign.sign (internal/crypto/sig.js:80:26)
    at Object.<anonymous> (/Users/norfeldt/Desktop/AsymEnc/sign.js:12:24)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
    at startup (internal/bootstrap/node.js:282:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:743:3)

(我不知道这有什么不同,但我想阅读我用 openssl 创建的 .pem 文件)

您说您使用的是 Node.js 版本 10,但您的 link 指向 Node.js 版本 11 的文档。版本 10 的文档位于 https://nodejs.org/dist/latest-v10.x/docs/api/crypto.html

在版本 11 中,作为第二个参数传递给 crypto.generateKeyPairSyncoptions 对象的 publicKeyEncodingprivateKeyEncoding 属性是可选的。在版本 10 中,这些属性不是可选的,它们 必须 指定。您的程序不提供这些属性,这就是它爆炸的原因。

如果你改变:

const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
  namedCurve: 'sect239k1'
});

至:

const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
  namedCurve: 'sect239k1',
  publicKeyEncoding:  { type: 'spki', format: 'der' },
  privateKeyEncoding: { type: 'pkcs8', format: 'der' }
});

那你的程序应该会更快乐。


更新

好的,我安装了 Node 10 和 运行 你的程序。 sign.sign() 正在爆炸,因为如文档中所述,它要求私钥采用 PEM 格式。它无法处理我的原始答案生成的 DER 格式的私钥。这同样适用于传递给 verify.verify() 的 public 密钥的格式——它必须是 PEM,而不是 DER。所以改变这个:

const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
  namedCurve: 'sect239k1',
  publicKeyEncoding:  { type: 'spki', format: 'der' },
  privateKeyEncoding: { type: 'pkcs8', format: 'der' }
});

对此:

const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
  namedCurve: 'sect239k1',
  publicKeyEncoding:  { type: 'spki', format: 'pem' },
  privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
});

也就是说,将 'der' 的两次出现都更改为 'pem'

这将使您的程序 运行 不会抛出异常。但是,验证尝试将失败,最终 console.log() 调用写入的报告结果将是 false。那是因为程序没有告诉 verify.verify()privateKey 字符串中使用的编码。要解决此问题并从验证中获得 true 结果,请更改:

verify.verify(publicKey, signature)

至:

verify.verify(publicKey, signature, 'hex')

匹配sign.sign()生成签名时指定的字符串编码。这部分的文档不是很清楚,但从实验来看,如果签名是一个字符串,那么您必须始终指定字符串的编码。您可以在此处跳过提供编码的唯一情况是,如果您在 sign.sign() 调用中也跳过它,这将导致 signature 生成为 Buffer 而不是作为字符串.