// Artalk 的 email_encrypted 字段 = MD5(email 小写),前端拿它当 Gravatar / Cravatar 的 hash。 // Workers 的 crypto.subtle 不提供 MD5,所以这里自带一份。 const K_HEX = [ 'd76aa478', 'e8c7b756', '242070db', 'c1bdceee', 'f57c0faf', '4787c62a', 'a8304613', 'fd469501', '698098d8', '8b44f7af', 'ffff5bb1', '895cd7be', '6b901122', 'fd987193', 'a679438e', '49b40821', 'f61e2562', 'c040b340', '265e5a51', 'e9b6c7aa', 'd62f105d', '02441453', 'd8a1e681', 'e7d3fbc8', '21e1cde6', 'c33707d6', 'f4d50d87', '455a14ed', 'a9e3e905', 'fcefa3f8', '676f02d9', '8d2a4c8a', 'fffa3942', '8771f681', '6d9d6122', 'fde5380c', 'a4beea44', '4bdecfa9', 'f6bb4b60', 'bebfbc70', '289b7ec6', 'eaa127fa', 'd4ef3085', '04881d05', 'd9d4d039', 'e6db99e5', '1fa27cf8', 'c4ac5665', 'f4292244', '432aff97', 'ab9423a7', 'fc93a039', '655b59c3', '8f0ccc92', 'ffeff47d', '85845dd1', '6fa87e4f', 'fe2ce6e0', 'a3014314', '4e0811a1', 'f7537e82', 'bd3af235', '2ad7d2bb', 'eb86d391', ].map((h) => parseInt(h, 16) >>> 0); const S = [ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, ]; function wordToHexLE(n: number): string { let out = ''; for (let i = 0; i < 4; i++) out += ((n >>> (i * 8)) & 0xff).toString(16).padStart(2, '0'); return out; } export function md5(input: string): string { const bytes = new TextEncoder().encode(input); const len = bytes.length; const padded = new Uint8Array((((len + 8) >> 6) + 1) * 64); padded.set(bytes); padded[len] = 0x80; const dv = new DataView(padded.buffer); const bitLen = len * 8; dv.setUint32(padded.length - 8, bitLen >>> 0, true); dv.setUint32(padded.length - 4, Math.floor(bitLen / 0x100000000), true); let a0 = 0x67452301; let b0 = 0xefcdab89; let c0 = 0x98badcfe; let d0 = 0x10325476; for (let chunk = 0; chunk < padded.length; chunk += 64) { const M = new Uint32Array(16); for (let i = 0; i < 16; i++) M[i] = dv.getUint32(chunk + i * 4, true); let A = a0; let B = b0; let C = c0; let D = d0; for (let i = 0; i < 64; i++) { let F: number; let g: number; if (i < 16) { F = (B & C) | (~B & D); g = i; } else if (i < 32) { F = (D & B) | (~D & C); g = (5 * i + 1) % 16; } else if (i < 48) { F = B ^ C ^ D; g = (3 * i + 5) % 16; } else { F = C ^ (B | ~D); g = (7 * i) % 16; } const sum = (F + A + K_HEX[i] + M[g]) >>> 0; A = D; D = C; C = B; B = (B + (((sum << S[i]) | (sum >>> (32 - S[i]))) >>> 0)) >>> 0; } a0 = (a0 + A) >>> 0; b0 = (b0 + B) >>> 0; c0 = (c0 + C) >>> 0; d0 = (d0 + D) >>> 0; } return wordToHexLE(a0) + wordToHexLE(b0) + wordToHexLE(c0) + wordToHexLE(d0); } export function md5Lower(input: string): string { return md5(input.trim().toLowerCase()); }