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

177 lines (176 loc) 7.71 kB
import { UTF8 } from '../core/codec'; import { createHash } from '../core/hash'; import { KitError, U8, genBitMask, rotateR } from '../core/utils'; // * Constants const K = new BigUint64Array([0x428a2f98d728ae22n, 0x7137449123ef65cdn, 0xb5c0fbcfec4d3b2fn, 0xe9b5dba58189dbbcn, 0x3956c25bf348b538n, 0x59f111f1b605d019n, 0x923f82a4af194f9bn, 0xab1c5ed5da6d8118n, 0xd807aa98a3030242n, 0x12835b0145706fben, 0x243185be4ee4b28cn, 0x550c7dc3d5ffb4e2n, 0x72be5d74f27b896fn, 0x80deb1fe3b1696b1n, 0x9bdc06a725c71235n, 0xc19bf174cf692694n, 0xe49b69c19ef14ad2n, 0xefbe4786384f25e3n, 0x0fc19dc68b8cd5b5n, 0x240ca1cc77ac9c65n, 0x2de92c6f592b0275n, 0x4a7484aa6ea6e483n, 0x5cb0a9dcbd41fbd4n, 0x76f988da831153b5n, 0x983e5152ee66dfabn, 0xa831c66d2db43210n, 0xb00327c898fb213fn, 0xbf597fc7beef0ee4n, 0xc6e00bf33da88fc2n, 0xd5a79147930aa725n, 0x06ca6351e003826fn, 0x142929670a0e6e70n, 0x27b70a8546d22ffcn, 0x2e1b21385c26c926n, 0x4d2c6dfc5ac42aedn, 0x53380d139d95b3dfn, 0x650a73548baf63den, 0x766a0abb3c77b2a8n, 0x81c2c92e47edaee6n, 0x92722c851482353bn, 0xa2bfe8a14cf10364n, 0xa81a664bbc423001n, 0xc24b8b70d0f89791n, 0xc76c51a30654be30n, 0xd192e819d6ef5218n, 0xd69906245565a910n, 0xf40e35855771202an, 0x106aa07032bbd1b8n, 0x19a4c116b8d2d0c8n, 0x1e376c085141ab53n, 0x2748774cdf8eeb99n, 0x34b0bcb5e19b48a8n, 0x391c0cb3c5c95a63n, 0x4ed8aa4ae3418acbn, 0x5b9cca4f7763e373n, 0x682e6ff3d6b2b8a3n, 0x748f82ee5defb2fcn, 0x78a5636f43172f60n, 0x84c87814a1f0ab72n, 0x8cc702081a6439ecn, 0x90befffa23631e28n, 0xa4506cebde82bde9n, 0xbef9a3f7b2c67915n, 0xc67178f2e372532bn, 0xca273eceea26619cn, 0xd186b8c721c0c207n, 0xeada7dd6cde0eb1en, 0xf57d4f7fee6ed178n, 0x06f067aa72176fban, 0x0a637dc5a2c898a6n, 0x113f9804bef90daen, 0x1b710b35131c471bn, 0x28db77f523047d84n, 0x32caab7b40c72493n, 0x3c9ebe0a15c9bebcn, 0x431d67c49c100d4cn, 0x4cc5d4becb3e42b6n, 0x597f299cfc657e2an, 0x5fcb6fab3ad6faecn, 0x6c44198c4a475817n]); // * Function const mask64 = genBitMask(64); const rotateR64 = (x, n) => rotateR(64, x, n, mask64); const Ch = (x, y, z) => (x & y) ^ ((~x) & z); const Maj = (x, y, z) => (x & y) ^ (x & z) ^ (y & z); const Sigma0 = (x) => rotateR64(x, 28n) ^ rotateR64(x, 34n) ^ rotateR64(x, 39n); const Sigma1 = (x) => rotateR64(x, 14n) ^ rotateR64(x, 18n) ^ rotateR64(x, 41n); const sigma0 = (x) => rotateR64(x, 1n) ^ rotateR64(x, 8n) ^ (x >> 7n); const sigma1 = (x) => rotateR64(x, 19n) ^ rotateR64(x, 61n) ^ (x >> 6n); /** * SHA-512/t IV 生成函数 / generator * * ```ts * (0 < t < 512) && (t !== 384) * ``` * * @param {number} t - 截断长度 / truncation length (bit) */ function IVGen(t) { if (t <= 0) { throw new KitError('SHA-512 truncation must be greater than 0'); } if (t >= 512) { throw new KitError('SHA-512 truncation must be less than 512'); } if (t === 384) { throw new KitError('SHA-512 truncation must not be 384'); } const state = new U8(64); const state_view = state.view(8); state_view.set(0, 0x6a09e667f3bcc908n ^ 0xa5a5a5a5a5a5a5a5n); state_view.set(1, 0xbb67ae8584caa73bn ^ 0xa5a5a5a5a5a5a5a5n); state_view.set(2, 0x3c6ef372fe94f82bn ^ 0xa5a5a5a5a5a5a5a5n); state_view.set(3, 0xa54ff53a5f1d36f1n ^ 0xa5a5a5a5a5a5a5a5n); state_view.set(4, 0x510e527fade682d1n ^ 0xa5a5a5a5a5a5a5a5n); state_view.set(5, 0x9b05688c2b3e6c1fn ^ 0xa5a5a5a5a5a5a5a5n); state_view.set(6, 0x1f83d9abfb41bd6bn ^ 0xa5a5a5a5a5a5a5a5n); state_view.set(7, 0x5be0cd19137e2179n ^ 0xa5a5a5a5a5a5a5a5n); return digest(state, UTF8(`SHA-512/${t}`)); } // * Algorithm function digest(state, message) { // * 初始化 state = state.slice(0); const state_view = state.view(8); const m_byte = message.byteLength; const m_bit = BigInt(m_byte) << 3n; const block_size = 128; // ceil((m_byte + 17) / 128) const block_total = (m_byte + 17 + 127) >> 7; // * 填充 const p = new U8(block_total * block_size); p.set(message); // appending the bit '1' to the message p[m_byte] = 0x80; // appending length const p_view = new DataView(p.buffer); p_view.setBigUint64(p.byteLength - 16, m_bit >> 32n); p_view.setBigUint64(p.byteLength - 8, m_bit & 0xffffffffffffffffn); // * 分块处理 for (let offset = 0; offset < p.length; offset += block_size) { /** B(n) = p[offset:offset + block_size] */ // 准备状态字 const H0 = state_view.get(0); const H1 = state_view.get(1); const H2 = state_view.get(2); const H3 = state_view.get(3); const H4 = state_view.get(4); const H5 = state_view.get(5); const H6 = state_view.get(6); const H7 = state_view.get(7); let a = H0; let b = H1; let c = H2; let d = H3; let e = H4; let f = H5; let g = H6; let h = H7; // 合并执行 扩展 & 压缩 const W = new BigUint64Array(80); for (let i = 0; i < W.length; i++) { // 扩展 if (i < 16) // W[i] = B(n)[i] W[i] = p_view.getBigUint64(offset + (i << 3)); else W[i] = sigma1(W[i - 2]) + W[i - 7] + sigma0(W[i - 15]) + W[i - 16]; // 压缩 const T1 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; const T2 = Sigma0(a) + Maj(a, b, c); h = g; g = f; f = e; e = (d + T1) & 0xffffffffffffffffn; d = c; c = b; b = a; a = (T1 + T2) & 0xffffffffffffffffn; } // 更新状态字 state_view.set(0, H0 + a); state_view.set(1, H1 + b); state_view.set(2, H2 + c); state_view.set(3, H3 + d); state_view.set(4, H4 + e); state_view.set(5, H5 + f); state_view.set(6, H6 + g); state_view.set(7, H7 + h); } // * 返回状态 return state; } function sha384Digest(M) { // * 初始化 SHA-384 状态 const state = new U8(64); const state_view = state.view(8); state_view.set(0, 0xcbbb9d5dc1059ed8n); state_view.set(1, 0x629a292a367cd507n); state_view.set(2, 0x9159015a3070dd17n); state_view.set(3, 0x152fecd8f70e5939n); state_view.set(4, 0x67332667ffc00b31n); state_view.set(5, 0x8eb44a8768581511n); state_view.set(6, 0xdb0c2e0d64f98fa7n); state_view.set(7, 0x47b5481dbefa4fa4n); return digest(state, M).slice(0, 48); } function sha512Digest(M) { // * 初始化 SHA-512 状态 const state = new U8(64); const state_view = state.view(8); state_view.set(0, 0x6a09e667f3bcc908n); state_view.set(1, 0xbb67ae8584caa73bn); state_view.set(2, 0x3c6ef372fe94f82bn); state_view.set(3, 0xa54ff53a5f1d36f1n); state_view.set(4, 0x510e527fade682d1n); state_view.set(5, 0x9b05688c2b3e6c1fn); state_view.set(6, 0x1f83d9abfb41bd6bn); state_view.set(7, 0x5be0cd19137e2179n); return digest(state, M); } export const sha384 = createHash(sha384Digest, { ALGORITHM: 'SHA-384', BLOCK_SIZE: 128, DIGEST_SIZE: 48, OID: '2.16.840.1.101.3.4.2.2', }); export const sha512 = createHash(sha512Digest, { ALGORITHM: 'SHA-512', BLOCK_SIZE: 128, DIGEST_SIZE: 64, OID: '2.16.840.1.101.3.4.2.3', }); /** * @param {number} t - 截断长度 / truncation length (bit) */ export function sha512t(t) { // * 初始化 SHA-512/t 状态 const status = IVGen(t); let OID; if (t === 224) OID = '2.16.840.1.101.3.4.2.5'; if (t === 256) OID = '2.16.840.1.101.3.4.2.6'; return createHash((M) => digest(status, M).slice(0, t >> 3), { ALGORITHM: `SHA-512/${t}`, BLOCK_SIZE: 128, DIGEST_SIZE: t >> 3, OID, }); }