tic-crypto/test.js

188 lines
9.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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格式的字符串)。
*/