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 实现的密码学套件。目标是提供一个简单易用的密码学库。
188 lines (187 loc) • 7.17 kB
JavaScript
import { sm2p256v1 } from '../../core/ec_params';
import { x963kdf } from '../../core/kdf';
import { genBitMask, getBIBits, joinBuffer, KitError, mod, modInverse, U8 } from '../../core/utils';
import { sm3 } from '../../hash/sm3';
import { ECC } from './ecc';
export function sm2(curve = sm2p256v1) {
let ecc;
switch (curve.type) {
case 'Weierstrass':
ecc = ECC(curve);
break;
case 'Montgomery':
ecc = ECC(curve);
break;
case 'Pseudo-Random':
ecc = ECC(curve);
break;
case 'Koblitz':
ecc = ECC(curve);
break;
default:
throw new KitError('unsupported curve type');
}
let toCatalyst;
switch (ecc.utils.catalyst) {
case 'jacobian':
toCatalyst = ecc.utils.cs.toJacobian;
break;
case 'ld':
toCatalyst = ecc.utils.cs.toLD;
break;
default:
throw new KitError('unsupported catalyst type');
}
const { G, a, b, n, h } = curve;
/** 优化基点 */
const CG = toCatalyst(G);
const p = 'p' in curve ? curve.p : undefined;
const p_bit = p ? getBIBits(p) : undefined;
const p_byte = p ? (p_bit + 7) >> 3 : undefined;
const m = 'm' in curve ? curve.m : undefined;
const m_bit = m ? getBIBits(m) : undefined;
const m_byte = m ? (m_bit + 7) >> 3 : undefined;
const ele_byte = p_byte ?? m_byte;
const { addPoint, mulPoint, isLegalPK } = ecc.utils;
const toAffine = ecc.utils.cs.toAffine;
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 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.Q) === false || isLegalPK(KY.Q) === false)
throw new KitError('非法的公钥');
const KA_d = KA.d;
const KX_d = KX.d;
const KX_Q_x = KX.Q.x;
const KY_Q_x = KY.Q.x;
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 KBQ = toCatalyst(KB.Q);
const KYQ = toCatalyst(KY.Q);
const V_j = mulPoint(addPoint(KBQ, mulPoint(KYQ, x2)), h * t);
if (V_j.isInfinity)
throw new KitError('协商失败');
const V = toAffine(V_j);
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 = key.d;
let r = 0n;
let s = 0n;
const e = hash(joinBuffer(Z, M)).toBI();
do {
const k = gen('private_key').d;
const p = toAffine(mulPoint(CG, 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;
// biome-ignore lint/correctness/noConstantCondition: <try not to throw an error when the probability event does not happen, just repeat the process>
} while (1);
return { r, s };
};
const verify = (Z, key, M, S) => {
const PA = toCatalyst(key.Q);
const { r, s } = S;
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 = toAffine(addPoint(mulPoint(CG, 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 Q = toCatalyst(p_key.Q);
const S = mulPoint(Q, h);
if (S.isInfinity)
throw new KitError('加密失败');
const { x, y } = toAffine(mulPoint(Q, C1.d));
const x2 = U8.fromBI(x);
const y2 = U8.fromBI(y);
const ikm = joinBuffer(x2, y2);
const C2 = kdf(M.length, ikm);
C2.forEach((_, i) => {
C2[i] ^= M[i];
});
const C3 = hash(joinBuffer(x2, M, y2));
return order === 'c1c2c3' ? joinBuffer(PointToU8(C1.Q), C2, C3) : joinBuffer(PointToU8(C1.Q), C3, C2);
};
const decrypt = (s_key, C) => {
const C1_Length = (ele_byte << 1) + 1;
const C3_Length = hash.DIGEST_SIZE;
const C2_Length = C.length - C1_Length - C3_Length;
const C1 = toCatalyst(U8ToPoint(C.subarray(0, C1_Length)));
const S = mulPoint(C1, h);
if (S.isInfinity)
throw new KitError('解密失败');
const { x, y } = toAffine(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, 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));
const isEqual = u.length === C3.length && u.every((val, i) => val === C3[i]);
if (!isEqual)
throw new KitError('解密失败');
return M;
};
return { encrypt, decrypt };
};
return {
utils: ecc.utils,
gen,
di,
es,
dh,
dsa,
};
}