@gjsify/crypto 0.3.13 → 0.3.15
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/lib/esm/asn1.js +576 -450
- package/lib/esm/bigint-math.js +37 -28
- package/lib/esm/cipher.js +1252 -1229
- package/lib/esm/constants.js +12 -13
- package/lib/esm/crypto-utils.js +54 -36
- package/lib/esm/dh.js +408 -368
- package/lib/esm/ecdh.js +403 -321
- package/lib/esm/ecdsa.js +138 -111
- package/lib/esm/hash.js +100 -89
- package/lib/esm/hkdf.js +65 -47
- package/lib/esm/hmac.js +95 -90
- package/lib/esm/index.js +75 -148
- package/lib/esm/key-object.js +348 -307
- package/lib/esm/mgf1.js +30 -24
- package/lib/esm/pbkdf2.js +66 -59
- package/lib/esm/public-encrypt.js +203 -156
- package/lib/esm/random.js +137 -124
- package/lib/esm/rsa-oaep.js +94 -87
- package/lib/esm/rsa-pss.js +95 -88
- package/lib/esm/scrypt.js +116 -115
- package/lib/esm/sign.js +267 -237
- package/lib/esm/timing-safe-equal.js +16 -11
- package/lib/esm/x509.js +215 -206
- package/package.json +7 -7
package/lib/esm/sign.js
CHANGED
|
@@ -1,248 +1,278 @@
|
|
|
1
|
-
import { Buffer } from "node:buffer";
|
|
2
|
-
import { Hash } from "./hash.js";
|
|
3
1
|
import { parsePemKey, rsaKeySize } from "./asn1.js";
|
|
4
|
-
import {
|
|
2
|
+
import { bigIntToBytes, bytesToBigInt, modPow } from "./bigint-math.js";
|
|
3
|
+
import { Hash } from "./hash.js";
|
|
4
|
+
import { Buffer } from "node:buffer";
|
|
5
|
+
|
|
6
|
+
//#region src/sign.ts
|
|
7
|
+
/**
|
|
8
|
+
* DigestInfo DER prefix bytes for each supported hash algorithm.
|
|
9
|
+
* These encode: SEQUENCE { SEQUENCE { OID hashAlg, NULL }, OCTET STRING hashValue }
|
|
10
|
+
* excluding the actual hash value at the end.
|
|
11
|
+
*/
|
|
5
12
|
const DIGEST_INFO_PREFIX = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
13
|
+
sha1: new Uint8Array([
|
|
14
|
+
48,
|
|
15
|
+
33,
|
|
16
|
+
48,
|
|
17
|
+
9,
|
|
18
|
+
6,
|
|
19
|
+
5,
|
|
20
|
+
43,
|
|
21
|
+
14,
|
|
22
|
+
3,
|
|
23
|
+
2,
|
|
24
|
+
26,
|
|
25
|
+
5,
|
|
26
|
+
0,
|
|
27
|
+
4,
|
|
28
|
+
20
|
|
29
|
+
]),
|
|
30
|
+
sha256: new Uint8Array([
|
|
31
|
+
48,
|
|
32
|
+
49,
|
|
33
|
+
48,
|
|
34
|
+
13,
|
|
35
|
+
6,
|
|
36
|
+
9,
|
|
37
|
+
96,
|
|
38
|
+
134,
|
|
39
|
+
72,
|
|
40
|
+
1,
|
|
41
|
+
101,
|
|
42
|
+
3,
|
|
43
|
+
4,
|
|
44
|
+
2,
|
|
45
|
+
1,
|
|
46
|
+
5,
|
|
47
|
+
0,
|
|
48
|
+
4,
|
|
49
|
+
32
|
|
50
|
+
]),
|
|
51
|
+
sha512: new Uint8Array([
|
|
52
|
+
48,
|
|
53
|
+
81,
|
|
54
|
+
48,
|
|
55
|
+
13,
|
|
56
|
+
6,
|
|
57
|
+
9,
|
|
58
|
+
96,
|
|
59
|
+
134,
|
|
60
|
+
72,
|
|
61
|
+
1,
|
|
62
|
+
101,
|
|
63
|
+
3,
|
|
64
|
+
4,
|
|
65
|
+
2,
|
|
66
|
+
3,
|
|
67
|
+
5,
|
|
68
|
+
0,
|
|
69
|
+
4,
|
|
70
|
+
64
|
|
71
|
+
])
|
|
65
72
|
};
|
|
73
|
+
/**
|
|
74
|
+
* Normalize algorithm strings like "RSA-SHA256", "SHA256", "sha256" to
|
|
75
|
+
* the canonical hash name used internally (e.g. "sha256").
|
|
76
|
+
*/
|
|
66
77
|
function normalizeSignAlgorithm(algorithm) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
let alg = algorithm.toLowerCase().replace(/-/g, "");
|
|
79
|
+
if (alg.startsWith("rsa")) {
|
|
80
|
+
alg = alg.slice(3);
|
|
81
|
+
}
|
|
82
|
+
if (!DIGEST_INFO_PREFIX[alg]) {
|
|
83
|
+
throw new Error(`Unsupported algorithm: ${algorithm}. Supported: RSA-SHA1, RSA-SHA256, RSA-SHA512`);
|
|
84
|
+
}
|
|
85
|
+
return alg;
|
|
75
86
|
}
|
|
76
87
|
function extractPem(key) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
class Sign {
|
|
91
|
-
_algorithm;
|
|
92
|
-
_hash;
|
|
93
|
-
_finalized = false;
|
|
94
|
-
constructor(algorithm) {
|
|
95
|
-
this._algorithm = normalizeSignAlgorithm(algorithm);
|
|
96
|
-
this._hash = new Hash(this._algorithm);
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Update the Sign object with the given data.
|
|
100
|
-
*/
|
|
101
|
-
update(data, inputEncoding) {
|
|
102
|
-
if (this._finalized) {
|
|
103
|
-
throw new Error("Sign was already finalized");
|
|
104
|
-
}
|
|
105
|
-
this._hash.update(data, inputEncoding);
|
|
106
|
-
return this;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Compute the signature using the private key.
|
|
110
|
-
* Returns the signature as a Buffer (or string if outputEncoding is given).
|
|
111
|
-
*/
|
|
112
|
-
sign(privateKey, outputEncoding) {
|
|
113
|
-
if (this._finalized) {
|
|
114
|
-
throw new Error("Sign was already finalized");
|
|
115
|
-
}
|
|
116
|
-
this._finalized = true;
|
|
117
|
-
const digest = this._hash.digest();
|
|
118
|
-
const pem = extractPem(privateKey);
|
|
119
|
-
const parsed = parsePemKey(pem);
|
|
120
|
-
if (parsed.type !== "rsa-private") {
|
|
121
|
-
throw new Error("privateKey must be an RSA private key");
|
|
122
|
-
}
|
|
123
|
-
const { n, e, d } = parsed.components;
|
|
124
|
-
const keyLen = rsaKeySize(n);
|
|
125
|
-
const prefix = DIGEST_INFO_PREFIX[this._algorithm];
|
|
126
|
-
const digestInfo = new Uint8Array(prefix.length + digest.length);
|
|
127
|
-
digestInfo.set(prefix, 0);
|
|
128
|
-
digestInfo.set(digest, prefix.length);
|
|
129
|
-
const padLen = keyLen - digestInfo.length - 3;
|
|
130
|
-
if (padLen < 8) {
|
|
131
|
-
throw new Error("Key is too short for the specified hash algorithm");
|
|
132
|
-
}
|
|
133
|
-
const em = new Uint8Array(keyLen);
|
|
134
|
-
em[0] = 0;
|
|
135
|
-
em[1] = 1;
|
|
136
|
-
for (let i = 2; i < 2 + padLen; i++) {
|
|
137
|
-
em[i] = 255;
|
|
138
|
-
}
|
|
139
|
-
em[2 + padLen] = 0;
|
|
140
|
-
em.set(digestInfo, 3 + padLen);
|
|
141
|
-
const m = bytesToBigInt(em);
|
|
142
|
-
const s = modPow(m, d, n);
|
|
143
|
-
const sigBytes = bigIntToBytes(s, keyLen);
|
|
144
|
-
const sigBuf = Buffer.from(sigBytes);
|
|
145
|
-
if (outputEncoding) {
|
|
146
|
-
return sigBuf.toString(outputEncoding);
|
|
147
|
-
}
|
|
148
|
-
return sigBuf;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
class Verify {
|
|
152
|
-
_algorithm;
|
|
153
|
-
_hash;
|
|
154
|
-
_finalized = false;
|
|
155
|
-
constructor(algorithm) {
|
|
156
|
-
this._algorithm = normalizeSignAlgorithm(algorithm);
|
|
157
|
-
this._hash = new Hash(this._algorithm);
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Update the Verify object with the given data.
|
|
161
|
-
*/
|
|
162
|
-
update(data, inputEncoding) {
|
|
163
|
-
if (this._finalized) {
|
|
164
|
-
throw new Error("Verify was already finalized");
|
|
165
|
-
}
|
|
166
|
-
this._hash.update(data, inputEncoding);
|
|
167
|
-
return this;
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Verify the signature against the public key.
|
|
171
|
-
* Returns true if the signature is valid, false otherwise.
|
|
172
|
-
*/
|
|
173
|
-
verify(publicKey, signature, signatureEncoding) {
|
|
174
|
-
if (this._finalized) {
|
|
175
|
-
throw new Error("Verify was already finalized");
|
|
176
|
-
}
|
|
177
|
-
this._finalized = true;
|
|
178
|
-
const digest = this._hash.digest();
|
|
179
|
-
const pem = extractPem(publicKey);
|
|
180
|
-
const parsed = parsePemKey(pem);
|
|
181
|
-
let n;
|
|
182
|
-
let e;
|
|
183
|
-
if (parsed.type === "rsa-public") {
|
|
184
|
-
n = parsed.components.n;
|
|
185
|
-
e = parsed.components.e;
|
|
186
|
-
} else if (parsed.type === "rsa-private") {
|
|
187
|
-
n = parsed.components.n;
|
|
188
|
-
e = parsed.components.e;
|
|
189
|
-
} else {
|
|
190
|
-
throw new Error("publicKey must be an RSA public or private key");
|
|
191
|
-
}
|
|
192
|
-
const keyLen = rsaKeySize(n);
|
|
193
|
-
let sigBytes;
|
|
194
|
-
if (typeof signature === "string") {
|
|
195
|
-
sigBytes = Buffer.from(signature, signatureEncoding || "base64");
|
|
196
|
-
} else {
|
|
197
|
-
sigBytes = signature instanceof Uint8Array ? signature : Buffer.from(signature);
|
|
198
|
-
}
|
|
199
|
-
if (sigBytes.length !== keyLen) {
|
|
200
|
-
return false;
|
|
201
|
-
}
|
|
202
|
-
const s = bytesToBigInt(sigBytes);
|
|
203
|
-
if (s >= n) {
|
|
204
|
-
return false;
|
|
205
|
-
}
|
|
206
|
-
const m = modPow(s, e, n);
|
|
207
|
-
const em = bigIntToBytes(m, keyLen);
|
|
208
|
-
if (em[0] !== 0 || em[1] !== 1) {
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
let sepIdx = 2;
|
|
212
|
-
while (sepIdx < em.length && em[sepIdx] === 255) {
|
|
213
|
-
sepIdx++;
|
|
214
|
-
}
|
|
215
|
-
if (sepIdx >= em.length || em[sepIdx] !== 0) {
|
|
216
|
-
return false;
|
|
217
|
-
}
|
|
218
|
-
if (sepIdx - 2 < 8) {
|
|
219
|
-
return false;
|
|
220
|
-
}
|
|
221
|
-
sepIdx++;
|
|
222
|
-
const recoveredDigestInfo = em.slice(sepIdx);
|
|
223
|
-
const prefix = DIGEST_INFO_PREFIX[this._algorithm];
|
|
224
|
-
const expectedDigestInfo = new Uint8Array(prefix.length + digest.length);
|
|
225
|
-
expectedDigestInfo.set(prefix, 0);
|
|
226
|
-
expectedDigestInfo.set(digest, prefix.length);
|
|
227
|
-
if (recoveredDigestInfo.length !== expectedDigestInfo.length) {
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
|
-
let diff = 0;
|
|
231
|
-
for (let i = 0; i < recoveredDigestInfo.length; i++) {
|
|
232
|
-
diff |= recoveredDigestInfo[i] ^ expectedDigestInfo[i];
|
|
233
|
-
}
|
|
234
|
-
return diff === 0;
|
|
235
|
-
}
|
|
88
|
+
if (typeof key === "string") {
|
|
89
|
+
return key;
|
|
90
|
+
}
|
|
91
|
+
if (Buffer.isBuffer(key) || key instanceof Uint8Array) {
|
|
92
|
+
return Buffer.from(key).toString("utf8");
|
|
93
|
+
}
|
|
94
|
+
if (key && typeof key === "object" && "key" in key) {
|
|
95
|
+
const k = key.key;
|
|
96
|
+
if (typeof k === "string") return k;
|
|
97
|
+
if (Buffer.isBuffer(k) || k instanceof Uint8Array) return Buffer.from(k).toString("utf8");
|
|
98
|
+
}
|
|
99
|
+
throw new TypeError("Invalid key argument");
|
|
236
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* The Sign class generates RSA PKCS#1 v1.5 signatures.
|
|
103
|
+
*
|
|
104
|
+
* Usage:
|
|
105
|
+
* const sign = createSign('RSA-SHA256');
|
|
106
|
+
* sign.update('data');
|
|
107
|
+
* const signature = sign.sign(privateKey);
|
|
108
|
+
*/
|
|
109
|
+
var Sign = class {
|
|
110
|
+
_algorithm;
|
|
111
|
+
_hash;
|
|
112
|
+
_finalized = false;
|
|
113
|
+
constructor(algorithm) {
|
|
114
|
+
this._algorithm = normalizeSignAlgorithm(algorithm);
|
|
115
|
+
this._hash = new Hash(this._algorithm);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Update the Sign object with the given data.
|
|
119
|
+
*/
|
|
120
|
+
update(data, inputEncoding) {
|
|
121
|
+
if (this._finalized) {
|
|
122
|
+
throw new Error("Sign was already finalized");
|
|
123
|
+
}
|
|
124
|
+
this._hash.update(data, inputEncoding);
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Compute the signature using the private key.
|
|
129
|
+
* Returns the signature as a Buffer (or string if outputEncoding is given).
|
|
130
|
+
*/
|
|
131
|
+
sign(privateKey, outputEncoding) {
|
|
132
|
+
if (this._finalized) {
|
|
133
|
+
throw new Error("Sign was already finalized");
|
|
134
|
+
}
|
|
135
|
+
this._finalized = true;
|
|
136
|
+
const digest = this._hash.digest();
|
|
137
|
+
const pem = extractPem(privateKey);
|
|
138
|
+
const parsed = parsePemKey(pem);
|
|
139
|
+
if (parsed.type !== "rsa-private") {
|
|
140
|
+
throw new Error("privateKey must be an RSA private key");
|
|
141
|
+
}
|
|
142
|
+
const { n, e, d } = parsed.components;
|
|
143
|
+
const keyLen = rsaKeySize(n);
|
|
144
|
+
const prefix = DIGEST_INFO_PREFIX[this._algorithm];
|
|
145
|
+
const digestInfo = new Uint8Array(prefix.length + digest.length);
|
|
146
|
+
digestInfo.set(prefix, 0);
|
|
147
|
+
digestInfo.set(digest, prefix.length);
|
|
148
|
+
const padLen = keyLen - digestInfo.length - 3;
|
|
149
|
+
if (padLen < 8) {
|
|
150
|
+
throw new Error("Key is too short for the specified hash algorithm");
|
|
151
|
+
}
|
|
152
|
+
const em = new Uint8Array(keyLen);
|
|
153
|
+
em[0] = 0;
|
|
154
|
+
em[1] = 1;
|
|
155
|
+
for (let i = 2; i < 2 + padLen; i++) {
|
|
156
|
+
em[i] = 255;
|
|
157
|
+
}
|
|
158
|
+
em[2 + padLen] = 0;
|
|
159
|
+
em.set(digestInfo, 3 + padLen);
|
|
160
|
+
const m = bytesToBigInt(em);
|
|
161
|
+
const s = modPow(m, d, n);
|
|
162
|
+
const sigBytes = bigIntToBytes(s, keyLen);
|
|
163
|
+
const sigBuf = Buffer.from(sigBytes);
|
|
164
|
+
if (outputEncoding) {
|
|
165
|
+
return sigBuf.toString(outputEncoding);
|
|
166
|
+
}
|
|
167
|
+
return sigBuf;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* The Verify class verifies RSA PKCS#1 v1.5 signatures.
|
|
172
|
+
*
|
|
173
|
+
* Usage:
|
|
174
|
+
* const verify = createVerify('RSA-SHA256');
|
|
175
|
+
* verify.update('data');
|
|
176
|
+
* const ok = verify.verify(publicKey, signature);
|
|
177
|
+
*/
|
|
178
|
+
var Verify = class {
|
|
179
|
+
_algorithm;
|
|
180
|
+
_hash;
|
|
181
|
+
_finalized = false;
|
|
182
|
+
constructor(algorithm) {
|
|
183
|
+
this._algorithm = normalizeSignAlgorithm(algorithm);
|
|
184
|
+
this._hash = new Hash(this._algorithm);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Update the Verify object with the given data.
|
|
188
|
+
*/
|
|
189
|
+
update(data, inputEncoding) {
|
|
190
|
+
if (this._finalized) {
|
|
191
|
+
throw new Error("Verify was already finalized");
|
|
192
|
+
}
|
|
193
|
+
this._hash.update(data, inputEncoding);
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Verify the signature against the public key.
|
|
198
|
+
* Returns true if the signature is valid, false otherwise.
|
|
199
|
+
*/
|
|
200
|
+
verify(publicKey, signature, signatureEncoding) {
|
|
201
|
+
if (this._finalized) {
|
|
202
|
+
throw new Error("Verify was already finalized");
|
|
203
|
+
}
|
|
204
|
+
this._finalized = true;
|
|
205
|
+
const digest = this._hash.digest();
|
|
206
|
+
const pem = extractPem(publicKey);
|
|
207
|
+
const parsed = parsePemKey(pem);
|
|
208
|
+
let n;
|
|
209
|
+
let e;
|
|
210
|
+
if (parsed.type === "rsa-public") {
|
|
211
|
+
n = parsed.components.n;
|
|
212
|
+
e = parsed.components.e;
|
|
213
|
+
} else if (parsed.type === "rsa-private") {
|
|
214
|
+
n = parsed.components.n;
|
|
215
|
+
e = parsed.components.e;
|
|
216
|
+
} else {
|
|
217
|
+
throw new Error("publicKey must be an RSA public or private key");
|
|
218
|
+
}
|
|
219
|
+
const keyLen = rsaKeySize(n);
|
|
220
|
+
let sigBytes;
|
|
221
|
+
if (typeof signature === "string") {
|
|
222
|
+
sigBytes = Buffer.from(signature, signatureEncoding || "base64");
|
|
223
|
+
} else {
|
|
224
|
+
sigBytes = signature instanceof Uint8Array ? signature : Buffer.from(signature);
|
|
225
|
+
}
|
|
226
|
+
if (sigBytes.length !== keyLen) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
const s = bytesToBigInt(sigBytes);
|
|
230
|
+
if (s >= n) {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
const m = modPow(s, e, n);
|
|
234
|
+
const em = bigIntToBytes(m, keyLen);
|
|
235
|
+
if (em[0] !== 0 || em[1] !== 1) {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
let sepIdx = 2;
|
|
239
|
+
while (sepIdx < em.length && em[sepIdx] === 255) {
|
|
240
|
+
sepIdx++;
|
|
241
|
+
}
|
|
242
|
+
if (sepIdx >= em.length || em[sepIdx] !== 0) {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
if (sepIdx - 2 < 8) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
sepIdx++;
|
|
249
|
+
const recoveredDigestInfo = em.slice(sepIdx);
|
|
250
|
+
const prefix = DIGEST_INFO_PREFIX[this._algorithm];
|
|
251
|
+
const expectedDigestInfo = new Uint8Array(prefix.length + digest.length);
|
|
252
|
+
expectedDigestInfo.set(prefix, 0);
|
|
253
|
+
expectedDigestInfo.set(digest, prefix.length);
|
|
254
|
+
if (recoveredDigestInfo.length !== expectedDigestInfo.length) {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
let diff = 0;
|
|
258
|
+
for (let i = 0; i < recoveredDigestInfo.length; i++) {
|
|
259
|
+
diff |= recoveredDigestInfo[i] ^ expectedDigestInfo[i];
|
|
260
|
+
}
|
|
261
|
+
return diff === 0;
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
/**
|
|
265
|
+
* Create and return a Sign object for the given algorithm.
|
|
266
|
+
*/
|
|
237
267
|
function createSign(algorithm) {
|
|
238
|
-
|
|
268
|
+
return new Sign(algorithm);
|
|
239
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* Create and return a Verify object for the given algorithm.
|
|
272
|
+
*/
|
|
240
273
|
function createVerify(algorithm) {
|
|
241
|
-
|
|
274
|
+
return new Verify(algorithm);
|
|
242
275
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
createSign,
|
|
247
|
-
createVerify
|
|
248
|
-
};
|
|
276
|
+
|
|
277
|
+
//#endregion
|
|
278
|
+
export { Sign, Verify, createSign, createVerify };
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
+
//#region src/timing-safe-equal.ts
|
|
2
|
+
/**
|
|
3
|
+
* Compare two buffers in constant time to prevent timing attacks.
|
|
4
|
+
* Both buffers must have the same length.
|
|
5
|
+
*/
|
|
1
6
|
function timingSafeEqual(a, b) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
if (a.length !== b.length) {
|
|
8
|
+
throw new RangeError("Input buffers must have the same byte length");
|
|
9
|
+
}
|
|
10
|
+
let result = 0;
|
|
11
|
+
for (let i = 0; i < a.length; i++) {
|
|
12
|
+
result |= a[i] ^ b[i];
|
|
13
|
+
}
|
|
14
|
+
return result === 0;
|
|
10
15
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
};
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { timingSafeEqual };
|