MD5(Message Digest Algorithm 5)是一种常用的哈希算法,它以一段任意长度的消息作为输入,通过一系列的计算,得到一个固定长度的哈希值。MD5算法广泛应用于数据完整性校验和密码加密等领域。
在数据传输过程中,为了确保数据的完整性,常常会使用MD5算法对数据进行校验。发送方在发送数据之前,计算数据的MD5哈希值,然后将数据和哈希值一起发送给接收方。接收方接收到数据后,再次计算数据的MD5哈希值,并与接收到的哈希值进行比较,以确认数据是否在传输过程中发生了丢失或篡改。
MD5算法在密码加密领域也被广泛使用。在用户注册或者登录时,通常会将用户输入的密码进行MD5加密后存储在数据库中。当用户再次登录时,系统会将用户输入的密码进行MD5加密,并与数据库中存储的加密后的密码进行比较,以验证用户的身份。
MD5算法可以用于校验文件的完整性。通过计算文件的MD5哈希值,可以快速判断两个文件是否相同。如果两个文件的MD5哈希值相同,则可以认为文件内容一致;反之,如果MD5哈希值不同,则说明文件内容发生了变化。
function md5(message) {
const padding = [
0x80,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
];
const S = [
0x67452301,
0xEFCDAB89,
0x98BADCFE,
0x10325476,
];
function rotateLeft(x, n) {
return (x << n) | (x >>> (32 - n));
}
function FF(a, b, c, d, x, s, t) {
return (
(a + ((b & c) | (~b & d)) + x + t) << s |
(a + ((b & c) | (~b & d)) + x + t) >>> (32 - s)
);
}
function GG(a, b, c, d, x, s, t) {
return (
(a + ((b & d) | (c & ~d)) + x + t) << s |
(a + ((b & d) | (c & ~d)) + x + t) >>> (32 - s)
);
}
function HH(a, b, c, d, x, s, t) {
return (
(a + (b ^ c ^ d) + x + t) << s |
(a + (b ^ c ^ d) + x + t) >>> (32 - s)
);
}
function II(a, b, c, d, x, s, t) {
return (
(a + (c ^ (b | ~d)) + x + t) << s |
(a + (c ^ (b | ~d)) + x + t) >>> (32 - s)
);
}
function transform(chunk, state) {
let [A, B, C, D] = state;
let [a, b, c, d] = [A, B, C, D];
for (let i = 0; i < 64; i++) {
let F, g;
if (i < 16) {
F = FF(b, c, d, a, chunk[i], [7, 12, 17, 22][i % 4], [
0xd76aa478,
0xe8c7b756,
0x242070db,
0xc1bdceee,
0xf57c0faf,
0x4787c62a,
0xa8304613,
0xfd469501,
0x698098d8,
0x8b44f7af,
0xffff5bb1,
0x895cd7be,
0x6b901122,
0xfd987193,
0xa679438e,
0x49b40821,
][i]);
g = i;
} else if (i < 32) {
F = GG(b, c, d, a, chunk[(5 * i + 1) % 16], [5, 9, 14, 20][i % 4], [
0xf61e2562,
0xc040b340,
0x265e5a51,
0xe9b6c7aa,
0xd62f105d,
0x02441453,
0xd8a1e681,
0xe7d3fbc8,
0x21e1cde6,
0xc33707d6,
0xf4d50d87,
0x455a14ed,
0xa9e3e905,
0xfcefa3f8,
0x676f02d9,
0x8d2a4c8a,
][i % 16]);
g = (5 * i + 1) % 16;
} else if (i < 48) {
F = HH(b, c, d, a, chunk[(3 * i + 5) % 16], [4, 11, 16, 23][i % 4], [
0xfffa3942,
0x8771f681,
0x6d9d6122,
0xfde5380c,
0xa4beea44,
0x4bdecfa9,
0xf6bb4b60,
0xbebfbc70,
0x289b7ec6,
0xeaa127fa,
0xd4ef3085,
0x04881d05,
0xd9d4d039,
0xe6db99e5,
0x1fa27cf8,
0xc4ac5665,
][i % 16]);
g = (3 * i + 5) % 16;
} else {
F = II(b, c, d, a, chunk[(7 * i) % 16], [6, 10, 15, 21][i % 4], [
0xf4292244,
0x432aff97,
0xab9423a7,
0xfc93a039,
0x655b59c3,
0x8f0ccc92,
0xffeff47d,
0x85845dd1,
0x6fa87e4f,
0xfe2ce6e0,
0xa3014314,
0x4e0811a1,
0xf7537e82,
0xbd3af235,
0x2ad7d2bb,
0xeb86d391,
][i % 16]);
g = (7 * i) % 16;
}
let temp = d;
d = c;
c = b;
b = (b + rotateLeft((a + F + S[g] + chunk[g]), [3, 7, 11, 19][i % 4])) & 0xffffffff;
a = temp;
}
return [
(A + a) & 0xffffffff,
(B + b) & 0xffffffff,
(C + c) & 0xffffffff,
(D + d) & 0xffffffff,
];
}
function paddingMessage(message) {
const bits = message.length * 8;
const paddingSize =
message.length % 64 < 56 ? 64 : 128 - (message.length % 64);
const buffer = Buffer.alloc(message.length + paddingSize + 8);
buffer.write(message, 0, 'utf-8');
buffer.writeUIntBE(0x80, message.length);
buffer.writeUInt32LE(bits, buffer.length - 8);
return buffer;
}
function splitMessage(message) {
const chunks = [];
for (let i = 0; i < message.length; i += 64) {
chunks.push(
Uint32Array.from(Object.values(message.slice(i, i + 64)))
);
}
return chunks;
}
function hash(message) {
const paddedMessage = paddingMessage(message);
const chunks = splitMessage(paddedMessage);
let state = S.slice();
for (const chunk of chunks) {
state = transform(chunk, state);
}
return state;
}
function toHex(value) {
return value.toString(16).padStart(8, '0');
}
const hashResult = hash(message);
return hashResult.map(toHex).join('');
}
const plaintext = 'Hello, MD5!';
const hash = md5(plaintext);
console.log(hash);