@pirxpilot/argon2 0.44.0

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.
Files changed (4) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +95 -0
  3. package/argon2.js +178 -0
  4. package/package.json +39 -0
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Ranieri Althoff
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,95 @@
1
+ [![NPM version][npm-image]][npm-url]
2
+ [![Build Status][build-image]][build-url]
3
+ [![Dependency Status][deps-image]][deps-url]
4
+ [![Financial contributors on Open Collective][opencollective-image]][opencollective-url]
5
+
6
+ # @pirxpilot/argon2
7
+
8
+ This is a fork of [node-argon2] that is using [`crypto.argon2`][crypto.argon2] implementation as described in [#469]
9
+ It can be used with node >= 24.7.0
10
+
11
+ ## Usage
12
+ It's possible to hash using either Argon2i, Argon2d or Argon2id (default), and
13
+ verify if a password matches a hash.
14
+
15
+ To hash a password:
16
+ ```js
17
+ import * as argon2 from '@pirxpilot/argon2';
18
+
19
+ try {
20
+ const hash = await argon2.hash("password");
21
+ } catch (err) {
22
+ //...
23
+ }
24
+ ```
25
+
26
+ To verify a password:
27
+ ```js
28
+ try {
29
+ if (await argon2.verify("<big long hash>", "password")) {
30
+ // password match
31
+ } else {
32
+ // password did not match
33
+ }
34
+ } catch (err) {
35
+ // internal failure
36
+ }
37
+ ```
38
+
39
+ > [!NOTE]
40
+ > By default, argon2.hash will generate secure hashes according to the security recommendations by the team that develops Argon2.
41
+ > **For password hashing, there is no need to modify them.**
42
+
43
+ To see how you can modify the output (hash length, encoding) and parameters
44
+ (time cost, memory cost and parallelism),
45
+ [read the wiki](https://github.com/ranisalt/node-argon2/wiki/Options)
46
+
47
+ ## Contributors
48
+
49
+ ### Code contributors
50
+
51
+ This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
52
+ <a href="https://github.com/ranisalt/node-argon2/graphs/contributors"><img src="https://opencollective.com/node-argon2/contributors.svg?width=890&button=false" /></a>
53
+
54
+ ### Financial contributors
55
+
56
+ Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/node-argon2/contribute)]
57
+
58
+ #### Individuals
59
+
60
+ <a href="https://opencollective.com/node-argon2"><img src="https://opencollective.com/node-argon2/individuals.svg?width=890"></a>
61
+
62
+ #### Organizations
63
+
64
+ Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/node-argon2/contribute)]
65
+
66
+ <a href="https://opencollective.com/node-argon2/organization/0/website"><img src="https://opencollective.com/node-argon2/organization/0/avatar.svg"></a>
67
+ <a href="https://opencollective.com/node-argon2/organization/1/website"><img src="https://opencollective.com/node-argon2/organization/1/avatar.svg"></a>
68
+ <a href="https://opencollective.com/node-argon2/organization/2/website"><img src="https://opencollective.com/node-argon2/organization/2/avatar.svg"></a>
69
+ <a href="https://opencollective.com/node-argon2/organization/3/website"><img src="https://opencollective.com/node-argon2/organization/3/avatar.svg"></a>
70
+ <a href="https://opencollective.com/node-argon2/organization/4/website"><img src="https://opencollective.com/node-argon2/organization/4/avatar.svg"></a>
71
+ <a href="https://opencollective.com/node-argon2/organization/5/website"><img src="https://opencollective.com/node-argon2/organization/5/avatar.svg"></a>
72
+ <a href="https://opencollective.com/node-argon2/organization/6/website"><img src="https://opencollective.com/node-argon2/organization/6/avatar.svg"></a>
73
+ <a href="https://opencollective.com/node-argon2/organization/7/website"><img src="https://opencollective.com/node-argon2/organization/7/avatar.svg"></a>
74
+ <a href="https://opencollective.com/node-argon2/organization/8/website"><img src="https://opencollective.com/node-argon2/organization/8/avatar.svg"></a>
75
+ <a href="https://opencollective.com/node-argon2/organization/9/website"><img src="https://opencollective.com/node-argon2/organization/9/avatar.svg"></a>
76
+
77
+ ## License
78
+ Work licensed under the [MIT License](LICENSE). Please check
79
+ [P-H-C/phc-winner-argon2](https://github.com/P-H-C/phc-winner-argon2) for
80
+ license over Argon2 and the reference implementation.
81
+
82
+ [opencollective-image]: https://img.shields.io/opencollective/all/node-argon2.svg?style=flat-square
83
+ [opencollective-url]: https://opencollective.com/node-argon2
84
+ [node-argon2]: https://www.npmjs.com/package/argon2
85
+ [#469]: https://github.com/ranisalt/node-argon2/issues/469
86
+ [crypto.argon2]: https://nodejs.org/api/crypto.html#cryptoargon2algorithm-parameters-callback
87
+
88
+ [npm-image]: https://img.shields.io/npm/v/@pirxpilot/argon2
89
+ [npm-url]: https://npmjs.org/package/@pirxpilot/argon2
90
+
91
+ [build-url]: https://github.com/pirxpilot/argon2/actions/workflows/check.yaml
92
+ [build-image]: https://img.shields.io/github/actions/workflow/status/pirxpilot/argon2/check.yaml?branch=main
93
+
94
+ [deps-image]: https://img.shields.io/librariesio/release/npm/@pirxpilot/argon2
95
+ [deps-url]: https://libraries.io/npm/@pirxpilot%2Fargon2
package/argon2.js ADDED
@@ -0,0 +1,178 @@
1
+ import { argon2, randomBytes, timingSafeEqual } from 'node:crypto';
2
+ import { promisify } from 'node:util';
3
+ import { deserialize, serialize } from '@phc/format';
4
+
5
+ const asyncArgon2 = promisify(argon2);
6
+
7
+ /** @type {(size: number) => Promise<Buffer>} */
8
+ const generateSalt = promisify(randomBytes);
9
+
10
+ export const argon2d = 0;
11
+ export const argon2i = 1;
12
+ export const argon2id = 2;
13
+
14
+ /** @enum {argon2i | argon2d | argon2id} */
15
+ const types = Object.freeze({ argon2d, argon2i, argon2id });
16
+
17
+ /** @enum {'argon2d' | 'argon2i' | 'argon2id'} */
18
+ const names = Object.freeze({
19
+ [types.argon2d]: 'argon2d',
20
+ [types.argon2i]: 'argon2i',
21
+ [types.argon2id]: 'argon2id'
22
+ });
23
+
24
+ const defaults = {
25
+ hashLength: 32,
26
+ timeCost: 3,
27
+ memoryCost: 1 << 16,
28
+ parallelism: 4,
29
+ type: argon2id,
30
+ version: 0x13
31
+ };
32
+
33
+ /**
34
+ * @typedef {Object} Options
35
+ * @property {number} [hashLength=32]
36
+ * @property {number} [timeCost=3]
37
+ * @property {number} [memoryCost=65536]
38
+ * @property {number} [parallelism=4]
39
+ * @property {keyof typeof names} [type=argon2id]
40
+ * @property {number} [version=19]
41
+ * @property {Buffer} [salt]
42
+ * @property {Buffer} [associatedData]
43
+ * @property {Buffer} [secret]
44
+ */
45
+
46
+ /**
47
+ * Hashes a password with Argon2, producing a raw hash
48
+ *
49
+ * @overload
50
+ * @param {Buffer | string} password The plaintext password to be hashed
51
+ * @param {Options & { raw: true }} options The parameters for Argon2
52
+ * @returns {Promise<Buffer>} The raw hash generated from `password`
53
+ */
54
+ /**
55
+ * Hashes a password with Argon2, producing an encoded hash
56
+ *
57
+ * @overload
58
+ * @param {Buffer | string} password The plaintext password to be hashed
59
+ * @param {Options & { raw?: boolean }} [options] The parameters for Argon2
60
+ * @returns {Promise<string>} The encoded hash generated from `password`
61
+ */
62
+ /**
63
+ * @param {Buffer | string} password The plaintext password to be hashed
64
+ * @param {Options & { raw?: boolean }} [options] The parameters for Argon2
65
+ */
66
+ export async function hash(password, options) {
67
+ let { raw, salt, ...rest } = { ...defaults, ...options };
68
+
69
+ if (rest.hashLength > 2 ** 32 - 1) {
70
+ throw new RangeError('Hash length is too large');
71
+ }
72
+
73
+ if (rest.memoryCost > 2 ** 32 - 1) {
74
+ throw new RangeError('Memory cost is too large');
75
+ }
76
+
77
+ if (rest.timeCost > 2 ** 32 - 1) {
78
+ throw new RangeError('Time cost is too large');
79
+ }
80
+
81
+ if (rest.parallelism > 2 ** 24 - 1) {
82
+ throw new RangeError('Parallelism is too large');
83
+ }
84
+
85
+ salt = salt ?? (await generateSalt(16));
86
+
87
+ const {
88
+ hashLength,
89
+ secret = Buffer.alloc(0),
90
+ type,
91
+ version,
92
+ memoryCost: m,
93
+ timeCost: t,
94
+ parallelism: p,
95
+ associatedData: data = Buffer.alloc(0)
96
+ } = rest;
97
+
98
+ const hash = await asyncArgon2(names[type], {
99
+ message: Buffer.from(password),
100
+ nonce: salt,
101
+ tagLength: hashLength,
102
+ secret,
103
+ associatedData: data,
104
+ parallelism: p,
105
+ memory: m,
106
+ passes: t
107
+ });
108
+ if (raw) {
109
+ return hash;
110
+ }
111
+
112
+ return serialize({
113
+ id: names[type],
114
+ version,
115
+ params: { m, t, p, ...(data.byteLength > 0 ? { data } : {}) },
116
+ salt,
117
+ hash
118
+ });
119
+ }
120
+
121
+ /**
122
+ * @param {string} digest The digest to be checked
123
+ * @param {Object} [options] The current parameters for Argon2
124
+ * @param {number} [options.timeCost=3]
125
+ * @param {number} [options.memoryCost=65536]
126
+ * @param {number} [options.parallelism=4]
127
+ * @param {number} [options.version=0x13]
128
+ * @returns {boolean} `true` if the digest parameters do not match the parameters in `options`, otherwise `false`
129
+ */
130
+ export function needsRehash(digest, options = {}) {
131
+ const { memoryCost, timeCost, parallelism, version } = {
132
+ ...defaults,
133
+ ...options
134
+ };
135
+
136
+ const {
137
+ version: v,
138
+ params: { m, t, p }
139
+ } = deserialize(digest);
140
+
141
+ return +v !== +version || +m !== +memoryCost || +t !== +timeCost || +p !== +parallelism;
142
+ }
143
+
144
+ /**
145
+ * @param {string} digest The digest to be checked
146
+ * @param {Buffer | string} password The plaintext password to be verified
147
+ * @param {Object} [options] The current parameters for Argon2
148
+ * @param {Buffer} [options.secret]
149
+ * @returns {Promise<boolean>} `true` if the digest parameters matches the hash generated from `password`, otherwise `false`
150
+ */
151
+ export async function verify(digest, password, options = {}) {
152
+ const { id, ...rest } = deserialize(digest);
153
+ if (!(id in types)) {
154
+ return false;
155
+ }
156
+
157
+ const {
158
+ params: { m, t, p, data = '' },
159
+ salt,
160
+ hash
161
+ } = rest;
162
+
163
+ const { secret = Buffer.alloc(0) } = options;
164
+
165
+ return timingSafeEqual(
166
+ await asyncArgon2(names[types[id]], {
167
+ message: Buffer.from(password),
168
+ nonce: salt,
169
+ tagLength: hash.byteLength,
170
+ secret,
171
+ associatedData: Buffer.from(data, 'base64'),
172
+ parallelism: p,
173
+ memory: m,
174
+ passes: t
175
+ }),
176
+ hash
177
+ );
178
+ }
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@pirxpilot/argon2",
3
+ "version": "0.44.0",
4
+ "description": "An Argon2 library for Node",
5
+ "keywords": [
6
+ "argon2",
7
+ "crypto",
8
+ "encryption",
9
+ "hashing",
10
+ "password"
11
+ ],
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/pirxpilot/argon2.git"
15
+ },
16
+ "license": "MIT",
17
+ "author": "Ranieri Althoff <ranisalt+argon2@gmail.com>",
18
+ "type": "module",
19
+ "exports": "./argon2.js",
20
+ "files": [
21
+ "argon2.js"
22
+ ],
23
+ "scripts": {
24
+ "test": "make check"
25
+ },
26
+ "dependencies": {
27
+ "@phc/format": "^1.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "@biomejs/biome": "2.3.11"
31
+ },
32
+ "engines": {
33
+ "node": ">= 24.7.0"
34
+ },
35
+ "collective": {
36
+ "type": "opencollective",
37
+ "url": "https://opencollective.com/node-argon2"
38
+ }
39
+ }