188 lines
9.2 KiB
JavaScript
188 lines
9.2 KiB
JavaScript
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.randomize_secword({lang:'chinese'})
|
||
console.log('secword = ', w)
|
||
|
||
let acc = tic.secword_to_account({ secword: w, coin: 'ETH' })
|
||
console.log('account = ', acc)
|
||
|
||
let add = tic.secword_to_address({ secword: w, coin: 'ETH' })
|
||
console.log('address = ', add)
|
||
|
||
/////////////////////// keyutil
|
||
|
||
let seckeyObject = new keyutil.Key('oct', Buffer.from(acc.prikey, 'hex'), { namedCurve: 'P-256K' }) // {P-256 : secp256r1, P-384 : secp384r1, P-521 : secp521r1, P-256K : secp256k1}
|
||
let seckeyObject2 = new keyutil.Key('oct', tic.hex_to_buf(acc.prikey, '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.prikey, 'hex'), Buffer.alloc(16))
|
||
|
||
////////////////////// crypto + PEM
|
||
|
||
toPEM = function (kp) {
|
||
let pubkey = crypto.createECDH('secp256k1').setPrivateKey(kp.prikey, 'hex').getPublicKey('hex', 'compressed')
|
||
console.log('ECDH created publickey = ', pubkey)
|
||
let mykey = '308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420' + kp.prikey + '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.prikey, '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.prikey) // 注意,不需要 '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格式的字符串)。
|
||
*/
|