tinyhmacmd5 0.1.0 → 0.1.2
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 +78 -4
- package/main.d.ts +12 -4
- package/main.js +16 -15
- package/package.json +14 -4
package/README.md
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
|
+
English | [中文](README-zh.md)
|
|
2
|
+
|
|
1
3
|
# Tiny HMAC MD5
|
|
2
4
|
|
|
3
|
-
A tiny,
|
|
5
|
+
A tiny, fully compliant HMAC-MD5 implementation for JavaScript:
|
|
6
|
+
[`browser.min.js`](browser.min.js) is only **1057 bytes**.
|
|
7
|
+
|
|
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**
|
|
4
13
|
|
|
5
|
-
|
|
14
|
+
**Live demo**: https://bddjr.github.io/tinyhmacmd5/
|
|
6
15
|
|
|
7
|
-
|
|
16
|
+
> [!WARNING]
|
|
17
|
+
> MD5 is cryptographically broken and unsafe for security-sensitive applications.
|
|
18
|
+
> Do not rely on it for password hashing, digital signatures, or certificate verification.
|
|
8
19
|
|
|
9
20
|
## Setup
|
|
10
21
|
|
|
11
22
|
### npm
|
|
12
23
|
|
|
24
|
+
|
|
13
25
|
```
|
|
14
26
|
npm i tinyhmacmd5
|
|
15
27
|
```
|
|
@@ -18,6 +30,10 @@ npm i tinyhmacmd5
|
|
|
18
30
|
import md5 from "tinyhmacmd5";
|
|
19
31
|
```
|
|
20
32
|
|
|
33
|
+
### Other Package Managers
|
|
34
|
+
|
|
35
|
+
You can also use other package managers (e.g. `pnpm` or `yarn`) in place of `npm`.
|
|
36
|
+
|
|
21
37
|
### jsDelivr
|
|
22
38
|
|
|
23
39
|
See https://www.jsdelivr.com/package/npm/tinyhmacmd5
|
|
@@ -26,10 +42,22 @@ See https://www.jsdelivr.com/package/npm/tinyhmacmd5
|
|
|
26
42
|
<script src="https://cdn.jsdelivr.net/npm/tinyhmacmd5"></script>
|
|
27
43
|
```
|
|
28
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
|
+
|
|
29
51
|
---
|
|
30
52
|
|
|
31
53
|
## Example
|
|
32
54
|
|
|
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.
|
|
60
|
+
|
|
33
61
|
HMAC-MD5:
|
|
34
62
|
|
|
35
63
|
```js
|
|
@@ -50,7 +78,7 @@ md5(Uint8Array.of(1, 2, 3), Uint8Array.of(4, 5, 6))
|
|
|
50
78
|
md5(Uint8Array.of(1, 2, 3), Uint8Array.of(4, 5, 6), true)
|
|
51
79
|
```
|
|
52
80
|
|
|
53
|
-
MD5:
|
|
81
|
+
MD5: (when `key` is `null` or `undefined`)
|
|
54
82
|
|
|
55
83
|
```js
|
|
56
84
|
// string to hex
|
|
@@ -72,6 +100,52 @@ md5(Uint8Array.of(1, 2, 3), null, true)
|
|
|
72
100
|
|
|
73
101
|
---
|
|
74
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 (1057 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
|
+
|
|
75
149
|
## Clone
|
|
76
150
|
|
|
77
151
|
```
|
package/main.d.ts
CHANGED
|
@@ -4,13 +4,21 @@
|
|
|
4
4
|
* By default, returns the hash as a lowercase hexadecimal string.
|
|
5
5
|
* If `raw` is true, returns a Uint8Array.
|
|
6
6
|
*
|
|
7
|
-
* @param {string | Uint8Array} data The input data to hash. Strings are UTF‑8 encoded.
|
|
8
|
-
* @param {string | Uint8Array | null} [key] Optional HMAC key. When given, HMAC‑MD5 is calculated instead of plain MD5.
|
|
7
|
+
* @param {string | Uint8Array | Uint8ClampedArray} data The input data to hash. Strings are UTF‑8 encoded.
|
|
8
|
+
* @param {string | Uint8Array | Uint8ClampedArray | null} [key] Optional HMAC key. When given, HMAC‑MD5 is calculated instead of plain MD5.
|
|
9
9
|
* @param {boolean} [raw] If true, the hash is returned as raw bytes (Uint8Array); otherwise, as a hex string.
|
|
10
10
|
* @returns {string | Uint8Array<ArrayBuffer>} The MD5 (or HMAC‑MD5) digest, either as a hex string or a Uint8Array.
|
|
11
11
|
*/
|
|
12
12
|
declare var md5: {
|
|
13
|
-
(
|
|
14
|
-
|
|
13
|
+
(
|
|
14
|
+
data: string | Uint8Array | Uint8ClampedArray,
|
|
15
|
+
key?: string | Uint8Array | Uint8ClampedArray | null,
|
|
16
|
+
raw?: false
|
|
17
|
+
): string;
|
|
18
|
+
(
|
|
19
|
+
data: string | Uint8Array | Uint8ClampedArray,
|
|
20
|
+
key: string | Uint8Array | Uint8ClampedArray | null | undefined,
|
|
21
|
+
raw: true
|
|
22
|
+
): Uint8Array<ArrayBuffer>;
|
|
15
23
|
};
|
|
16
24
|
export default md5;
|
package/main.js
CHANGED
|
@@ -64,10 +64,10 @@ let binlMD5 = (
|
|
|
64
64
|
(l = j >> 4 << 2)
|
|
65
65
|
? l > 4
|
|
66
66
|
? l > 8
|
|
67
|
-
? t1 ^ (t0 | ~t2) // Round 4:
|
|
68
|
-
: t0 ^ t1 ^ t2 // Round 3:
|
|
69
|
-
: t0 & t2 | t1 & ~t2 // Round 2:
|
|
70
|
-
: t0 & t1 | ~t0 & t2 // Round 1:
|
|
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)]
|
|
@@ -106,7 +106,8 @@ let inputToBinl = (
|
|
|
106
106
|
? input = new TextEncoder().encode(input)
|
|
107
107
|
: input
|
|
108
108
|
).length,
|
|
109
|
-
// Using Array
|
|
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
|
) => {
|
|
@@ -125,15 +126,15 @@ let inputToBinl = (
|
|
|
125
126
|
|
|
126
127
|
/**
|
|
127
128
|
* @overload
|
|
128
|
-
* @param {string | Uint8Array} data
|
|
129
|
-
* @param {string | Uint8Array | null} [key]
|
|
129
|
+
* @param {string | Uint8Array | Uint8ClampedArray} data
|
|
130
|
+
* @param {string | Uint8Array | Uint8ClampedArray | null} [key]
|
|
130
131
|
* @param {false} [raw]
|
|
131
132
|
* @returns {string}
|
|
132
133
|
*/
|
|
133
134
|
/**
|
|
134
135
|
* @overload
|
|
135
|
-
* @param {string | Uint8Array} data
|
|
136
|
-
* @param {string | Uint8Array | null | undefined} key
|
|
136
|
+
* @param {string | Uint8Array | Uint8ClampedArray} data
|
|
137
|
+
* @param {string | Uint8Array | Uint8ClampedArray | null | undefined} key
|
|
137
138
|
* @param {true} raw
|
|
138
139
|
* @returns {Uint8Array<ArrayBuffer>}
|
|
139
140
|
*/
|
|
@@ -143,8 +144,8 @@ let inputToBinl = (
|
|
|
143
144
|
* By default, returns the hash as a lowercase hexadecimal string.
|
|
144
145
|
* If `raw` is true, returns a Uint8Array.
|
|
145
146
|
*
|
|
146
|
-
* @param {string | Uint8Array} data The input data to hash. Strings are UTF‑8 encoded.
|
|
147
|
-
* @param {string | Uint8Array | null} [key] Optional HMAC key. When given, HMAC‑MD5 is calculated instead of plain MD5.
|
|
147
|
+
* @param {string | Uint8Array | Uint8ClampedArray} data The input data to hash. Strings are UTF‑8 encoded.
|
|
148
|
+
* @param {string | Uint8Array | Uint8ClampedArray | null} [key] Optional HMAC key. When given, HMAC‑MD5 is calculated instead of plain MD5.
|
|
148
149
|
* @param {boolean} [raw] If true, the hash is returned as raw bytes (Uint8Array); otherwise, as a hex string.
|
|
149
150
|
* @returns {string | Uint8Array<ArrayBuffer>} The MD5 (or HMAC‑MD5) digest, either as a hex string or a Uint8Array.
|
|
150
151
|
*/
|
|
@@ -157,17 +158,17 @@ var md5 = (data, key, raw) => {
|
|
|
157
158
|
if (hasKey) {
|
|
158
159
|
// HMAC
|
|
159
160
|
let [bkey, keyByteLen] = inputToBinl(key, 0)
|
|
160
|
-
let
|
|
161
|
+
let opad = []
|
|
161
162
|
if (keyByteLen > 64) {
|
|
162
163
|
bkey = binlMD5(bkey, keyByteLen)
|
|
163
164
|
}
|
|
164
165
|
for (; i;) {
|
|
165
|
-
bdata[--i] = 0x36363636 ^ bkey[i]
|
|
166
|
-
|
|
166
|
+
bdata[--i] = 0x36363636 ^ bkey[i] // ipad
|
|
167
|
+
opad[i] = 0x5c5c5c5c ^ bkey[i]
|
|
167
168
|
}
|
|
168
169
|
i = 16
|
|
169
170
|
bdata = binlMD5(bdata, 64 + dataByteLen)
|
|
170
|
-
bdata.unshift(...
|
|
171
|
+
bdata.unshift(...opad)
|
|
171
172
|
dataByteLen = 80
|
|
172
173
|
}
|
|
173
174
|
|
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.2",
|
|
4
|
+
"description": "A tiny, fully compliant HMAC-MD5 implementation for JavaScript: browser.min.js is only 1057 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
|
-
"
|
|
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
|
}
|