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 CHANGED
@@ -2,15 +2,18 @@ English | [中文](README-zh.md)
2
2
 
3
3
  # Tiny HMAC MD5
4
4
 
5
- A tiny, fully compliant HMAC-MD5 implementation for JavaScript:
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 raw `Uint8Array`
10
- - **Supports inputs ≥ 512 MiB**: Full 64‑bit length padding per RFC 1321
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
- ### Inline
48
+ It will define the `md5` function using `var`.
46
49
 
47
- You can embed [`browser.min.js`](browser.min.js) directly into your script.
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
- > This library does not validate input types.
57
- > Please ensure the input type matches the definitions in [`main.d.ts`](main.d.ts).
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<ArrayBuffer>
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<ArrayBuffer>
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<ArrayBuffer>
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<ArrayBuffer>
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 (1045 bytes) while also improving reliability.
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=1732584193,e=271733878,n=~r,t=~e,o=2**32,f=Math,a=f.floor,l=r=>16*a((r+8)/64)+16,c=[],d=(d,i,u=0,g=l(i),h,s,w,y,A=[r,t,n,e],v=[...A])=>{for(d[g-1]=0|8*i/o,d[g-2]=0|8*i,d[a(i/4)]|=128<<i%4*8;u<d.length;u+=16){for(y=g=0;g<64;)A[3&y]=0|((h=0|(h=A[3&++y],s=A[3&++y],w=A[3&++y],((i=g>>4<<2)?i>4?i>8?s^(h|~w):h^s^w:h&w|s&~w:h&s|~h&w)+(0|d[u+(g*(29521>>i)+(1296>>i)&15)])+(s="',16%).4$+07&*/5".charCodeAt(i+g%4),c[63-g++]??=0|o*f.abs(f.sin(g)))+A[y+1&3]))<<s|h>>>64-s)+A[y+2&3];for(y=4;y;)v[--y]=A[y]=0|v[y]+A[y]}return A},i=(r,e,n=("string"==typeof r?r=(new TextEncoder).encode(r):r).length,t=new Int32Array(l(4*e+n)),o=0)=>{for(;o<n;)t[e++]=r[o++]|r[o++]<<8|r[o++]<<16|r[o++]<<24;return[t,n]};var md5=(r,e,n)=>{var t=16,o=null!=e,[f,a]=i(r,o*t),l=new Uint8Array(t);if(o){let[r,n]=i(e,0),o=[];for(n>64&&(r=d(r,n));t;)o[--t]=1785358954^(f[t]=909522486^r[t]);t=16,f=o.concat(d(f,64+a)),a=80}for(f=d(f,a);t;)l[--t]=f[t>>2]>>>t%4*8;return n?l:l.reduce((r,e)=>r+(e>>4&&"")+e.toString(16),"")}}
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
- let A = 1732584193
6
- , D = 271733878
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
- let toBinlLen = (byteLen) => floor((byteLen + 8) / 64) * 16 + 16
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 = [A, B, C, D],
37
+ output = [t0, ~t1, ~t0, t1],
47
38
  oldOutput = [...output],
48
39
  ) => {
49
40
  // console.time("binlMD5")
50
41
 
51
42
  // append padding
52
- x[j - 1] = 0 | l * 8 / $2_32;
53
- x[j - 2] = 0 | l * 8;
54
- x[floor(l / 4)] |= 0x80 << l % 4 * 8;
55
-
56
- for (; i < x.length; i += 16) {
57
- for (oi = j = 0; j < 64;) {
58
- output[oi & 3] = (
59
- t0 = 0 | (
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
- t1 = "',16%).4$+07&*/5".charCodeAt(l + j % 4),
77
- K[63 - j++] ??= 0 | $2_32 * $Math.abs($Math.sin(j))
78
- ) +
79
- output[oi + 1 & 3]
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 = 4; 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
- , out = new Uint8Array(i)
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
- opad[--i] = 0x6a6a6a6a ^ (bdata[i] = 0x36363636 ^ bkey[i])
147
+ temp[--i] = 0x6a6a6a6a ^ (bdata[i] = 0x36363636 ^ bkey[i])
154
148
  }
155
149
  i = 16
156
- bdata = opad.concat(binlMD5(bdata, 64 + dataByteLen))
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
- out[--i] = bdata[i >> 2] >>> i % 4 * 8
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 raw
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.5",
4
- "description": "A tiny, fully compliant HMAC-MD5 implementation for JavaScript: browser.min.js is only 1045 bytes.",
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
- "javascript",
33
- "typescript"
46
+ "tiny-hashes",
47
+ "tiny-js-md5",
48
+ "spark-md5"
34
49
  ],
35
50
  "repository": {
36
51
  "type": "git",