tinyhmacmd5 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -23
- package/browser.min.js +1 -1
- package/main.js +38 -42
- package/package.json +19 -4
package/README.md
CHANGED
|
@@ -2,15 +2,18 @@ English | [中文](README-zh.md)
|
|
|
2
2
|
|
|
3
3
|
# Tiny HMAC MD5
|
|
4
4
|
|
|
5
|
-
A tiny
|
|
6
|
-
[`browser.min.js`](browser.min.js) is only **1045 bytes**.
|
|
5
|
+
A tiny and reliable HMAC-MD5 implementation for JavaScript: [`browser.min.js`](browser.min.js) is only **997 bytes**.
|
|
7
6
|
|
|
8
7
|
- **Input type**: `string` (UTF‑8), `Uint8Array` or `Uint8ClampedArray`
|
|
9
|
-
- **Output type**: hex `string` or
|
|
10
|
-
- **Supports inputs ≥ 512 MiB**:
|
|
8
|
+
- **Output type**: hex `string` or bytes `Uint8Array`
|
|
9
|
+
- **Supports inputs ≥ 512 MiB**: The input length theoretically supports 0 to $2^{53}-1$ (`Number.MAX_SAFE_INTEGER`).
|
|
11
10
|
- **TypeScript‑ready**: [`main.d.ts`](main.d.ts)
|
|
12
11
|
- **0 dependencies**
|
|
13
12
|
|
|
13
|
+
`tinyhmacmd5` does not simply aim for the smallest possible size.
|
|
14
|
+
Its goal is to balance code size and runtime performance, so some performance-oriented implementations are intentionally retained.
|
|
15
|
+
As a result, the final size is not the smallest theoretically achievable.
|
|
16
|
+
|
|
14
17
|
**Live demo**: https://bddjr.github.io/tinyhmacmd5/
|
|
15
18
|
|
|
16
19
|
> [!WARNING]
|
|
@@ -42,10 +45,11 @@ See https://www.jsdelivr.com/package/npm/tinyhmacmd5
|
|
|
42
45
|
<script src="https://cdn.jsdelivr.net/npm/tinyhmacmd5"></script>
|
|
43
46
|
```
|
|
44
47
|
|
|
45
|
-
|
|
48
|
+
It will define the `md5` function using `var`.
|
|
46
49
|
|
|
47
|
-
|
|
50
|
+
### Inline
|
|
48
51
|
|
|
52
|
+
You can embed [`browser.min.js`](browser.min.js) directly into your script.
|
|
49
53
|
It will define the `md5` function using `var`.
|
|
50
54
|
|
|
51
55
|
---
|
|
@@ -53,20 +57,18 @@ It will define the `md5` function using `var`.
|
|
|
53
57
|
## Example
|
|
54
58
|
|
|
55
59
|
> [!NOTE]
|
|
56
|
-
>
|
|
57
|
-
>
|
|
58
|
-
> TypeScript will catch mismatches at compile time (unless you use `any`).
|
|
59
|
-
> Invalid types may produce an incorrect MD5 hash.
|
|
60
|
+
> Please ensure that the input type matches the definition in [`main.d.ts`](main.d.ts).
|
|
61
|
+
> Invalid types may return an incorrect MD5 hash.
|
|
60
62
|
|
|
61
63
|
HMAC-MD5:
|
|
62
64
|
|
|
63
65
|
```js
|
|
64
|
-
// string to hex
|
|
66
|
+
// string (UTF-8) to hex
|
|
65
67
|
// returns "c87fdc912df24da05a6e3fed927e9d89"
|
|
66
68
|
md5("Hello world!👋", "HMAC key 🔑")
|
|
67
69
|
|
|
68
|
-
// string to bytes
|
|
69
|
-
// returns Uint8Array
|
|
70
|
+
// string (UTF-8) to bytes
|
|
71
|
+
// returns Uint8Array(16)
|
|
70
72
|
md5("Hello world!👋", "HMAC key 🔑", true)
|
|
71
73
|
|
|
72
74
|
// bytes to hex
|
|
@@ -74,19 +76,19 @@ md5("Hello world!👋", "HMAC key 🔑", true)
|
|
|
74
76
|
md5(Uint8Array.of(1, 2, 3), Uint8Array.of(4, 5, 6))
|
|
75
77
|
|
|
76
78
|
// bytes to bytes
|
|
77
|
-
// returns Uint8Array
|
|
79
|
+
// returns Uint8Array(16)
|
|
78
80
|
md5(Uint8Array.of(1, 2, 3), Uint8Array.of(4, 5, 6), true)
|
|
79
81
|
```
|
|
80
82
|
|
|
81
83
|
MD5: (when `key` is `null` or `undefined`)
|
|
82
84
|
|
|
83
85
|
```js
|
|
84
|
-
// string to hex
|
|
86
|
+
// string (UTF-8) to hex
|
|
85
87
|
// returns "3ac851eecf9e37be7565bf073a73c9dc"
|
|
86
88
|
md5("Hello world!👋")
|
|
87
89
|
|
|
88
|
-
// string to bytes
|
|
89
|
-
// returns Uint8Array
|
|
90
|
+
// string (UTF-8) to bytes
|
|
91
|
+
// returns Uint8Array(16)
|
|
90
92
|
md5("Hello world!👋", null, true)
|
|
91
93
|
|
|
92
94
|
// bytes to hex
|
|
@@ -94,10 +96,40 @@ md5("Hello world!👋", null, true)
|
|
|
94
96
|
md5(Uint8Array.of(1, 2, 3))
|
|
95
97
|
|
|
96
98
|
// bytes to bytes
|
|
97
|
-
// returns Uint8Array
|
|
99
|
+
// returns Uint8Array(16)
|
|
98
100
|
md5(Uint8Array.of(1, 2, 3), null, true)
|
|
99
101
|
```
|
|
100
102
|
|
|
103
|
+
`ArrayBuffer` must be wrapped in a `Uint8Array` before use as input;
|
|
104
|
+
otherwise, it will return an incorrect MD5 hash.
|
|
105
|
+
|
|
106
|
+
```js
|
|
107
|
+
let data = new ArrayBuffer(8)
|
|
108
|
+
|
|
109
|
+
// MD5: bytes to hex
|
|
110
|
+
md5(new Uint8Array(data))
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
You can also input a `Uint8ClampedArray`, which has the same effect as using a `Uint8Array`.
|
|
114
|
+
|
|
115
|
+
```js
|
|
116
|
+
// MD5: bytes to hex
|
|
117
|
+
// returns "5289df737df57326fcdd22597afb1fac"
|
|
118
|
+
md5(Uint8ClampedArray.of(1, 2, 3))
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**[⚠️Unsafe]** You can also input a `number[]`, but every element must be an integer in the range `0 ≤ x ≤ 255`;
|
|
122
|
+
otherwise, it will return an incorrect MD5 hash.
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
let data = [0, 1, 127, 255]
|
|
126
|
+
|
|
127
|
+
// MD5: bytes to hex
|
|
128
|
+
// returns "b23d6235d525eed4c4b8d741d4c2a5a1"
|
|
129
|
+
//@ts-ignore
|
|
130
|
+
md5(data)
|
|
131
|
+
```
|
|
132
|
+
|
|
101
133
|
---
|
|
102
134
|
|
|
103
135
|
## Runtime Environment
|
|
@@ -109,14 +141,12 @@ Environments that support [Nullish coalescing assignment (`??=`)](https://develo
|
|
|
109
141
|
- Firefox ≥ 79 (2020-07-28)
|
|
110
142
|
- Safari ≥ 14 (2020-09-16)
|
|
111
143
|
|
|
144
|
+
Not recommended for use in environments that support `node:crypto`, as `node:crypto` already provides HMAC-MD5.
|
|
145
|
+
|
|
112
146
|
---
|
|
113
147
|
|
|
114
148
|
## Why I Made This Project
|
|
115
149
|
|
|
116
|
-
> [!NOTE]
|
|
117
|
-
> AI-translated from Chinese.
|
|
118
|
-
> [查看原文](README-zh.md#为什么做这个项目)
|
|
119
|
-
|
|
120
150
|
I initially used HMAC-MD5 just to call a certain website's API. That site signs the request body with `crypto-js`'s HMAC-MD5 to make reverse engineering harder.
|
|
121
151
|
|
|
122
152
|
But I only needed HMAC-MD5. Depending on `crypto-js` felt way too bloated. The Web Crypto API doesn't support HMAC-MD5, so I had no choice but to drag in a dependency.
|
|
@@ -131,12 +161,14 @@ During the adaptation, I discovered that `blueimp-md5` did not correctly handle
|
|
|
131
161
|
|
|
132
162
|
I also found that using `Array` to process inputs over 512 MiB could throw a `RangeError`, so I replaced it with `Int32Array`.
|
|
133
163
|
|
|
134
|
-
I demonstrated in practice that HMAC-MD5 can be implemented in an extremely small footprint (
|
|
164
|
+
I demonstrated in practice that HMAC-MD5 can be implemented in an extremely small footprint (997 bytes) while also improving reliability.
|
|
135
165
|
|
|
136
166
|
Maybe not many people care about saving just a few KB, but `tinyhmacmd5` exists precisely to "explore the unknown".
|
|
137
167
|
|
|
138
168
|
INVINCIBLE EXPERIMENT!
|
|
139
169
|
|
|
170
|
+
[查看原文](README-zh.md#为什么做这个项目)
|
|
171
|
+
|
|
140
172
|
---
|
|
141
173
|
|
|
142
174
|
## License
|
package/browser.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** @license https://bddjr.github.io/tinyhmacmd5/lic */
|
|
2
|
-
{let r=
|
|
2
|
+
{let r=[],n=Math,t=n.floor,e=r=>16*t((r+72)/64),o=(o,f,a=0,l=e(f),c=1732584193,i=271733878,d,g,h=[c,~i,~c,i],u=[...h])=>{for(o[l-1]=0|f/2**29,o[t(f/4)]|=128<<(o[l-2]=f<<3);a<o.length;){for(l=0;l<64;)h[g&=3]=0|((i=0|h[g]+(c=h[3&++g],i=h[3&++g],d=h[3&++g],(f=l>>4<<2)?f>4?f>8?i^(c|~d):c^i^d:c&d|i&~d:c&i|~c&d)+(0|o[a+(l*(29521>>f)+(1296>>f)&15)])+(d="',16%).4$+07&*/5".charCodeAt(3&l|f),r[63-l++]??=0|2**32*n.abs(n.sin(l))))<<d|i>>>64-d)+c;for(;g;a+=4)u[--g]=h[g]=0|u[g]+h[g]}return h},f=(r,n,t=("string"==typeof r?r=(new TextEncoder).encode(r):r).length,o=new Int32Array(e(4*n+t)),f=0)=>{for(;f<t;)o[n++]=r[f++]|r[f++]<<8|r[f++]<<16|r[f++]<<24;return[o,t]};var md5=(r,n,t)=>{var e=16,a=null!=n,[l,c]=f(r,a*e),i=[],d=t?new Uint8Array(e):"";if(a){let[r,t]=f(n,0);for(t>64&&(r=o(r,t));e;)i[--e]=1785358954^(l[e]=909522486^r[e]);e=16,l=i.concat(o(l,64+c)),c=80}for(l=o(l,c);e;t?d[e]=i:d=(i>>4&&"")+i.toString(16)+d)i=l[--e>>2]>>8*e&255;return d}}
|
package/main.js
CHANGED
|
@@ -2,22 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
// Adapted from https://github.com/blueimp/JavaScript-MD5
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
, C = ~A
|
|
8
|
-
, B = ~D
|
|
9
|
-
|
|
10
|
-
let $2_32 = 2 ** 32
|
|
5
|
+
/** @type {number[]} MD5 constants cached in memory */
|
|
6
|
+
let K = []
|
|
11
7
|
|
|
12
8
|
let $Math = Math
|
|
13
9
|
|
|
14
10
|
let floor = $Math.floor
|
|
15
11
|
|
|
16
12
|
/** @param {number} byteLen */
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
/** @type {number[]} MD5 constants cached in memory */
|
|
20
|
-
let K = []
|
|
13
|
+
// `byteLen` may be >= 2**32, so cannot use `>>>` as a replacement for `floor`
|
|
14
|
+
let toBinlLen = (byteLen) => floor((byteLen + 72) / 64) * 16
|
|
21
15
|
|
|
22
16
|
/**
|
|
23
17
|
* Calculate the MD5 of an array of little-endian words, and a byte length.
|
|
@@ -25,9 +19,6 @@ let K = []
|
|
|
25
19
|
* @param {Int32Array | number[]} x Array of little-endian words
|
|
26
20
|
* @param {number} l Byte length
|
|
27
21
|
*
|
|
28
|
-
* @param {number} [j]
|
|
29
|
-
* @param {number} [t0]
|
|
30
|
-
* @param {number} [t1]
|
|
31
22
|
* @param {number} [t2]
|
|
32
23
|
* @param {number} [oi]
|
|
33
24
|
*
|
|
@@ -39,24 +30,25 @@ let binlMD5 = (
|
|
|
39
30
|
// var:
|
|
40
31
|
i = 0,
|
|
41
32
|
j = toBinlLen(l),
|
|
42
|
-
t0,
|
|
43
|
-
t1,
|
|
33
|
+
t0 = 1732584193,
|
|
34
|
+
t1 = 271733878,
|
|
44
35
|
t2,
|
|
45
36
|
oi,
|
|
46
|
-
output = [
|
|
37
|
+
output = [t0, ~t1, ~t0, t1],
|
|
47
38
|
oldOutput = [...output],
|
|
48
39
|
) => {
|
|
49
40
|
// console.time("binlMD5")
|
|
50
41
|
|
|
51
42
|
// append padding
|
|
52
|
-
|
|
53
|
-
x[j -
|
|
54
|
-
x[floor(l / 4)] |= 0x80 <<
|
|
55
|
-
|
|
56
|
-
for (; i < x.length;
|
|
57
|
-
for (
|
|
58
|
-
output[oi
|
|
59
|
-
|
|
43
|
+
// `l` may be >= 2**32, so cannot use `>>>` as a replacement for `floor`
|
|
44
|
+
x[j - 1] = 0 | l / 2 ** 29;
|
|
45
|
+
x[floor(l / 4)] |= 0x80 << (x[j - 2] = l << 3);
|
|
46
|
+
|
|
47
|
+
for (; i < x.length;) {
|
|
48
|
+
for (j = 0; j < 64;) {
|
|
49
|
+
output[oi &= 3] = 0 | (
|
|
50
|
+
(t1 = 0 | (
|
|
51
|
+
output[oi] +
|
|
60
52
|
(
|
|
61
53
|
t0 = output[++oi & 3],
|
|
62
54
|
t1 = output[++oi & 3],
|
|
@@ -73,15 +65,13 @@ let binlMD5 = (
|
|
|
73
65
|
0 | x[i + (j * (0x7351 >> l) + (0x0510 >> l) & 15)]
|
|
74
66
|
) +
|
|
75
67
|
(
|
|
76
|
-
|
|
77
|
-
K[63 - j++] ??= 0 |
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
0 | (t0 << t1 | t0 >>> 64 - t1) + output[oi + 2 & 3]
|
|
82
|
-
)
|
|
68
|
+
t2 = "',16%).4$+07&*/5".charCodeAt(j & 3 | l),
|
|
69
|
+
K[63 - j++] ??= 0 | 2 ** 32 * $Math.abs($Math.sin(j))
|
|
70
|
+
)
|
|
71
|
+
)) << t2 | t1 >>> 64 - t2
|
|
72
|
+
) + t0
|
|
83
73
|
}
|
|
84
|
-
for (oi
|
|
74
|
+
for (; oi; i += 4) {
|
|
85
75
|
oldOutput[--oi] = output[oi] = 0 | oldOutput[oi] + output[oi]
|
|
86
76
|
}
|
|
87
77
|
}
|
|
@@ -139,34 +129,40 @@ var md5 = (data, key, raw) => {
|
|
|
139
129
|
var i = 16
|
|
140
130
|
, hasKey = key != null
|
|
141
131
|
, [bdata, dataByteLen] = inputToBinl(data, /**@type {*}*/(hasKey) * i)
|
|
142
|
-
|
|
132
|
+
|
|
133
|
+
/** @type {*} */
|
|
134
|
+
var temp = []
|
|
135
|
+
|
|
136
|
+
/** @type {*} */
|
|
137
|
+
var out = raw ? new Uint8Array(i) : ''
|
|
143
138
|
|
|
144
139
|
if (hasKey) {
|
|
145
140
|
// HMAC
|
|
146
141
|
let [bkey, keyByteLen] = inputToBinl(key, 0)
|
|
147
|
-
let opad = []
|
|
148
142
|
if (keyByteLen > 64) {
|
|
149
143
|
bkey = binlMD5(bkey, keyByteLen)
|
|
150
144
|
}
|
|
151
145
|
for (; i;) {
|
|
152
146
|
// (0x36363636 ^ 0x5c5c5c5c) == 0x6a6a6a6a
|
|
153
|
-
|
|
147
|
+
temp[--i] = 0x6a6a6a6a ^ (bdata[i] = 0x36363636 ^ bkey[i])
|
|
154
148
|
}
|
|
155
149
|
i = 16
|
|
156
|
-
bdata =
|
|
150
|
+
bdata = temp.concat(binlMD5(bdata, 64 + dataByteLen))
|
|
157
151
|
dataByteLen = 80
|
|
158
152
|
}
|
|
159
153
|
|
|
160
154
|
bdata = binlMD5(bdata, dataByteLen)
|
|
161
155
|
|
|
162
|
-
// binl to bytes
|
|
163
|
-
for (; i;
|
|
164
|
-
|
|
156
|
+
// binl to bytes or hex
|
|
157
|
+
for (; i;
|
|
158
|
+
raw
|
|
159
|
+
? out[i] = temp
|
|
160
|
+
: out = (temp >> 4 && '') + temp.toString(16) + out
|
|
161
|
+
) {
|
|
162
|
+
temp = bdata[--i >> 2] >> i * 8 & 0xff
|
|
165
163
|
}
|
|
166
164
|
|
|
167
|
-
return
|
|
168
|
-
? out
|
|
169
|
-
: out.reduce((p, v) => p + (v >> 4 && '') + v.toString(16), '')
|
|
165
|
+
return out
|
|
170
166
|
}
|
|
171
167
|
|
|
172
168
|
export default md5
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tinyhmacmd5",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "A tiny
|
|
3
|
+
"version": "0.1.7",
|
|
4
|
+
"description": "A tiny and reliable HMAC-MD5 implementation for JavaScript: browser.min.js is only 997 bytes.",
|
|
5
5
|
"author": "bddjr",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
@@ -17,20 +17,35 @@
|
|
|
17
17
|
"keywords": [
|
|
18
18
|
"md5",
|
|
19
19
|
"hash",
|
|
20
|
+
"hashing",
|
|
20
21
|
"hmac",
|
|
21
22
|
"hmacmd5",
|
|
22
23
|
"hmac-md5",
|
|
23
24
|
"tiny",
|
|
25
|
+
"tiny-hmac-md5",
|
|
26
|
+
"small",
|
|
27
|
+
"lightweight",
|
|
28
|
+
"minimal",
|
|
24
29
|
"hex",
|
|
25
30
|
"crypto",
|
|
26
31
|
"encryption",
|
|
27
32
|
"cryptography",
|
|
33
|
+
"message-digest",
|
|
34
|
+
"cryptographic-hash",
|
|
35
|
+
"web",
|
|
36
|
+
"pure-javascript",
|
|
37
|
+
"esm",
|
|
38
|
+
"javascript",
|
|
39
|
+
"typescript",
|
|
40
|
+
"frontend",
|
|
41
|
+
"front-end",
|
|
28
42
|
"blueimp",
|
|
29
43
|
"blueimp-md5",
|
|
30
44
|
"js-md5",
|
|
31
45
|
"crypto-js",
|
|
32
|
-
"
|
|
33
|
-
"
|
|
46
|
+
"tiny-hashes",
|
|
47
|
+
"tiny-js-md5",
|
|
48
|
+
"spark-md5"
|
|
34
49
|
],
|
|
35
50
|
"repository": {
|
|
36
51
|
"type": "git",
|