tinyhmacmd5 0.4.1 → 0.4.2-es2026
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 +29 -31
- package/browser.min.js +1 -1
- package/main.js +11 -18
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,7 +2,9 @@ English | [中文](README-zh.md)
|
|
|
2
2
|
|
|
3
3
|
# Tiny HMAC MD5
|
|
4
4
|
|
|
5
|
-
A tiny and reliable HMAC-MD5 implementation for JavaScript:
|
|
5
|
+
A tiny and reliable HMAC-MD5 implementation for JavaScript:
|
|
6
|
+
|
|
7
|
+
[`browser.min.js`](browser.min.js) is only **975 bytes**.
|
|
6
8
|
|
|
7
9
|
- **Input type**: `string` (UTF‑8), `Uint8Array` or `Uint8ClampedArray`
|
|
8
10
|
- **Output type**: hex `string` or bytes `Uint8Array`
|
|
@@ -10,14 +12,10 @@ A tiny and reliable HMAC-MD5 implementation for JavaScript: [`browser.min.js`](b
|
|
|
10
12
|
- **TypeScript‑ready**: [`main.d.ts`](main.d.ts)
|
|
11
13
|
- **0 dependencies**
|
|
12
14
|
|
|
13
|
-
**Live demo**: https://bddjr.github.io/tinyhmacmd5/
|
|
14
|
-
|
|
15
15
|
`tinyhmacmd5` does not simply aim for the smallest possible size.
|
|
16
16
|
Its goal is to balance code size and runtime performance, so some performance-oriented implementations are intentionally retained.
|
|
17
17
|
As a result, the final size is not the smallest theoretically achievable.
|
|
18
18
|
|
|
19
|
-
If you need a smaller implementation that targets ECMAScript 2026, see the [`es2026`](https://github.com/bddjr/tinyhmacmd5/tree/es2026) branch.
|
|
20
|
-
|
|
21
19
|
> [!WARNING]
|
|
22
20
|
> MD5 is cryptographically broken and unsafe for security-sensitive applications.
|
|
23
21
|
> Do not rely on it for password hashing, digital signatures, or certificate verification.
|
|
@@ -27,7 +25,7 @@ If you need a smaller implementation that targets ECMAScript 2026, see the [`es2
|
|
|
27
25
|
### npm
|
|
28
26
|
|
|
29
27
|
```
|
|
30
|
-
npm i tinyhmacmd5
|
|
28
|
+
npm i tinyhmacmd5@es2026
|
|
31
29
|
```
|
|
32
30
|
|
|
33
31
|
```js
|
|
@@ -43,7 +41,7 @@ You can also use other package managers (e.g. `pnpm` or `yarn`) in place of `npm
|
|
|
43
41
|
See https://www.jsdelivr.com/package/npm/tinyhmacmd5
|
|
44
42
|
|
|
45
43
|
```html
|
|
46
|
-
<script src="https://cdn.jsdelivr.net/npm/tinyhmacmd5"></script>
|
|
44
|
+
<script src="https://cdn.jsdelivr.net/npm/tinyhmacmd5@es2026"></script>
|
|
47
45
|
```
|
|
48
46
|
|
|
49
47
|
It will define the `md5` function using `var`.
|
|
@@ -51,7 +49,7 @@ It will define the `md5` function using `var`.
|
|
|
51
49
|
### UNPKG
|
|
52
50
|
|
|
53
51
|
```html
|
|
54
|
-
<script src="https://unpkg.com/tinyhmacmd5"></script>
|
|
52
|
+
<script src="https://unpkg.com/tinyhmacmd5@es2026"></script>
|
|
55
53
|
```
|
|
56
54
|
|
|
57
55
|
It will define the `md5` function using `var`.
|
|
@@ -142,22 +140,22 @@ md5(data)
|
|
|
142
140
|
|
|
143
141
|
## Runtime Environment
|
|
144
142
|
|
|
145
|
-
Environments that support [
|
|
143
|
+
Environments that support [`Uint8Array.prototype.toHex()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/toHex) :
|
|
146
144
|
|
|
147
145
|
- Desktop
|
|
148
|
-
- Chrome ≥
|
|
149
|
-
- Edge ≥
|
|
150
|
-
- Firefox ≥
|
|
151
|
-
- Opera ≥
|
|
152
|
-
- Safari ≥
|
|
146
|
+
- Chrome ≥ 140 (2025-09-02)
|
|
147
|
+
- Edge ≥ 140 (2025-09-05)
|
|
148
|
+
- Firefox ≥ 133 (2024-11-26)
|
|
149
|
+
- Opera ≥ 124 (2025-11-13)
|
|
150
|
+
- Safari ≥ 18.2 (2024-12-11)
|
|
153
151
|
- Mobile
|
|
154
|
-
- Chrome Android ≥
|
|
155
|
-
- Firefox for Android ≥
|
|
156
|
-
- Opera Android ≥
|
|
157
|
-
- Safari on iOS ≥
|
|
158
|
-
- Samsung Browser
|
|
159
|
-
- WebView Android ≥
|
|
160
|
-
- WebView on iOS ≥
|
|
152
|
+
- Chrome Android ≥ 140 (2025-09-02)
|
|
153
|
+
- Firefox for Android ≥ 133 (2024-11-26)
|
|
154
|
+
- Opera Android ≥ 92 (2025-10-08)
|
|
155
|
+
- Safari on iOS ≥ 18.2 (2024-12-11)
|
|
156
|
+
- Samsung Browser ×
|
|
157
|
+
- WebView Android ≥ 140 (2025-09-02)
|
|
158
|
+
- WebView on iOS ≥ 18.2 (2024-12-11)
|
|
161
159
|
|
|
162
160
|
Not recommended for use in environments that support `node:crypto`, as `node:crypto` already provides HMAC-MD5.
|
|
163
161
|
|
|
@@ -172,19 +170,19 @@ pnpm benchmark
|
|
|
172
170
|
```
|
|
173
171
|
Data length: 104857600 chars (100MiB)
|
|
174
172
|
--------------------------------------------------
|
|
175
|
-
tinyhmacmd5 :
|
|
176
|
-
js-md5 :
|
|
177
|
-
blueimp-md5 :
|
|
178
|
-
crypto-js :
|
|
179
|
-
node:crypto :
|
|
173
|
+
tinyhmacmd5 : 550.92 ms
|
|
174
|
+
js-md5 : 128.96 ms
|
|
175
|
+
blueimp-md5 : 3837.83 ms
|
|
176
|
+
crypto-js : 1562.08 ms
|
|
177
|
+
node:crypto : 129.08 ms
|
|
180
178
|
--------------------------------------------------
|
|
181
179
|
✅ All pure JS implementations match node:crypto result.
|
|
182
180
|
|
|
183
181
|
--- Pure 513MiB Test (No prior small tests) ---
|
|
184
|
-
tinyhmacmd5 HMAC-MD5 timer: 2.
|
|
185
|
-
node:crypto HMAC-MD5 timer:
|
|
186
|
-
tinyhmacmd5 MD5 timer: 2.
|
|
187
|
-
node:crypto MD5 timer: 550.
|
|
182
|
+
tinyhmacmd5 HMAC-MD5 timer: 2.706s
|
|
183
|
+
node:crypto HMAC-MD5 timer: 547.808ms
|
|
184
|
+
tinyhmacmd5 MD5 timer: 2.693s
|
|
185
|
+
node:crypto MD5 timer: 550.144ms
|
|
188
186
|
```
|
|
189
187
|
|
|
190
188
|
CPU: i5-10600KF
|
|
@@ -210,7 +208,7 @@ During the adaptation, I discovered that `blueimp-md5` did not correctly handle
|
|
|
210
208
|
|
|
211
209
|
I also found that using `Array` to process inputs over 512 MiB could throw a `RangeError`, so I replaced it with `Int32Array`.
|
|
212
210
|
|
|
213
|
-
I demonstrated in practice that HMAC-MD5 can be implemented in an extremely small footprint (
|
|
211
|
+
I demonstrated in practice that HMAC-MD5 can be implemented in an extremely small footprint (975 bytes) while also improving reliability.
|
|
214
212
|
|
|
215
213
|
Maybe not many people care about saving just a few KB, but `tinyhmacmd5` exists precisely to "explore the unknown".
|
|
216
214
|
|
package/browser.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
/*! npmjs.com/tinyhmacmd5 */{let e=
|
|
1
|
+
/*! npmjs.com/tinyhmacmd5 */{let e=Int32Array,r=Uint8Array,n=new e(64).map((e,r)=>2**32*Math.abs(Math.sin(r+1))),t=1&new r(n.buffer)[3],f=(r,t,f=0,o,a=1732584193,w=271733878,l,u,h=r.length,s=e.of(a,~w,~a,w),d=new e(s))=>{for(r[h-1]=t/2**29,r[(t-t%4)/4]|=128<<(r[h-2]=t<<3);f<h;f+=16){for(t=o=0;t<16;t+=4)for(;o<4*t+16;)s[u&=3]=((w=s[u]+n[o]+(a=s[3&++u],w=s[3&++u],l=s[3&++u],w^(t>4?t>8?a|~l:a^l:t?l&(a^w):~a&(w^l)))+r[f+(o*(29521>>t)+(1296>>t)&15)])<<(l="',16%).4$+07&*/5".charCodeAt(3&o++|t))|w>>>32-l)+a;for(;u;)d[--u]=s[u]+=d[u]}return s},o=(n,f,o=("string"==typeof n?n=(new TextEncoder).encode(n):n).length,a=new e(f+18+(o-(o+8&63))/4),w=t&&new r(a.buffer,4*f).set(n))=>{for(;w<o;3&++w||f++)a[f]|=n[w]<<8*w;return[a,o]};var md5=(n,t,a)=>{var w=16,l=null!=t,[u,h]=o(n,l*w),s=new r(w);if(l){let[r,n]=o(t,0),a=new e(32);for(n>64&&(r=f(r,n)),n=w;n;)a[--n]=1785358954^(u[n]=909522486^r[n]);a.set(f(u,64+h),w),u=a,h=80}for(u=f(u,h);w;)s[--w]=u[w>>2]>>8*w;return a?s:s.toHex()}}
|
package/main.js
CHANGED
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
// Adapted from https://github.com/blueimp/JavaScript-MD5
|
|
4
4
|
|
|
5
|
-
let $Math = Math
|
|
6
|
-
|
|
7
5
|
let $Int32Array = Int32Array
|
|
8
6
|
|
|
9
7
|
let $Uint8Array = Uint8Array
|
|
10
8
|
|
|
11
9
|
/** MD5 constants cached in memory */
|
|
12
|
-
let K = new $Int32Array(64).map((v, i) => 2 ** 32 *
|
|
10
|
+
let K = new $Int32Array(64).map((v, i) => 2 ** 32 * Math.abs(Math.sin(i + 1)))
|
|
13
11
|
|
|
14
12
|
/** is little-endian */
|
|
15
13
|
let isLE = new $Uint8Array(K.buffer)[3] & 1
|
|
@@ -44,16 +42,16 @@ let wordsMD5 = (
|
|
|
44
42
|
// `l` may be >= 2**32, so cannot use `>>>` as a replacement for `floor`.
|
|
45
43
|
// `l << 3` cannot be changed to `l * 8`, as it would trigger JIT deoptimization on large inputs.
|
|
46
44
|
x[xLen - 1] = l / 2 ** 29;
|
|
47
|
-
x[
|
|
45
|
+
x[(l - l % 4) / 4] |= 0x80 << (x[xLen - 2] = l << 3);
|
|
48
46
|
|
|
49
47
|
for (; i < xLen; i += 16) {
|
|
50
|
-
for (l = 0; l < 16; l += 4) {
|
|
51
|
-
for (
|
|
48
|
+
for (l = j = 0; l < 16; l += 4) {
|
|
49
|
+
for (; j < 4 * l + 16;) {
|
|
52
50
|
output[oi &= 3] = (
|
|
53
51
|
(
|
|
54
52
|
t1 = (
|
|
55
53
|
output[oi] +
|
|
56
|
-
K[
|
|
54
|
+
K[j] +
|
|
57
55
|
(
|
|
58
56
|
t0 = output[++oi & 3],
|
|
59
57
|
t1 = output[++oi & 3],
|
|
@@ -98,13 +96,14 @@ let inputToWords = (
|
|
|
98
96
|
j,
|
|
99
97
|
// var:
|
|
100
98
|
byteLen = (
|
|
99
|
+
// Don't replace the type check below with something like `input.big`; it's unreliable.
|
|
101
100
|
typeof input == 'string'
|
|
102
101
|
? input = new TextEncoder().encode(input)
|
|
103
102
|
: input
|
|
104
103
|
).length,
|
|
105
104
|
// Using `Array` to process inputs over 512 MiB could throw a `RangeError`,
|
|
106
105
|
// so I replaced it with `Int32Array`.
|
|
107
|
-
output = new $Int32Array(j +
|
|
106
|
+
output = new $Int32Array(j + 18 + (byteLen - (byteLen + 8 & 63)) / 4),
|
|
108
107
|
// (fast) little-endian
|
|
109
108
|
i = isLE && new $Uint8Array(output.buffer, j * 4).set(input),
|
|
110
109
|
) => {
|
|
@@ -130,9 +129,7 @@ var md5 = (data, key, raw) => {
|
|
|
130
129
|
var i = 16
|
|
131
130
|
, hasKey = key != null
|
|
132
131
|
, [bdata, temp] = inputToWords(data, /**@type {*}*/(hasKey) * i)
|
|
133
|
-
|
|
134
|
-
/** @type {*} */
|
|
135
|
-
var out = raw ? new $Uint8Array(i) : ''
|
|
132
|
+
, out = new $Uint8Array(i)
|
|
136
133
|
|
|
137
134
|
if (hasKey) {
|
|
138
135
|
// HMAC
|
|
@@ -153,15 +150,11 @@ var md5 = (data, key, raw) => {
|
|
|
153
150
|
bdata = wordsMD5(bdata, temp)
|
|
154
151
|
|
|
155
152
|
// words to bytes or hex
|
|
156
|
-
for (; i;
|
|
157
|
-
|
|
158
|
-
? out[i] = temp
|
|
159
|
-
: out = (temp >> 4 && '') + temp.toString(16) + out
|
|
160
|
-
) {
|
|
161
|
-
temp = bdata[--i >> 2] >> i * 8 & 0xff
|
|
153
|
+
for (; i;) {
|
|
154
|
+
out[--i] = bdata[i >> 2] >> i * 8
|
|
162
155
|
}
|
|
163
156
|
|
|
164
|
-
return out
|
|
157
|
+
return raw ? out : out.toHex()
|
|
165
158
|
}
|
|
166
159
|
|
|
167
160
|
export default md5
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tinyhmacmd5",
|
|
3
|
-
"version": "0.4.
|
|
4
|
-
"description": "A tiny and reliable HMAC-MD5 implementation for JavaScript: browser.min.js is only
|
|
3
|
+
"version": "0.4.2-es2026",
|
|
4
|
+
"description": "A tiny and reliable HMAC-MD5 implementation for JavaScript: browser.min.js is only 975 bytes.",
|
|
5
5
|
"author": "bddjr",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"typescript": "^7.0.2"
|
|
64
64
|
},
|
|
65
65
|
"scripts": {
|
|
66
|
-
"build": "tsc && node scripts/build.mjs && es-check
|
|
66
|
+
"build": "tsc && node scripts/build.mjs && es-check es2026 --module --checkFeatures main.js browser.min.js",
|
|
67
67
|
"build:unchanged": "node scripts/build-unchanged.mjs",
|
|
68
68
|
"test": "pnpm build && pnpm test:only",
|
|
69
69
|
"test:only": "node scripts/test.mjs && node scripts/test-513MiB.mjs",
|