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 实现的密码学套件。目标是提供一个简单易用的密码学库。
150 lines (149 loc) • 6.09 kB
JavaScript
import { createHash } from '../core/hash';
import { U8, rotateL32 } from '../core/utils';
// * Constants
/**
* 轮常量列表 K 由 64 个 32 位无符号整数组成, 使用 1 到 64 的正弦函数生成.
*
* The round constants K is a list of 64 32-bit unsigned integers,
* generated by the sine function from 1 to 64.
*
* ```ts
* const K: number[] = []
* for (let i = 0; i < 64; i++) {
* K[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) >>> 0
* }
* ```
*/
const K = new Uint32Array([0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE, 0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501, 0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE, 0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821, 0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA, 0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8, 0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED, 0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A, 0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C, 0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70, 0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05, 0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665, 0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039, 0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1, 0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1, 0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391]);
// * Function
function FF(a, b, c, d, m, s, k) {
const n = a + ((b & c) | (~b & d)) + m + k;
return rotateL32(n, s) + b;
}
function GG(a, b, c, d, m, s, k) {
const n = a + ((b & d) | (c & ~d)) + m + k;
return rotateL32(n, s) + b;
}
function HH(a, b, c, d, m, s, k) {
const n = a + (b ^ c ^ d) + m + k;
return rotateL32(n, s) + b;
}
function II(a, b, c, d, m, s, k) {
const n = a + (c ^ (b | ~d)) + m + k;
return rotateL32(n, s) + b;
}
// * Algorithm
function digest(message) {
// * 初始化
const state = new Uint32Array([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476]);
const m_byte = message.length;
const m_bit = BigInt(m_byte) << 3n;
const block_size = 64;
// ceil((M_BYTE + 9) / 64)
const block_total = (m_byte + 9 + 63) >> 6;
// * 填充
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.length - 8, m_bit, true);
// * 分块处理
for (let offset = 0; offset < p.length;) {
// 获取分块
const current_buffer = p.subarray(offset, offset += block_size).buffer;
// 准备状态字
const A = state[0];
const B = state[1];
const C = state[2];
const D = state[3];
let a = A;
let b = B;
let c = C;
let d = D;
// 划分词典
const M = new Uint32Array(current_buffer);
/* Round 1 */
a = FF(a, b, c, d, M[0], 7, K[0]);
d = FF(d, a, b, c, M[1], 12, K[1]);
c = FF(c, d, a, b, M[2], 17, K[2]);
b = FF(b, c, d, a, M[3], 22, K[3]);
a = FF(a, b, c, d, M[4], 7, K[4]);
d = FF(d, a, b, c, M[5], 12, K[5]);
c = FF(c, d, a, b, M[6], 17, K[6]);
b = FF(b, c, d, a, M[7], 22, K[7]);
a = FF(a, b, c, d, M[8], 7, K[8]);
d = FF(d, a, b, c, M[9], 12, K[9]);
c = FF(c, d, a, b, M[10], 17, K[10]);
b = FF(b, c, d, a, M[11], 22, K[11]);
a = FF(a, b, c, d, M[12], 7, K[12]);
d = FF(d, a, b, c, M[13], 12, K[13]);
c = FF(c, d, a, b, M[14], 17, K[14]);
b = FF(b, c, d, a, M[15], 22, K[15]);
/* Round 2 */
a = GG(a, b, c, d, M[1], 5, K[16]);
d = GG(d, a, b, c, M[6], 9, K[17]);
c = GG(c, d, a, b, M[11], 14, K[18]);
b = GG(b, c, d, a, M[0], 20, K[19]);
a = GG(a, b, c, d, M[5], 5, K[20]);
d = GG(d, a, b, c, M[10], 9, K[21]);
c = GG(c, d, a, b, M[15], 14, K[22]);
b = GG(b, c, d, a, M[4], 20, K[23]);
a = GG(a, b, c, d, M[9], 5, K[24]);
d = GG(d, a, b, c, M[14], 9, K[25]);
c = GG(c, d, a, b, M[3], 14, K[26]);
b = GG(b, c, d, a, M[8], 20, K[27]);
a = GG(a, b, c, d, M[13], 5, K[28]);
d = GG(d, a, b, c, M[2], 9, K[29]);
c = GG(c, d, a, b, M[7], 14, K[30]);
b = GG(b, c, d, a, M[12], 20, K[31]);
/* Round 3 */
a = HH(a, b, c, d, M[5], 4, K[32]);
d = HH(d, a, b, c, M[8], 11, K[33]);
c = HH(c, d, a, b, M[11], 16, K[34]);
b = HH(b, c, d, a, M[14], 23, K[35]);
a = HH(a, b, c, d, M[1], 4, K[36]);
d = HH(d, a, b, c, M[4], 11, K[37]);
c = HH(c, d, a, b, M[7], 16, K[38]);
b = HH(b, c, d, a, M[10], 23, K[39]);
a = HH(a, b, c, d, M[13], 4, K[40]);
d = HH(d, a, b, c, M[0], 11, K[41]);
c = HH(c, d, a, b, M[3], 16, K[42]);
b = HH(b, c, d, a, M[6], 23, K[43]);
a = HH(a, b, c, d, M[9], 4, K[44]);
d = HH(d, a, b, c, M[12], 11, K[45]);
c = HH(c, d, a, b, M[15], 16, K[46]);
b = HH(b, c, d, a, M[2], 23, K[47]);
/* Round 4 */
a = II(a, b, c, d, M[0], 6, K[48]);
d = II(d, a, b, c, M[7], 10, K[49]);
c = II(c, d, a, b, M[14], 15, K[50]);
b = II(b, c, d, a, M[5], 21, K[51]);
a = II(a, b, c, d, M[12], 6, K[52]);
d = II(d, a, b, c, M[3], 10, K[53]);
c = II(c, d, a, b, M[10], 15, K[54]);
b = II(b, c, d, a, M[1], 21, K[55]);
a = II(a, b, c, d, M[8], 6, K[56]);
d = II(d, a, b, c, M[15], 10, K[57]);
c = II(c, d, a, b, M[6], 15, K[58]);
b = II(b, c, d, a, M[13], 21, K[59]);
a = II(a, b, c, d, M[4], 6, K[60]);
d = II(d, a, b, c, M[11], 10, K[61]);
c = II(c, d, a, b, M[2], 15, K[62]);
b = II(b, c, d, a, M[9], 21, K[63]);
// 更新状态字
state[0] = A + a;
state[1] = B + b;
state[2] = C + c;
state[3] = D + d;
}
// * 返回状态
return new U8(state.buffer);
}
export const md5 = createHash(digest, {
ALGORITHM: 'MD5',
BLOCK_SIZE: 64,
DIGEST_SIZE: 16,
OID: '1.2.840.113549.2.5',
});