@ivujs/i-utils
Version:
前端模块化 JavaScript 工具库
270 lines (219 loc) • 7.87 kB
JavaScript
'use strict';
var jsbn = require('../lib/jsbn.cjs');
var asn1 = require('../lib/asn1.cjs');
var utils = require('../lib/utils.cjs');
var sm3 = require('../lib/sm3.cjs');
const { BigInteger } = jsbn;
const { decodeDer, encodeDer } = asn1;
const { G, curve, n } = utils.generateEcparam();
const C1C2C3 = 0;
/**
* 加密
*/
function doEncrypt(msg, publicKey, cipherMode = 1) {
msg = typeof msg === "string" ? utils.hexToArray(utils.utf8ToHex(msg)) : Array.prototype.slice.call(msg);
publicKey = utils.getGlobalCurve().decodePointHex(publicKey); // 先将公钥转成点
const keypair = utils.generateKeyPairHex();
const k = new BigInteger(keypair.privateKey, 16); // 随机数 k
// c1 = k * G
let c1 = keypair.publicKey;
if (c1.length > 128) c1 = c1.substr(c1.length - 128);
// (x2, y2) = k * publicKey
const p = publicKey.multiply(k);
const x2 = utils.hexToArray(utils.leftPad(p.getX().toBigInteger().toRadix(16), 64));
const y2 = utils.hexToArray(utils.leftPad(p.getY().toBigInteger().toRadix(16), 64));
// c3 = hash(x2 || msg || y2)
const c3 = utils.arrayToHex(sm3.sm3([].concat(x2, msg, y2)));
let ct = 1;
let offset = 0;
let t = []; // 256 位
const z = [].concat(x2, y2);
const nextT = () => {
// (1) Hai = hash(z || ct)
// (2) ct++
t = sm3.sm3([...z, (ct >> 24) & 0x00ff, (ct >> 16) & 0x00ff, (ct >> 8) & 0x00ff, ct & 0x00ff]);
ct++;
offset = 0;
};
nextT(); // 先生成 Ha1
for (let i = 0, len = msg.length; i < len; i++) {
// t = Ha1 || Ha2 || Ha3 || Ha4
if (offset === t.length) nextT();
// c2 = msg ^ t
msg[i] ^= t[offset++] & 0xff;
}
const c2 = utils.arrayToHex(msg);
return cipherMode === C1C2C3 ? c1 + c2 + c3 : c1 + c3 + c2;
}
/**
* 解密
*/
function doDecrypt(encryptData, privateKey, cipherMode = 1, { output = "string" } = {}) {
privateKey = new BigInteger(privateKey, 16);
let c3 = encryptData.substr(128, 64);
let c2 = encryptData.substr(128 + 64);
if (cipherMode === C1C2C3) {
c3 = encryptData.substr(encryptData.length - 64);
c2 = encryptData.substr(128, encryptData.length - 128 - 64);
}
const msg = utils.hexToArray(c2);
const c1 = utils.getGlobalCurve().decodePointHex("04" + encryptData.substr(0, 128));
const p = c1.multiply(privateKey);
const x2 = utils.hexToArray(utils.leftPad(p.getX().toBigInteger().toRadix(16), 64));
const y2 = utils.hexToArray(utils.leftPad(p.getY().toBigInteger().toRadix(16), 64));
let ct = 1;
let offset = 0;
let t = []; // 256 位
const z = [].concat(x2, y2);
const nextT = () => {
// (1) Hai = hash(z || ct)
// (2) ct++
t = sm3.sm3([...z, (ct >> 24) & 0x00ff, (ct >> 16) & 0x00ff, (ct >> 8) & 0x00ff, ct & 0x00ff]);
ct++;
offset = 0;
};
nextT(); // 先生成 Ha1
for (let i = 0, len = msg.length; i < len; i++) {
// t = Ha1 || Ha2 || Ha3 || Ha4
if (offset === t.length) nextT();
// c2 = msg ^ t
msg[i] ^= t[offset++] & 0xff;
}
// c3 = hash(x2 || msg || y2)
const checkC3 = utils.arrayToHex(sm3.sm3([].concat(x2, msg, y2)));
if (checkC3 === c3.toLowerCase()) {
return output === "array" ? msg : utils.arrayToUtf8(msg);
} else {
return output === "array" ? [] : "";
}
}
/**
* 签名
*/
function doSignature(msg, privateKey, { pointPool, der, hash, publicKey, userId } = {}) {
let hashHex = typeof msg === "string" ? utils.utf8ToHex(msg) : utils.arrayToHex(msg);
if (hash) {
// sm3杂凑
publicKey = publicKey || getPublicKeyFromPrivateKey(privateKey);
hashHex = getHash(hashHex, publicKey, userId);
}
const dA = new BigInteger(privateKey, 16);
const e = new BigInteger(hashHex, 16);
// k
let k = null;
let r = null;
let s = null;
do {
do {
let point;
if (pointPool && pointPool.length) {
point = pointPool.pop();
} else {
point = getPoint();
}
k = point.k;
// r = (e + x1) mod n
r = e.add(point.x1).mod(n);
} while (r.equals(BigInteger.ZERO) || r.add(k).equals(n));
// s = ((1 + dA)^-1 * (k - r * dA)) mod n
s = dA
.add(BigInteger.ONE)
.modInverse(n)
.multiply(k.subtract(r.multiply(dA)))
.mod(n);
} while (s.equals(BigInteger.ZERO));
if (der) return encodeDer(r, s); // asn.1 der 编码
return utils.leftPad(r.toString(16), 64) + utils.leftPad(s.toString(16), 64);
}
/**
* 验签
*/
function doVerifySignature(msg, signHex, publicKey, { der, hash, userId } = {}) {
let hashHex = typeof msg === "string" ? utils.utf8ToHex(msg) : utils.arrayToHex(msg);
if (hash) {
// sm3杂凑
hashHex = getHash(hashHex, publicKey, userId);
}
let r;
let s;
if (der) {
const decodeDerObj = decodeDer(signHex); // asn.1 der 解码
r = decodeDerObj.r;
s = decodeDerObj.s;
} else {
r = new BigInteger(signHex.substring(0, 64), 16);
s = new BigInteger(signHex.substring(64), 16);
}
const PA = curve.decodePointHex(publicKey);
const e = new BigInteger(hashHex, 16);
// t = (r + s) mod n
const t = r.add(s).mod(n);
if (t.equals(BigInteger.ZERO)) return false;
// x1y1 = s * G + t * PA
const x1y1 = G.multiply(s).add(PA.multiply(t));
// R = (e + x1) mod n
const R = e.add(x1y1.getX().toBigInteger()).mod(n);
return r.equals(R);
}
/**
* sm3杂凑算法
*/
function getHash(hashHex, publicKey, userId = "1234567812345678") {
// z = hash(entl || userId || a || b || gx || gy || px || py)
userId = utils.utf8ToHex(userId);
const a = utils.leftPad(G.curve.a.toBigInteger().toRadix(16), 64);
const b = utils.leftPad(G.curve.b.toBigInteger().toRadix(16), 64);
const gx = utils.leftPad(G.getX().toBigInteger().toRadix(16), 64);
const gy = utils.leftPad(G.getY().toBigInteger().toRadix(16), 64);
let px;
let py;
if (publicKey.length === 128) {
px = publicKey.substr(0, 64);
py = publicKey.substr(64, 64);
} else {
const point = G.curve.decodePointHex(publicKey);
px = utils.leftPad(point.getX().toBigInteger().toRadix(16), 64);
py = utils.leftPad(point.getY().toBigInteger().toRadix(16), 64);
}
const data = utils.hexToArray(userId + a + b + gx + gy + px + py);
const entl = userId.length * 4;
data.unshift(entl & 0x00ff);
data.unshift((entl >> 8) & 0x00ff);
const z = sm3.sm3(data);
// e = hash(z || msg)
return utils.arrayToHex(sm3.sm3(z.concat(utils.hexToArray(hashHex))));
}
/**
* 计算公钥
*/
function getPublicKeyFromPrivateKey(privateKey) {
const PA = G.multiply(new BigInteger(privateKey, 16));
const x = utils.leftPad(PA.getX().toBigInteger().toString(16), 64);
const y = utils.leftPad(PA.getY().toBigInteger().toString(16), 64);
return "04" + x + y;
}
/**
* 获取椭圆曲线点
*/
function getPoint() {
const keypair = utils.generateKeyPairHex();
const PA = curve.decodePointHex(keypair.publicKey);
keypair.k = new BigInteger(keypair.privateKey, 16);
keypair.x1 = PA.getX().toBigInteger();
return keypair;
}
// es6 export
const generateKeyPairHex = utils.generateKeyPairHex;
const compressPublicKeyHex = utils.compressPublicKeyHex;
const comparePublicKeyHex = utils.comparePublicKeyHex;
const verifyPublicKey = utils.verifyPublicKey;
exports.comparePublicKeyHex = comparePublicKeyHex;
exports.compressPublicKeyHex = compressPublicKeyHex;
exports.doDecrypt = doDecrypt;
exports.doEncrypt = doEncrypt;
exports.doSignature = doSignature;
exports.doVerifySignature = doVerifySignature;
exports.generateKeyPairHex = generateKeyPairHex;
exports.getPoint = getPoint;
exports.getPublicKeyFromPrivateKey = getPublicKeyFromPrivateKey;
exports.verifyPublicKey = verifyPublicKey;