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

233 lines (232 loc) 8.09 kB
import { aes } from '../../cipher/blockCipher/aes'; import { cbc, createCipher } from '../../core/cipher'; import { EC } from '../../core/ec'; import { x963kdf } from '../../core/kdf'; import { genBitMask, genRandomBI, getBIBits, joinBuffer, KitError, mod, modInverse, U8 } from '../../core/utils'; import { hmac } from '../../hash/hmac'; import { sha256 } from '../../hash/sha256'; // * Functions /** * 定义 ECIES 配置 * * Define ECIES Configuration */ export function defineECIES(config) { config = config ?? {}; const { cipher = cbc(aes(256)), mac = hmac(sha256), kdf = x963kdf(sha256), S1 = new Uint8Array(0), S2 = new Uint8Array(0), iv = new Uint8Array(cipher.BLOCK_SIZE), } = config; return { cipher, mac, kdf, S1, S2, iv }; } export function ECC(curve) { let ec; switch (curve.type) { case 'Weierstrass': case 'Montgomery': ec = EC(curve); break; case 'Pseudo-Random': case 'Koblitz': ec = EC(curve); break; default: throw new KitError('unsupported curve type'); } let toCatalyst; switch (ec.catalyst) { case 'jacobian': toCatalyst = ec.cs.toJacobian; break; case 'ld': toCatalyst = ec.cs.toLD; break; default: throw new KitError('unsupported catalyst type'); } const { G, n, h } = curve; /** 优化基点 */ const CG = toCatalyst(G); const n_bit = getBIBits(n); const n_mask = genBitMask(n_bit); 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, isLegalSK, isLegalPK } = ec; const toAffine = ec.cs.toAffine; function gen(type = 'key_pair', s_key) { if (type === 'key_pair') { // private key const { result: d } = genRandomBI(n, ele_byte); // public key const _ = mulPoint(CG, d); const Q = toAffine(_); return { Q, d }; } else if (type === 'private_key') { const { result: d } = genRandomBI(n, ele_byte); return { d }; } else if (type === 'public_key') { const d = s_key.d; if (d === 0n) throw new KitError('Invalid private key'); const _ = mulPoint(CG, d); const Q = toAffine(_); return { Q, d }; } throw new KitError('Invalid type'); } const dh = (s_key, p_key) => { if (!isLegalPK(p_key.Q)) throw new KitError('Invalid public key'); if (!isLegalSK(s_key.d)) throw new KitError('Invalid private key'); const Q = toCatalyst(p_key.Q); const d = s_key.d; const S = mulPoint(Q, d); if (S.isInfinity) throw new KitError('the result of ECDH is the point at infinity'); return toAffine(S); }; const cdh = (s_key, p_key) => { if (!isLegalPK(p_key.Q)) throw new KitError('Invalid public key'); if (!isLegalSK(s_key.d)) throw new KitError('Invalid private key'); const Q = toCatalyst(p_key.Q); const d = s_key.d; const S = mulPoint(Q, d * h); if (S.isInfinity) throw new KitError('the result of ECDH is the point at infinity'); return toAffine(S); }; const mqv = (u1, u2, v1, v2) => { if (!isLegalPK(v1.Q) || !isLegalPK(v2.Q)) throw new KitError('Invalid public key'); const ceilLog2n = n_bit; const L = 1n << BigInt(Math.ceil(ceilLog2n / 2)); const u1d = u1.d; const u2d = u2.d; const u2Qx = u2.Q.x; const v2Qx = v2.Q.x; const Q2u = mod(u2Qx, L) + L; const Q2v = mod(v2Qx, L) + L; const s = mod(u2d + Q2u * u1d, n); const v2Q = toCatalyst(v2.Q); const v1Q = toCatalyst(v1.Q); const P = mulPoint(addPoint(v2Q, mulPoint(v1Q, Q2v)), s * h); if (P.isInfinity) throw new KitError('Public key not available'); return toAffine(P); }; const dsa = (hash = sha256) => { const sign = (s_key, M) => { const d = s_key.d; let r = 0n; let s = 0n; let z = hash(M).toBI(); while (z > n_mask) { z = z >> 1n; } do { const K = gen(); const k = K.d; const x1 = K.Q.x; r = mod(x1, n); if (r === 0n) continue; s = modInverse(k, n) * mod(z + r * d, n); s = mod(s, n); } while (s === 0n); return { r, s }; }; const verify = (p_key, M, signature) => { const Q = toCatalyst(p_key.Q); const r = signature.r; const s = signature.s; if (r <= 0n || r >= n || s <= 0n || s >= n) return false; let z = hash(M).toBI(); while (z > n_mask) { z = z >> 1n; } const w = modInverse(s, n); const u1 = mod(z * w, n); const u2 = mod(r * w, n); const P_j = addPoint(mulPoint(CG, u1), mulPoint(Q, u2)); const P = toAffine(P_j); const v = mod(P.x, n); return v === r; }; return { sign, verify }; }; const ies = (config) => { const { cipher, mac, kdf, S1, S2, iv } = defineECIES(config); const encrypt = (p_key, M) => { if (!isLegalPK(p_key.Q)) throw new KitError('Invalid public key'); let s_key; let deriveShare; do { s_key = gen(); deriveShare = dh(s_key, p_key); } while (deriveShare.isInfinity); const Z = U8.fromBI(deriveShare.x); const K = kdf(cipher.KEY_SIZE + mac.KEY_SIZE, joinBuffer(Z, S1)); const KE = K.slice(0, cipher.KEY_SIZE); const KM = K.slice(cipher.KEY_SIZE, cipher.KEY_SIZE + mac.KEY_SIZE); const _cipher = cipher(KE, iv); const R = { Q: s_key.Q }; const C = _cipher.encrypt(M); const D = mac(KM, joinBuffer(C, S2)); return { R, C, D }; }; const decrypt = (s_key, CT) => { const { R, C, D } = CT; // 密钥派生 const deriveShare = dh(s_key, R); if (deriveShare.isInfinity) throw new KitError('ECIES Decryption failed'); const Z = U8.fromBI(deriveShare.x); const K = kdf(cipher.KEY_SIZE + mac.KEY_SIZE, joinBuffer(Z, S1)); const KE = K.slice(0, cipher.KEY_SIZE); const KM = K.slice(cipher.KEY_SIZE, cipher.KEY_SIZE + mac.KEY_SIZE); const _cipher = cipher(KE, iv); // 校验 if (mac(KM, joinBuffer(C, S2)).some((v, i) => v !== D[i])) throw new KitError('ECIES Decryption failed'); // 解密 const M = _cipher.decrypt(C); return new U8(M); }; return { encrypt, decrypt }; }; return { parameters: curve, utils: ec, gen, dh, cdh, mqv, dsa, ies, }; } // * Algorithms for Test /** * ! 此加密算法仅用于测试 ECIES * ! This encryption algorithm is only used for testing ECIES */ export const es_xor = createCipher((K) => { const encrypt = (M) => new U8(M.map((v, i) => v ^ K[i])); const decrypt = (C) => new U8(C.map((v, i) => v ^ K[i])); return { encrypt, decrypt }; }, { ALGORITHM: 'ES-XOR', BLOCK_SIZE: 20, KEY_SIZE: 20, MIN_KEY_SIZE: 20, MAX_KEY_SIZE: 20, });