md5

数学事实

反复线性和非线性交替计算

代码js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
function md5(string) {
function RotateLeft(lValue, iShiftBits) {
return ((lValue << iShiftBits) | (lValue >>> (32 - iShiftBits))) & 0xFFFFFFFF;
}

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
function unsignAdd(lX, lY) {
return ((lX & 0xFFFFFFFF) + (lY & 0xFFFFFFFF) ) & 0xFFFFFFFF;
}

// (a,b,c,d) = (d, ((a+f(b,c,d) + data + Ki)<<< s)+b, b, c)
function f(a, b, c, d, x, s, ac, Fn) {
return unsignAdd(RotateLeft(unsignAdd(a, unsignAdd(unsignAdd(Fn(b, c, d), x), ac)), s), b);
}

function ConvertToWordArray(string) {
let lWordCount;
let lMessageLength = string.length;
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
let lNumberOfWords_temp1 = lMessageLength + 8;
let lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
let lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
let lWordArray = Array(lNumberOfWords - 1);
let lBytePosition = 0;
let lByteCount = 0;
while (lByteCount < lMessageLength) {
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
lByteCount++;
}
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
return lWordArray;
};
function WordToHex(v) {
let WordToHexValue = "";
for (let i = 0; i < 4; i++) {
WordToHexValue += `0${((v >>> (i * 8)) & 0xFF).toString(16)}`.substr(-2);
}
return WordToHexValue;
};
function Utf8Encode(string) {
let utftext = "";
for (let n = 0; n < string.length; n++) {
let c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
};
let x = ConvertToWordArray(Utf8Encode(string));

let funcs = [
(x,y,z) => ((x & y) | ((~x) & z) ),
(x,y,z) => ((x & z) | (y & (~z))),
(x,y,z) => (x ^ y ^ z),
(x,y,z) => (y ^ (x | (~z)))
];
// K = abs(sin(i+1))*(2^32) int part
// https://softwareengineering.stackexchange.com/questions/89694/md5-implementation-notes
const K = [ 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 ] ;

const S = [[7,12,17,22],[5,9,14,20],[4,11,16,23],[6,10,15,21]];

const offset = [[1,0],[5,1],[3,5],[7,0]];

// 01234567 89abcdef fedcba98 76543210
let abcd = [0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476];

// http://www.faqs.org/rfcs/rfc1321.html
for (let idx = 0; idx < x.length; idx += 16) {
const ABCD = [...abcd];
for(let i = 0;i < 4;i ++){
for(let j = 0;j < 4;j ++){
for(let k = 0;k < 4;k ++){
abcd = [abcd[3],f(...abcd, x[idx + ((offset[i][0]*(j*4+k) + offset[i][1] ) %16)], S[i][k], K[(i*4+j)*4+k], funcs[i]),abcd[1],abcd[2]];
}
}
}
abcd = ABCD.map((item,idx)=> unsignAdd(item,abcd[idx]));
}
return abcd.map(item=>WordToHex(item)).join('').toLowerCase();
}

console.log(md5(""))
console.log(md5("demo"))

两段看起来复杂的函数 其实 是字符串通过utf8/ascii之类转换成 数值

其中一些值和公式的设计大自能有个想法感受了,还不明白的是offset和s的设计为什么是这样的,搜了半天也没搜到

https://en.wikipedia.org/wiki/MD5