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 实现的密码学套件。目标是提供一个简单易用的密码学库。

176 lines (175 loc) 6.75 kB
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, }; }