tinyhmacmd5 0.1.1 → 0.1.3

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
@@ -1,10 +1,17 @@
1
+ English | [中文](README-zh.md)
2
+
1
3
  # Tiny HMAC MD5
2
4
 
3
- A tiny JavaScript HMAC-MD5 implementation.
5
+ A tiny, fully compliant HMAC-MD5 implementation for JavaScript:
6
+ [`browser.min.js`](browser.min.js) is only **1051 bytes**.
4
7
 
5
- The minified browser bundle ([`browser.min.js`](browser.min.js)) is only 1057 bytes.
8
+ - **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
11
+ - **TypeScript‑ready**: [`main.d.ts`](main.d.ts)
12
+ - **0 dependencies**
6
13
 
7
- Preview: https://bddjr.github.io/tinyhmacmd5/
14
+ **Live demo**: https://bddjr.github.io/tinyhmacmd5/
8
15
 
9
16
  > [!WARNING]
10
17
  > MD5 is cryptographically broken and unsafe for security-sensitive applications.
@@ -14,6 +21,7 @@ Preview: https://bddjr.github.io/tinyhmacmd5/
14
21
 
15
22
  ### npm
16
23
 
24
+
17
25
  ```
18
26
  npm i tinyhmacmd5
19
27
  ```
@@ -22,6 +30,10 @@ npm i tinyhmacmd5
22
30
  import md5 from "tinyhmacmd5";
23
31
  ```
24
32
 
33
+ ### Other Package Managers
34
+
35
+ You can also use other package managers (e.g. `pnpm` or `yarn`) in place of `npm`.
36
+
25
37
  ### jsDelivr
26
38
 
27
39
  See https://www.jsdelivr.com/package/npm/tinyhmacmd5
@@ -30,13 +42,21 @@ See https://www.jsdelivr.com/package/npm/tinyhmacmd5
30
42
  <script src="https://cdn.jsdelivr.net/npm/tinyhmacmd5"></script>
31
43
  ```
32
44
 
45
+ ### Inline
46
+
47
+ You can embed [`browser.min.js`](browser.min.js) directly into your script.
48
+
49
+ It will define the `md5` function using `var`.
50
+
33
51
  ---
34
52
 
35
53
  ## Example
36
54
 
