用eccrypto加解密,用crypto签名。互相转换压缩和非压缩公钥

This commit is contained in:
Luk Lu
2020-02-20 13:36:44 +08:00
parent c494dd51de
commit 09d831af00
6 changed files with 726 additions and 79 deletions

190
test.js Normal file
View File

@@ -0,0 +1,190 @@
const bigInt = require("big-integer");
// Consts for secp256k1 curve. Adjust accordingly
// https://en.bitcoin.it/wiki/Secp256k1
const prime = new bigInt('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16), // 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
pIdent = new bigInt('3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c', 16) // prime.add(1).divide(4);
console.log('pIdent=',pIdent.toString(), ' = ', pIdent.toString(16))
/**
* Point decompress secp256k1 curve
* @param {string} Compressed representation in hex string
* @return {string} Uncompressed representation in hex string
*/
function ECPointDecompress( comp ) {
var signY = new Number(comp[1]) - 2;
var x = new bigInt(comp.substring(2), 16);
// y mod p = +-(x^3 + 7)^((p+1)/4) mod p
console.log('ECP x=', x.toString(), ' = ', x.toString(16))
var y = x.modPow(3, prime).add(7).mod(prime).modPow( pIdent, prime );
// If the parity doesn't match it's the *other* root
console.log('ECP y=', y.toString(), ' = ', y.toString(16))
if( y.mod(2).toJSNumber() !== signY ) {
// y = prime - y
y = prime.subtract( y );
}
console.log('ECP y=', y.toString(), ' = ', y.toString(16))
return '04' + x.toString(16).padStart(64, '0') + y.toString(16).padStart(64, '0');
}
let pubkey1= ECPointDecompress('035d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b2')
console.log(pubkey1) // "045d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b24a323dd24b19c55f0a060ccd4bce314323bd7e804f3dfa8a77f14e3ab1cc4749"
correct = "045d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b2356d086fb7a78f3ce3359a4caee6dd4fcf0c19a961b1c36b5b442d031d219d75"
BigNumber = require('bignumber.js')
function uncompressPubkey(comp){
// Consts for P256 curve. Adjust accordingly
const prime = new BigNumber('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16).integerValue(),
pIdent = prime.plus(1).idiv(4).integerValue()
console.log('pIdent=', pIdent.toString(), ' = ', pIdent.toString(16))
var signY = new Number(comp[1]) - 2;
var x = new BigNumber(comp.substring(2), 16).integerValue();
console.log('x=',x.toString(), ' = ', x.toString(16))
// y^2 = x^3 - 3x + b
var y = x.pow(3).mod(prime).plus(7).mod(prime).pow(pIdent).mod(prime).integerValue();
console.log('y=',y.toString(), ' = ', y.toString(16))
// If the parity doesn't match it's the *other* root
if( y.mod(2).integerValue().toNumber() !== signY ) {
// y = prime - y
y = prime.minus( y ).integerValue();
}
console.log('yy=', y.toString(), ' = ', y.toString(16))
return '04' + x.toString(16).padStart(64, '0') + y.toString(16).padStart(64, '0');
}
let pubkey2=uncompressPubkey('035d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b2')
console.log(pubkey2)
///////////////////////////////////////
const tic = require('./index')
const crypto = require('crypto')
const keyutil = require('js-crypto-key-utils') // https://github.com/junkurihara/jscu/tree/master/packages/js-crypto-key-utils
// https://github.com/arvati/crypto-keys
// nodejs cipher/decipher 用同一个密码在stream上操作。
let w = '驳 惊 而 煤 靠 客 示 待 诉 屈 屏 未' // tic.randomSecword('chinese')
console.log('secword = ', w)
let acc = tic.secword2account(w, {coin:'ETH'})
console.log('account = ', acc)
let add = tic.secword2address(w, {coin:'ETH'})
console.log('address = ', add)
/////////////////////// keyutil
let seckeyObject = new keyutil.Key('oct', Buffer.from(acc.seckey, 'hex'), {namedCurve:'P-256K'}) // {P-256 : secp256r1, P-384 : secp384r1, P-521 : secp521r1, P-256K : secp256k1}
let seckeyObject2 = new keyutil.Key('oct', tic.hex2buf(acc.seckey, 'hex'), {namedCurve:'P-256K'})
let seckeyPEM
seckeyObject.export('pem').then(data=>seckeyPEM=data)
let seckeyDER
seckeyObject2.export('der').then(data=>seckeyDER=data)
var signerKU = crypto.createSign('sha256');
signerKU.write('毛主席万岁');
signerKU.end();
var signatureKU = signerKU.sign(seckeyPEM); // specify format in [pem,der] and type in [pkcs1, pkcs8, sec1]
console.log('signature = ', signatureKU.toString('hex'))
console.log('length = ', signatureKU.toString('hex').length)
var signerKUDER = crypto.createSign('sha256')
signerKUDER.write('毛主席万岁');
signerKUDER.end();
var signatureKUDER = signerKUDER.sign({key:seckeyDER, format:'der', type:'pkcs8'}); // specify format in [pem,der] and type in [pkcs1, pkcs8, sec1]
console.log('signature DER = ', signatureKUDER.toString('hex'))
console.log('length DER = ', signatureKUDER.toString('hex').length)
let pubkeyObject = new keyutil.Key('oct', Buffer.from(acc.pubkey, 'hex'), {namedCurve:'P-256K'})
let pubkeyPEM
pubkeyObject.export('der').then(data=>pubkeyPEM=data)
var verifyKU = crypto.createVerify('sha256');
verifyKU.write('毛主席万岁');
verifyKU.end();
var verified = verifyKU.verify(pubkeyPEM, signatureKU); // specify format in [pem,der] and type in [pkcs1,spki]
console.log('verified = ', verified) // 可以验证通过但是用的privatekey没有成功使用publickey。
crypto.createCipheriv('aes-256-cfb', Buffer.from(acc.seckey,'hex'), Buffer.alloc(16))
////////////////////// crypto + PEM
toPEM=function (kp){
let pubkey = crypto.createECDH('secp256k1').setPrivateKey(kp.seckey, 'hex').getPublicKey('hex','compressed')
console.log('ECDH created publickey = ', pubkey)
let mykey = '308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420' + kp.seckey + 'a144034200' + pubkey
console.log(mykey)
let privKey = '-----BEGIN PRIVATE KEY-----\n' + Buffer.from(mykey, 'hex').toString('base64') + '\n-----END PRIVATE KEY-----'
// pubKey2 = crypto.createPublicKey(privKey); //也可恢复出公钥。测试不成功。
return privKey
}
let privKeyPEM = toPEM(acc)
const signerPEM = crypto.createSign('sha256')
signerPEM.write('毛主席万岁')
signerPEM.end()
let signaturePEM = signerPEM.sign(privKeyPEM, 'hex') // 失败,无论对压缩或非压缩公钥
console.log('signaturePEM = ', signaturePEM)
let pemKP = toPEM(acc)
console.log('pemKP = ', pemKP)
//////////////////// crypto, DER
// https://stackoverflow.com/questions/58350484/why-nodejs-crypto-sign-function-only-accept-privatekey-pem-format
// https://www.shangyang.me/2017/05/24/encrypt-rsa-keyformat/
var buf1 = Buffer.from('308141020100301306072a8648ce3d020106082a8648ce3d030107042730250201010420', 'hex'); // specific byte-sequence for curve prime256v1
var buf2 = Buffer.from(acc.seckey, 'hex'); // raw private key (32 bytes)
var privateKeyPkcs8Der = Buffer.concat([buf1, buf2], buf1.length + buf2.length);
var sign = crypto.createSign('sha256');
sign.write('毛主席万岁');
sign.end();
var signature = sign.sign({ key: privateKeyPkcs8Der, format: 'der', type: 'pkcs8' }); // specify format in [pem,der] and type in [pkcs1, pkcs8, sec1]
console.log('signature = ', signature.toString('hex'))
console.log('length = ', signature.toString('hex').length)
var buf3 = Buffer.from('3059301306072a8648ce3d020106082a8648ce3d030107034200', 'hex'); // specific byte-sequence for curve prime256v1
var buf4 = Buffer.from(acc.pubkey, 'hex'); // raw public key (uncompressed, 65 bytes, startting with 04)
// 这个key无法sign。reason: 'too long'
//var publicKeyX509Der = Buffer.concat([buf3, buf4], buf3.length + buf4.length);
//var publicKey = crypto.createPublicKey({key:publicKeyX509Der, format:'der', type:'spki'})
var publicKey = crypto.createPublicKey({ key: privateKeyPkcs8Der, type: 'pkcs8', format: 'der' });
var publicKeyX509Der = publicKey.export({type: 'spki', format: 'der'})
var verify = crypto.createVerify('sha256');
verify.write('毛主席万岁');
verify.end();
var verified = verify.verify({ key: publicKeyX509Der, format: 'der', type: 'spki' }, signature); // specify format in [pem,der] and type in [pkcs1,spki]
console.log('verified = ', verified) // 可以验证通过但是用的privatekey没有成功使用publickey。
/////////////////////// elliptic
var EC = require('elliptic').ec;
// Create and initialize EC context
// (better do it once and reuse it)
var ec = new EC('secp256k1');
// Generate keys
//var key = ec.genKeyPair();
var key = ec.keyFromPrivate(acc.seckey) // 注意,不需要 'hex' 参数
// Sign the message's hash (input must be an array, or a hex-string)
var msgHash = tic.hash('毛主席万岁')
var msgHashBad = tic.hash('毛主席万岁 ')
var signature2 = key.sign(msgHash);
// Export DER encoded signature in Array
var derSign = signature2.toDER(); // 无法直接导出成 hex。可以
console.log('signature by elliptic = ', Buffer.from(derSign).toString('hex'))
// 或者重新创建使用 pubkey也能成功
// ec.keyFromPublic(acc.pubkey, 'hex').verify(msgHash, signature2)
console.log(key.verify(msgHash, signature2))
console.log(key.verify(msgHashBad, signature2))
//////////////////
/*
createCipher/Decipher: 使用 pwd, 对称加解密。已放弃。
createCipheriv/Deciperiv: 使用 key, 对称加解密。
private/publicEncrypt/Decrypt: 非对称加解密。
crypto.privateEncrypt(crypto.generateKeyPairSync('rsa', {modulusLength:2048}).privateKey, Buffer.from('锦瑟无端五十弦'))
以上是唯一测出来可用的privatekey不能用 'ec', {namedCurve:'secp256k1'}, 也不能用crypto.createPrivateKey(pem格式的字符串)。
*/