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.generateKeyPairSync
的 options
对象的 publicKeyEncoding
和 privateKeyEncoding
属性是可选的。在版本 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
而不是作为字符串.
我阅读了以下内容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.generateKeyPairSync
的 options
对象的 publicKeyEncoding
和 privateKeyEncoding
属性是可选的。在版本 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
而不是作为字符串.