37
- > [!WARNING]
38
- > Please make sure on your own that the types of input parameters conform to the definitions in [`main.d.ts`](main.d.ts).
39
- > If you pass wrong types, it may not throw an error and may produce incorrect results.
55
+ > [!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.
40
60
 
41
61
  HMAC-MD5:
42
62
 
@@ -58,7 +78,7 @@ md5(Uint8Array.of(1, 2, 3), Uint8Array.of(4, 5, 6))
58
78
  md5(Uint8Array.of(1, 2, 3), Uint8Array.of(4, 5, 6), true)
59
79
  ```
60
80
 
61
- MD5:
81
+ MD5: (when `key` is `null` or `undefined`)
62
82
 
63
83
  ```js
64
84
  // string to hex
@@ -80,6 +100,52 @@ md5(Uint8Array.of(1, 2, 3), null, true)
80
100
 
81
101
  ---
82
102
 
103
+ ## Runtime Environment
104
+
105
+ Environments that support [Nullish coalescing assignment (`??=`)](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_assignment) :
106
+
107
+ - Chrome ≥ 85 (2020-08-25)
108
+ - Edge ≥ 85 (2020-08-27)
109
+ - Firefox ≥ 79 (2020-07-28)
110
+ - Safari ≥ 14 (2020-09-16)
111
+
112
+ ---
113
+
114
+ ## Why I Made This Project
115
+
116
+ > [!NOTE]
117
+ > AI-translated from Chinese.
118
+ > [查看原文](README-zh.md#为什么做这个项目)
119
+
120
+ 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
+
122
+ 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.
123
+
124
+ Then I found `blueimp-md5`. Its `md5.min.js` is only 3750 bytes, even smaller than `js-md5`.
125
+
126
+ But I felt `blueimp-md5` was still far too bloated. It has some completely unnecessary design choices—it repeatedly parses strings and creates new ones, adding a lot of unnecessary overhead.
127
+
128
+ So I decided to adapt it, use a more modern implementation, and shrink the size even further. That's how `tinyhmacmd5` was born.
129
+
130
+ During the adaptation, I discovered that `blueimp-md5` did not correctly handle the 64-bit length field required by MD5 when the input bit-length exceeded 32 bits. It wrote only the low 32 bits and ignored the high 32 bits. I fixed this bug.
131
+
132
+ I also found that using `Array` to process inputs over 512 MiB could throw a `RangeError`, so I replaced it with `Int32Array`.
133
+
134
+ I demonstrated in practice that HMAC-MD5 can be implemented in an extremely small footprint (1051 bytes) while also improving reliability.
135
+
136
+ Maybe not many people care about saving just a few KB, but `tinyhmacmd5` exists precisely to "explore the unknown".
137
+
138
+ INVINCIBLE EXPERIMENT!
139
+
140
+ ---
141
+
142
+ ## License
143
+
144
+ The MIT License
145
+ See: [`LICENSE`](LICENSE)
146
+
147
+ ---
148
+
83
149
  ## Clone
84
150
 
85
151
  ```
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,i=[],u=(u,d,h=0,c=l(d),g,s,w,y,A=[r,t,n,e],v=[...A])=>{for(u[c-1]=0|8*d/o,u[c-2]=0|8*d,u[a(d/4)]|=128<<d%4*8;h<u.length;h+=16){for(y=c=0;c<64;)A[3&y]=0|((g=0|(g=A[3&++y],s=A[3&++y],w=A[3&++y],((d=c>>4<<2)?d>4?d>8?s^(g|~w):g^s^w:g&w|s&~w:g&s|~g&w)+(0|u[h+(c*(29521>>d)+(1296>>d)&15)])+(s=31&"',16%).4$+07&*/5".charCodeAt(d+c%4),i[63-c++]??=0|o*f.abs(f.sin(c)))+A[y+1&3]))<<s|g>>>32-s)+A[y+2&3];for(y=4;y;)v[--y]=A[y]=0|v[y]+A[y]}return A},d=(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]=d(r,o*t),l=new Uint8Array(t);if(o){let[r,n]=d(e,0),o=[];for(n>64&&(r=u(r,n));t;)f[--t]=909522486^r[t],o[t]=1549556828^r[t];t=16,(f=u(f,64+a)).unshift(...o),a=80}for(f=u(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=1732584193,e=271733878,n=~r,t=~e,o=2**32,f=Math,a=f.floor,l=r=>16*a((r+8)/64)+16,i=[],u=(u,d,h=0,c=l(d),g,s,w,y,A=[r,t,n,e],v=[...A])=>{for(u[c-1]=0|8*d/o,u[c-2]=0|8*d,u[a(d/4)]|=128<<d%4*8;h<u.length;h+=16){for(y=c=0;c<64;)A[3&y]=0|((g=0|(g=A[3&++y],s=A[3&++y],w=A[3&++y],((d=c>>4<<2)?d>4?d>8?s^(g|~w):g^s^w:g&w|s&~w:g&s|~g&w)+(0|u[h+(c*(29521>>d)+(1296>>d)&15)])+(s="',16%).4$+07&*/5".charCodeAt(d+c%4),i[63-c++]??=0|o*f.abs(f.sin(c)))+A[y+1&3]))<<s|g>>>64-s)+A[y+2&3];for(y=4;y;)v[--y]=A[y]=0|v[y]+A[y]}return A},d=(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]=d(r,o*t),l=new Uint8Array(t);if(o){let[r,n]=d(e,0),o=[];for(n>64&&(r=u(r,n));t;)o[--t]=1785358954^(f[t]=909522486^r[t]);t=16,(f=u(f,64+a)).unshift(...o),a=80}for(f=u(f,a);t;)l[--t]=f[t>>2]>>>t%4*8;return n?l:l.reduce((r,e)=>r+(e>>4&&"")+e.toString(16),"")}}
package/main.js CHANGED
@@ -64,21 +64,21 @@ let binlMD5 = (
64
64
  (l = j >> 4 << 2)
65
65
  ? l > 4
66
66
  ? l > 8
67
- ? t1 ^ (t0 | ~t2) // Round 4: II
68
- : t0 ^ t1 ^ t2 // Round 3: HH
69
- : t0 & t2 | t1 & ~t2 // Round 2: GG
70
- : t0 & t1 | ~t0 & t2 // Round 1: FF
67
+ ? t1 ^ (t0 | ~t2) // Round 4: I
68
+ : t0 ^ t1 ^ t2 // Round 3: H
69
+ : t0 & t2 | t1 & ~t2 // Round 2: G
70
+ : t0 & t1 | ~t0 & t2 // Round 1: F
71
71
  ) +
72
72
  (
73
73
  0 | x[i + (j * (0x7351 >> l) + (0x0510 >> l) & 15)]
74
74
  ) +
75
75
  (
76
- t1 = "',16%).4$+07&*/5".charCodeAt(l + j % 4) & 31,
76
+ t1 = "',16%).4$+07&*/5".charCodeAt(l + j % 4),
77
77
  K[63 - j++] ??= 0 | $2_32 * $Math.abs($Math.sin(j))
78
78
  ) +
79
79
  output[oi + 1 & 3]
80
80
  ),
81
- 0 | (t0 << t1 | t0 >>> 32 - t1) + output[oi + 2 & 3]
81
+ 0 | (t0 << t1 | t0 >>> 64 - t1) + output[oi + 2 & 3]
82
82
  )
83
83
  }
84
84
  for (oi = 4; oi;) {
@@ -106,7 +106,8 @@ let inputToBinl = (
106
106
  ? input = new TextEncoder().encode(input)
107
107
  : input
108
108
  ).length,
109
- // Using Array would fail to handle large files, so Int32Array must be used.
109
+ // Using `Array` to process inputs over 512 MiB could throw a `RangeError`,
110
+ // so I replaced it with `Int32Array`.
110
111
  output = new Int32Array(toBinlLen(j * 4 + byteLen)),
111
112
  i = 0,
112
113
  ) => {
@@ -162,8 +163,8 @@ var md5 = (data, key, raw) => {
162
163
  bkey = binlMD5(bkey, keyByteLen)
163
164
  }
164
165
  for (; i;) {
165
- bdata[--i] = 0x36363636 ^ bkey[i] // ipad
166
- opad[i] = 0x5c5c5c5c ^ bkey[i]
166
+ // (0x36363636 ^ 0x5c5c5c5c) == 0x6a6a6a6a
167
+ opad[--i] = 0x6a6a6a6a ^ (bdata[i] = 0x36363636 ^ bkey[i])
167
168
  }
168
169
  i = 16
169
170
  bdata = binlMD5(bdata, 64 + dataByteLen)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tinyhmacmd5",
3
- "version": "0.1.1",
4
- "description": "A tiny JavaScript HMAC-MD5 implementation. The minified browser bundle is only 1057 bytes.",
3
+ "version": "0.1.3",
4
+ "description": "A tiny, fully compliant HMAC-MD5 implementation for JavaScript: browser.min.js is only 1051 bytes.",
5
5
  "author": "bddjr",
6
6
  "license": "MIT",
7
7
  "type": "module",
@@ -16,14 +16,21 @@
16
16
  "homepage": "https://bddjr.github.io/tinyhmacmd5/",
17
17
  "keywords": [
18
18
  "md5",
19
+ "hash",
19
20
  "hmac",
20
21
  "hmacmd5",
21
22
  "hmac-md5",
22
23
  "tiny",
23
24
  "hex",
24
25
  "crypto",
26
+ "encryption",
27
+ "cryptography",
25
28
  "blueimp",
26
- "blueimp-md5"
29
+ "blueimp-md5",
30
+ "js-md5",
31
+ "crypto-js",
32
+ "javascript",
33
+ "typescript"
27
34
  ],
28
35
  "repository": {
29
36
  "type": "git",
@@ -37,6 +44,9 @@
37
44
  },
38
45
  "scripts": {
39
46
  "build": "tsc && node scripts/build.mjs && es-check es2021 --module --checkFeatures main.js browser.min.js",
40
- "test": "pnpm build && node scripts/test.mjs"
47
+ "build:unchanged": "node scripts/build-unchanged.mjs",
48
+ "test": "pnpm build && pnpm test:only",
49
+ "test:only": "node scripts/test.mjs",
50
+ "test:unchanged": "pnpm build:unchanged && pnpm test:only"
41
51
  }
42
52
  }