@ivujs/i-utils
Version:
前端模块化 JavaScript 工具库
199 lines (160 loc) • 5.2 kB
JavaScript
'use strict';
var jsbn = require('./jsbn.cjs');
var ec = require('./ec.cjs');
const { BigInteger, SecureRandom } = jsbn;
const { ECCurveFp } = ec;
const rng = new SecureRandom();
const { curve, G, n } = generateEcparam();
/**
* 获取公共椭圆曲线
*/
function getGlobalCurve() {
return curve;
}
/**
* 生成ecparam
*/
function generateEcparam() {
// 椭圆曲线
const p = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16);
const a = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16);
const b = new BigInteger("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16);
const curve = new ECCurveFp(p, a, b);
// 基点
const gxHex = "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7";
const gyHex = "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0";
const G = curve.decodePointHex("04" + gxHex + gyHex);
const n = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16);
return { curve, G, n };
}
/**
* 生成密钥对:publicKey = privateKey * G
*/
function generateKeyPairHex(a, b, c) {
const random = a ? new BigInteger(a, b, c) : new BigInteger(n.bitLength(), rng);
const d = random.mod(n.subtract(BigInteger.ONE)).add(BigInteger.ONE); // 随机数
const privateKey = leftPad(d.toString(16), 64);
const P = G.multiply(d); // P = dG,p 为公钥,d 为私钥
const Px = leftPad(P.getX().toBigInteger().toString(16), 64);
const Py = leftPad(P.getY().toBigInteger().toString(16), 64);
const publicKey = "04" + Px + Py;
return { privateKey, publicKey };
}
/**
* 生成压缩公钥
*/
function compressPublicKeyHex(s) {
if (s.length !== 130) throw new Error("Invalid public key to compress");
const len = (s.length - 2) / 2;
const xHex = s.substr(2, len);
const y = new BigInteger(s.substr(len + 2, len), 16);
let prefix = "03";
if (y.mod(new BigInteger("2")).equals(BigInteger.ZERO)) prefix = "02";
return prefix + xHex;
}
/**
* utf8串转16进制串
*/
function utf8ToHex(input) {
input = unescape(encodeURIComponent(input));
const length = input.length;
// 转换到字数组
const words = [];
for (let i = 0; i < length; i++) {
words[i >>> 2] |= (input.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);
}
// 转换到16进制
const hexChars = [];
for (let i = 0; i < length; i++) {
const bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
hexChars.push((bite >>> 4).toString(16));
hexChars.push((bite & 0x0f).toString(16));
}
return hexChars.join("");
}
/**
* 补全16进制字符串
*/
function leftPad(input, num) {
if (input.length >= num) return input;
return new Array(num - input.length + 1).join("0") + input;
}
/**
* 转成16进制串
*/
function arrayToHex(arr) {
return arr
.map((item) => {
item = item.toString(16);
return item.length === 1 ? "0" + item : item;
})
.join("");
}
/**
* 转成utf8串
*/
function arrayToUtf8(arr) {
const words = [];
let j = 0;
for (let i = 0; i < arr.length * 2; i += 2) {
words[i >>> 3] |= parseInt(arr[j], 10) << (24 - (i % 8) * 4);
j++;
}
try {
const latin1Chars = [];
for (let i = 0; i < arr.length; i++) {
const bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
latin1Chars.push(String.fromCharCode(bite));
}
return decodeURIComponent(escape(latin1Chars.join("")));
} catch (e) {
throw new Error("Malformed UTF-8 data");
}
}
/**
* 转成字节数组
*/
function hexToArray(hexStr) {
const words = [];
let hexStrLength = hexStr.length;
if (hexStrLength % 2 !== 0) {
hexStr = leftPad(hexStr, hexStrLength + 1);
}
hexStrLength = hexStr.length;
for (let i = 0; i < hexStrLength; i += 2) {
words.push(parseInt(hexStr.substr(i, 2), 16));
}
return words;
}
/**
* 验证公钥是否为椭圆曲线上的点
*/
function verifyPublicKey(publicKey) {
const point = curve.decodePointHex(publicKey);
if (!point) return false;
const x = point.getX();
const y = point.getY();
// 验证 y^2 是否等于 x^3 + ax + b
return y.square().equals(x.multiply(x.square()).add(x.multiply(curve.a)).add(curve.b));
}
/**
* 验证公钥是否等价,等价返回true
*/
function comparePublicKeyHex(publicKey1, publicKey2) {
const point1 = curve.decodePointHex(publicKey1);
if (!point1) return false;
const point2 = curve.decodePointHex(publicKey2);
if (!point2) return false;
return point1.equals(point2);
}
exports.arrayToHex = arrayToHex;
exports.arrayToUtf8 = arrayToUtf8;
exports.comparePublicKeyHex = comparePublicKeyHex;
exports.compressPublicKeyHex = compressPublicKeyHex;
exports.generateEcparam = generateEcparam;
exports.generateKeyPairHex = generateKeyPairHex;
exports.getGlobalCurve = getGlobalCurve;
exports.hexToArray = hexToArray;
exports.leftPad = leftPad;
exports.utf8ToHex = utf8ToHex;
exports.verifyPublicKey = verifyPublicKey;