// 验证将嵌入页面的纯 JS MD5 —— 采用已按 RFC 1321 向量验证通过的 Wikipedia 伪代码式实现(无符号运算) var MD5 = (function(){ "use strict"; var K = []; for (var i = 0; i < 64; i++) K[i] = Math.floor(Math.abs(Math.sin(i + 1)) * 4294967296) >>> 0; var 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 rotl(x,c){ return ((x << c) | (x >>> (32 - c))) >>> 0; } function md5bytes(bytes){ var msg = bytes.slice(); msg.push(0x80); while (msg.length % 64 !== 56) msg.push(0); var bitLen = bytes.length * 8; for (var i = 0; i < 8; i++) msg.push(Math.floor(bitLen / Math.pow(2, 8*i)) & 0xFF); var a0 = 0x67452301, b0 = 0xefcdab89, c0 = 0x98badcfe, d0 = 0x10325476; for (var off = 0; off < msg.length; off += 64) { var M = []; for (var j = 0; j < 16; j++) M[j] = (msg[off+4*j] | (msg[off+4*j+1] << 8) | (msg[off+4*j+2] << 16) | (msg[off+4*j+3] << 24)) >>> 0; var A = a0, B = b0, C = c0, D = d0; for (i = 0; i < 64; i++) { var F, g; 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; } F = (F + A + K[i] + M[g]) >>> 0; var oB = B; A = D; D = C; C = B; B = (oB + rotl(F, S[i])) >>> 0; } a0 = (a0 + A) >>> 0; b0 = (b0 + B) >>> 0; c0 = (c0 + C) >>> 0; d0 = (d0 + D) >>> 0; } function hex(n){ var s = ""; for (var q = 0; q < 4; q++) s += ((n >>> (8*q)) & 0xFF).toString(16).padStart(2, "0"); return s; } return hex(a0) + hex(b0) + hex(c0) + hex(d0); } return function(text){ return md5bytes(Array.from(new TextEncoder().encode(text))); }; })(); // RFC 1321 全部标准向量 + Node crypto 交叉验证 + sign 黄金样本 var crypto = require("crypto"); var vectors = [ ["", "d41d8cd98f00b204e9800998ecf8427e"], ["a", "0cc175b9c0f1b6a831c399e269772661"], ["abc", "900150983cd24fb0d6963f7d28e17f72"], ["message digest", "f96b697d7cb7938d525a2f31aaf161d0"], ["abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b"], ["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "d174ab98d277d9f5a5611c2c9f419d9f"], ["12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a"] ]; var fail = 0; vectors.forEach(function(v){ var got = MD5(v[0]); if (got !== v[1]) { console.log("FAIL:", JSON.stringify(v[0]).slice(0,40), "got", got); fail++; } }); ["中文测试身份信息","J4jfHM+yZFENVRar0N+/NxgQzgEAdluPWGVyQ4Csq9A=","430703198610010059"].forEach(function(cn){ if (MD5(cn) !== crypto.createHash("md5").update(cn,"utf8").digest("hex")) { console.log("CN FAIL:", cn); fail++; } }); var sign = MD5("D5flYECKtjoOaXB5UiHkO0DKYvmCk7dFFW7plSwDhPI=" + "1789254840029" + "CKtjoOaXB5UiHkO0DKYvmCk7dFFW7plSwDhPI=" + "1789254840029".slice(6)).toUpperCase(); if (sign !== "4CB87B6061991364D261753E3291F2A1") { console.log("SIGN FAIL:", sign); fail++; } console.log(fail === 0 ? "MD5 + SIGN ALL VERIFIED" : "FAILED: " + fail); process.exit(fail ? 1 : 0);