UNPKG

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
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, }; }