我阅读了以下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
文件)
答案 0 :(得分:3)
您说您正在使用Node.js版本10,但是链接指向Node.js版本11的文档。版本10的文档位于https://nodejs.org/dist/latest-v10.x/docs/api/crypto.html
在版本11中,作为第二个参数传递给publicKeyEncoding
的{{1}}对象的privateKeyEncoding
和options
属性是可选的。在版本10中,这些属性不是可选的,必须必须指定。您的程序没有提供这些属性,这就是为什么它会崩溃的原因。
如果您更改:
crypto.generateKeyPairSync
收件人:
const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
namedCurve: 'sect239k1'
});
那么您的程序应该更快乐。
好的,我安装了Node 10并运行了程序。 const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
namedCurve: 'sect239k1',
publicKeyEncoding: { type: 'spki', format: 'der' },
privateKeyEncoding: { type: 'pkcs8', format: 'der' }
});
之所以爆炸,是因为如文档中所述,它要求私钥采用PEM格式。它无法处理我原始答案产生的DER格式的私钥。传递给sign.sign()
的公钥格式也是如此-它必须是PEM,而不是DER。所以改变这个:
verify.verify()
对此:
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
而不是生成为字符串。