mima-kit
Version:
mima-kit is a cryptographic suite implemented in TypeScript. The goal is to provide an easy-to-use cryptographic library. mima-kit 是一个使用 TypeScript 实现的密码学套件。目标是提供一个简单易用的密码学库。
176 lines (175 loc) • 6.75 kB
JavaScript
import { sm2p256v1 } from '../../core/ecParams';
import { x963kdf } from '../../core/kdf';
import { sm3 } from '../../hash/sm3';
import { KitError, U8, genBitMask, getBIBits, joinBuffer, mod, modInverse } from '../../core/utils';
import { FpECC } from './ecc';
/**
* SM2 椭圆曲线公钥密码算法
*
* Public Key Cryptography Algorithm SM2 Based on Elliptic Curves
*
* @param {FpECParams} curve - 椭圆曲线参数 / Elliptic Curve Parameters (default: sm2p256v1)
*/
export function sm2(curve = sm2p256v1) {
const { p, a, b, G, n, h } = curve;
const p_bit = getBIBits(p);
const p_byte = (p_bit + 7) >> 3;
const ecc = FpECC(curve);
const { addPoint, mulPoint } = ecc.utils;
const a_buffer = U8.fromBI(a);
const b_buffer = U8.fromBI(b);
const Gx_buffer = U8.fromBI(G.x);
const Gy_buffer = U8.fromBI(G.y);
const gen = ecc.gen;
const isLegalPK = ecc.utils.isLegalPK;
const PointToU8 = ecc.utils.PointToU8;
const U8ToPoint = ecc.utils.U8ToPoint;
const di = (id, key, hash = sm3) => {
const ent = id.length << 3;
if (ent > 0xFFFF) {
throw new KitError('ID长度超过了最大限制');
}
const ENT = new Uint8Array([ent >> 8, ent & 0xFF]);
const a = a_buffer;
const b = b_buffer;
const Gx = Gx_buffer;
const Gy = Gy_buffer;
const Ax = typeof key.Q.x === 'bigint' ? U8.fromBI(key.Q.x) : U8.from(key.Q.x);
const Ay = typeof key.Q.y === 'bigint' ? U8.fromBI(key.Q.y) : U8.from(key.Q.y);
const ZA = hash(joinBuffer(ENT, id, a, b, Gx, Gy, Ax, Ay));
return ZA;
};
const w = Math.ceil(getBIBits(n) / 2) - 1;
const w_mask = genBitMask(w);
const dh = (KA, KX, KB, KY, ZA = new Uint8Array(), ZB = new Uint8Array()) => {
if (isLegalPK(KB) === false || isLegalPK(KY) === false) {
throw new KitError('非法的公钥');
}
const KA_d = typeof KA.d === 'bigint' ? KA.d : U8.from(KA.d).toBI();
const KX_d = typeof KX.d === 'bigint' ? KX.d : U8.from(KX.d).toBI();
const KX_Q_x = typeof KX.Q.x === 'bigint' ? KX.Q.x : U8.from(KX.Q.x).toBI();
const KY_Q_x = typeof KY.Q.x === 'bigint' ? KY.Q.x : U8.from(KY.Q.x).toBI();
const x1 = (1n << BigInt(w)) + (KX_Q_x & w_mask);
const x2 = (1n << BigInt(w)) + (KY_Q_x & w_mask);
const t = mod(KA_d + KX_d * x1, n);
const V = mulPoint(addPoint(KB.Q, mulPoint(KY.Q, x2)), h * t);
if (V.isInfinity) {
throw new KitError('协商失败');
}
const xu = U8.fromBI(V.x);
const yu = U8.fromBI(V.y);
return joinBuffer(xu, yu, ZA, ZB);
};
const dsa = (hash = sm3) => {
if (hash.DIGEST_SIZE !== 32) {
throw new KitError('不支持的哈希算法');
}
const sign = (Z, key, M) => {
const dA = typeof key.d === 'bigint' ? key.d : U8.from(key.d).toBI();
let r = 0n;
let s = 0n;
const e = hash(joinBuffer(Z, M)).toBI();
do {
const k = gen('private_key').d.toBI();
const p = mulPoint(G, k);
r = mod(e + p.x, n);
if (r === 0n || r + k === n) {
continue;
}
const numerator = mod(k - r * dA, n);
const denominator = modInverse(1n + dA, n);
s = mod(numerator * denominator, n);
if (s === 0n) {
continue;
}
break;
} while (1);
const r_buffer = new U8(p_byte);
const s_buffer = new U8(p_byte);
r_buffer.set(U8.fromBI(r));
s_buffer.set(U8.fromBI(s));
return { r: r_buffer, s: s_buffer };
};
const verify = (Z, key, M, S) => {
const PA = key.Q;
const r = typeof S.r === 'bigint' ? S.r : U8.from(S.r).toBI();
const s = typeof S.s === 'bigint' ? S.s : U8.from(S.s).toBI();
if (r <= 0n || r >= n || s <= 0n || s >= n) {
return false;
}
const e = hash(joinBuffer(Z, M)).toBI();
const t = mod(r + s, n);
if (t === 0n) {
return false;
}
const p = addPoint(mulPoint(G, s), mulPoint(PA, t));
const R = mod(e + p.x, n);
return R === r;
};
return { sign, verify };
};
const es = (hash = sm3, kdf = x963kdf(sm3), order = 'c1c3c2') => {
const encrypt = (p_key, M) => {
const C1 = gen();
const S = mulPoint(p_key.Q, h);
if (S.isInfinity) {
throw new KitError('加密失败');
}
const { x, y } = mulPoint(p_key.Q, C1.d);
const x2 = U8.fromBI(x);
const y2 = U8.fromBI(y);
const ikm = joinBuffer(x2, y2);
const C2 = kdf(M.length << 3, ikm);
C2.forEach((_, i) => C2[i] ^= M[i]);
const C3 = hash(joinBuffer(x2, M, y2));
if (order === 'c1c2c3') {
return joinBuffer(PointToU8(C1.Q), C2, C3);
}
else {
return joinBuffer(PointToU8(C1.Q), C3, C2);
}
};
const decrypt = (s_key, C) => {
const C1_Length = (p_byte << 1) + 1;
const C3_Length = hash.DIGEST_SIZE;
const C2_Length = C.length - C1_Length - C3_Length;
const C1 = U8ToPoint(C.subarray(0, C1_Length));
const S = mulPoint(C1, h);
if (S.isInfinity) {
throw new KitError('解密失败');
}
const { x, y } = mulPoint(C1, s_key.d);
const x2 = U8.fromBI(x);
const y2 = U8.fromBI(y);
const ikm = joinBuffer(x2, y2);
const t = kdf(C2_Length << 3, ikm);
let C2;
let C3;
if (order === 'c1c2c3') {
C2 = C.subarray(C1_Length, C1_Length + C2_Length);
C3 = C.subarray(C1_Length + C2_Length);
}
else {
C3 = C.subarray(C1_Length, C1_Length + C3_Length);
C2 = C.subarray(C1_Length + C3_Length);
}
const M = t.map((_, i) => t[i] ^ C2[i]);
const u = hash(joinBuffer(x2, M, y2));
u.forEach((_, i) => {
if (u[i] !== C3[i]) {
throw new KitError('解密失败');
}
});
return M;
};
return { encrypt, decrypt };
};
return {
utils: ecc.utils,
gen,
di,
es,
dh,
dsa,
};
}