UNPKG

@ivujs/i-utils

Version:

前端模块化 JavaScript 工具库

259 lines (209 loc) 7.61 kB
import * as jsbn from '../lib/jsbn.mjs'; import * as asn1 from '../lib/asn1.mjs'; import { generateEcparam, hexToArray, utf8ToHex, getGlobalCurve, generateKeyPairHex as generateKeyPairHex$1, leftPad, arrayToHex, arrayToUtf8, compressPublicKeyHex as compressPublicKeyHex$1, comparePublicKeyHex as comparePublicKeyHex$1, verifyPublicKey as verifyPublicKey$1 } from '../lib/utils.mjs'; import { sm3 } from '../lib/sm3.mjs'; const { BigInteger } = jsbn; const { decodeDer, encodeDer } = asn1; const { G, curve, n } = generateEcparam(); const C1C2C3 = 0; /** * 加密 */ function doEncrypt(msg, publicKey, cipherMode = 1) { msg = typeof msg === "string" ? hexToArray(utf8ToHex(msg)) : Array.prototype.slice.call(msg); publicKey = getGlobalCurve().decodePointHex(publicKey); // 先将公钥转成点 const keypair = generateKeyPairHex$1(); 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 = hexToArray(leftPad(p.getX().toBigInteger().toRadix(16), 64)); const y2 = hexToArray(leftPad(p.getY().toBigInteger().toRadix(16), 64)); // c3 = hash(x2 || msg || y2) const c3 = arrayToHex(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([...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 = 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 = hexToArray(c2); const c1 = getGlobalCurve().decodePointHex("04" + encryptData.substr(0, 128)); const p = c1.multiply(privateKey); const x2 = hexToArray(leftPad(p.getX().toBigInteger().toRadix(16), 64)); const y2 = hexToArray(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([...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 = arrayToHex(sm3([].concat(x2, msg, y2))); if (checkC3 === c3.toLowerCase()) { return output === "array" ? msg : arrayToUtf8(msg); } else { return output === "array" ? [] : ""; } } /** * 签名 */ function doSignature(msg, privateKey, { pointPool, der, hash, publicKey, userId } = {}) { let hashHex = typeof msg === "string" ? utf8ToHex(msg) : 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 leftPad(r.toString(16), 64) + leftPad(s.toString(16), 64); } /** * 验签 */ function doVerifySignature(msg, signHex, publicKey, { der, hash, userId } = {}) { let hashHex = typeof msg === "string" ? utf8ToHex(msg) : 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 = utf8ToHex(userId); const a = leftPad(G.curve.a.toBigInteger().toRadix(16), 64); const b = leftPad(G.curve.b.toBigInteger().toRadix(16), 64); const gx = leftPad(G.getX().toBigInteger().toRadix(16), 64); const gy = 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 = leftPad(point.getX().toBigInteger().toRadix(16), 64); py = leftPad(point.getY().toBigInteger().toRadix(16), 64); } const data = 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(data); // e = hash(z || msg) return arrayToHex(sm3(z.concat(hexToArray(hashHex)))); } /** * 计算公钥 */ function getPublicKeyFromPrivateKey(privateKey) { const PA = G.multiply(new BigInteger(privateKey, 16)); const x = leftPad(PA.getX().toBigInteger().toString(16), 64); const y = leftPad(PA.getY().toBigInteger().toString(16), 64); return "04" + x + y; } /** * 获取椭圆曲线点 */ function getPoint() { const keypair = generateKeyPairHex$1(); const PA = curve.decodePointHex(keypair.publicKey); keypair.k = new BigInteger(keypair.privateKey, 16); keypair.x1 = PA.getX().toBigInteger(); return keypair; } // es6 export const generateKeyPairHex = generateKeyPairHex$1; const compressPublicKeyHex = compressPublicKeyHex$1; const comparePublicKeyHex = comparePublicKeyHex$1; const verifyPublicKey = verifyPublicKey$1; export { comparePublicKeyHex, compressPublicKeyHex, doDecrypt, doEncrypt, doSignature, doVerifySignature, generateKeyPairHex, getPoint, getPublicKeyFromPrivateKey, verifyPublicKey };