react-native-quick-crypto 1.1.1 → 1.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/QuickCrypto.podspec +1 -0
- package/android/CMakeLists.txt +4 -0
- package/cpp/cipher/CCMCipher.cpp +7 -11
- package/cpp/cipher/ChaCha20Cipher.cpp +6 -10
- package/cpp/cipher/ChaCha20Poly1305Cipher.cpp +10 -16
- package/cpp/cipher/GCMCipher.cpp +3 -5
- package/cpp/cipher/HybridCipher.cpp +7 -13
- package/cpp/cipher/HybridRsaCipher.cpp +19 -27
- package/cpp/cipher/OCBCipher.cpp +2 -3
- package/cpp/cipher/XChaCha20Poly1305Cipher.cpp +13 -19
- package/cpp/cipher/XSalsa20Cipher.cpp +8 -12
- package/cpp/cipher/XSalsa20Poly1305Cipher.cpp +11 -16
- package/cpp/keys/HybridKeyObjectHandle.cpp +630 -2
- package/cpp/keys/HybridKeyObjectHandle.hpp +21 -1
- package/cpp/sign/HybridSignHandle.cpp +26 -8
- package/cpp/sign/HybridVerifyHandle.cpp +28 -11
- package/cpp/slhdsa/HybridSlhDsaKeyPair.cpp +245 -0
- package/cpp/slhdsa/HybridSlhDsaKeyPair.hpp +48 -0
- package/cpp/turboshake/HybridTurboShake.cpp +379 -0
- package/cpp/turboshake/HybridTurboShake.hpp +28 -0
- package/cpp/utils/HybridUtils.cpp +83 -21
- package/cpp/utils/HybridUtils.hpp +4 -0
- package/deps/blake3/README.md +6 -7
- package/deps/blake3/c/blake3.c +3 -2
- package/deps/blake3/c/blake3.h +2 -2
- package/deps/blake3/c/blake3_dispatch.c +2 -2
- package/deps/blake3/c/blake3_impl.h +1 -1
- package/deps/blake3/c/blake3_neon.c +5 -4
- package/deps/ncrypto/include/ncrypto/version.h +2 -2
- package/deps/ncrypto/include/ncrypto.h +9 -2
- package/deps/ncrypto/src/ncrypto.cpp +130 -35
- package/lib/commonjs/dhKeyPair.js +3 -0
- package/lib/commonjs/dhKeyPair.js.map +1 -1
- package/lib/commonjs/dsa.js +3 -0
- package/lib/commonjs/dsa.js.map +1 -1
- package/lib/commonjs/ec.js +37 -30
- package/lib/commonjs/ec.js.map +1 -1
- package/lib/commonjs/ed.js +60 -6
- package/lib/commonjs/ed.js.map +1 -1
- package/lib/commonjs/expo-plugin/withXCode.js +3 -3
- package/lib/commonjs/hash.js +52 -5
- package/lib/commonjs/hash.js.map +1 -1
- package/lib/commonjs/keys/classes.js +33 -7
- package/lib/commonjs/keys/classes.js.map +1 -1
- package/lib/commonjs/keys/generateKeyPair.js +85 -4
- package/lib/commonjs/keys/generateKeyPair.js.map +1 -1
- package/lib/commonjs/keys/index.js +50 -2
- package/lib/commonjs/keys/index.js.map +1 -1
- package/lib/commonjs/keys/signVerify.js +9 -2
- package/lib/commonjs/keys/signVerify.js.map +1 -1
- package/lib/commonjs/keys/utils.js +59 -1
- package/lib/commonjs/keys/utils.js.map +1 -1
- package/lib/commonjs/random.js +63 -9
- package/lib/commonjs/random.js.map +1 -1
- package/lib/commonjs/rsa.js +3 -0
- package/lib/commonjs/rsa.js.map +1 -1
- package/lib/commonjs/slhdsa.js +70 -0
- package/lib/commonjs/slhdsa.js.map +1 -0
- package/lib/commonjs/specs/slhDsaKeyPair.nitro.js +6 -0
- package/lib/commonjs/specs/slhDsaKeyPair.nitro.js.map +1 -0
- package/lib/commonjs/specs/turboshake.nitro.js +6 -0
- package/lib/commonjs/specs/turboshake.nitro.js.map +1 -0
- package/lib/commonjs/subtle.js +926 -275
- package/lib/commonjs/subtle.js.map +1 -1
- package/lib/commonjs/utils/conversion.js +61 -25
- package/lib/commonjs/utils/conversion.js.map +1 -1
- package/lib/commonjs/utils/errors.js +63 -4
- package/lib/commonjs/utils/errors.js.map +1 -1
- package/lib/commonjs/utils/types.js.map +1 -1
- package/lib/commonjs/utils/validation.js +46 -0
- package/lib/commonjs/utils/validation.js.map +1 -1
- package/lib/module/dhKeyPair.js +3 -0
- package/lib/module/dhKeyPair.js.map +1 -1
- package/lib/module/dsa.js +3 -0
- package/lib/module/dsa.js.map +1 -1
- package/lib/module/ec.js +38 -31
- package/lib/module/ec.js.map +1 -1
- package/lib/module/ed.js +61 -7
- package/lib/module/ed.js.map +1 -1
- package/lib/module/expo-plugin/withXCode.js +3 -3
- package/lib/module/hash.js +52 -5
- package/lib/module/hash.js.map +1 -1
- package/lib/module/keys/classes.js +31 -5
- package/lib/module/keys/classes.js.map +1 -1
- package/lib/module/keys/generateKeyPair.js +86 -5
- package/lib/module/keys/generateKeyPair.js.map +1 -1
- package/lib/module/keys/index.js +50 -2
- package/lib/module/keys/index.js.map +1 -1
- package/lib/module/keys/signVerify.js +9 -2
- package/lib/module/keys/signVerify.js.map +1 -1
- package/lib/module/keys/utils.js +57 -1
- package/lib/module/keys/utils.js.map +1 -1
- package/lib/module/random.js +63 -10
- package/lib/module/random.js.map +1 -1
- package/lib/module/rsa.js +3 -0
- package/lib/module/rsa.js.map +1 -1
- package/lib/module/slhdsa.js +64 -0
- package/lib/module/slhdsa.js.map +1 -0
- package/lib/module/specs/slhDsaKeyPair.nitro.js +4 -0
- package/lib/module/specs/slhDsaKeyPair.nitro.js.map +1 -0
- package/lib/module/specs/turboshake.nitro.js +4 -0
- package/lib/module/specs/turboshake.nitro.js.map +1 -0
- package/lib/module/subtle.js +927 -276
- package/lib/module/subtle.js.map +1 -1
- package/lib/module/utils/conversion.js +59 -25
- package/lib/module/utils/conversion.js.map +1 -1
- package/lib/module/utils/errors.js +61 -4
- package/lib/module/utils/errors.js.map +1 -1
- package/lib/module/utils/types.js.map +1 -1
- package/lib/module/utils/validation.js +44 -0
- package/lib/module/utils/validation.js.map +1 -1
- package/lib/typescript/dhKeyPair.d.ts.map +1 -1
- package/lib/typescript/dsa.d.ts.map +1 -1
- package/lib/typescript/ec.d.ts.map +1 -1
- package/lib/typescript/ed.d.ts.map +1 -1
- package/lib/typescript/hash.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +12 -7
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/keys/classes.d.ts +10 -1
- package/lib/typescript/keys/classes.d.ts.map +1 -1
- package/lib/typescript/keys/generateKeyPair.d.ts +12 -1
- package/lib/typescript/keys/generateKeyPair.d.ts.map +1 -1
- package/lib/typescript/keys/index.d.ts +3 -1
- package/lib/typescript/keys/index.d.ts.map +1 -1
- package/lib/typescript/keys/signVerify.d.ts.map +1 -1
- package/lib/typescript/keys/utils.d.ts +21 -4
- package/lib/typescript/keys/utils.d.ts.map +1 -1
- package/lib/typescript/random.d.ts +5 -1
- package/lib/typescript/random.d.ts.map +1 -1
- package/lib/typescript/rsa.d.ts.map +1 -1
- package/lib/typescript/slhdsa.d.ts +19 -0
- package/lib/typescript/slhdsa.d.ts.map +1 -0
- package/lib/typescript/specs/keyObjectHandle.nitro.d.ts +9 -0
- package/lib/typescript/specs/keyObjectHandle.nitro.d.ts.map +1 -1
- package/lib/typescript/specs/slhDsaKeyPair.nitro.d.ts +16 -0
- package/lib/typescript/specs/slhDsaKeyPair.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/turboshake.nitro.d.ts +11 -0
- package/lib/typescript/specs/turboshake.nitro.d.ts.map +1 -0
- package/lib/typescript/subtle.d.ts +3 -2
- package/lib/typescript/subtle.d.ts.map +1 -1
- package/lib/typescript/utils/conversion.d.ts +9 -6
- package/lib/typescript/utils/conversion.d.ts.map +1 -1
- package/lib/typescript/utils/errors.d.ts +12 -0
- package/lib/typescript/utils/errors.d.ts.map +1 -1
- package/lib/typescript/utils/types.d.ts +32 -15
- package/lib/typescript/utils/types.d.ts.map +1 -1
- package/lib/typescript/utils/validation.d.ts +3 -1
- package/lib/typescript/utils/validation.d.ts.map +1 -1
- package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +2 -0
- package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +20 -0
- package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +20 -0
- package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +48 -0
- package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp +9 -0
- package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp +9 -0
- package/nitrogen/generated/shared/c++/HybridSlhDsaKeyPairSpec.cpp +29 -0
- package/nitrogen/generated/shared/c++/HybridSlhDsaKeyPairSpec.hpp +72 -0
- package/nitrogen/generated/shared/c++/HybridTurboShakeSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridTurboShakeSpec.hpp +70 -0
- package/nitrogen/generated/shared/c++/JWK.hpp +9 -1
- package/nitrogen/generated/shared/c++/JWKkty.hpp +4 -0
- package/nitrogen/generated/shared/c++/KangarooTwelveVariant.hpp +76 -0
- package/nitrogen/generated/shared/c++/TurboShakeVariant.hpp +76 -0
- package/package.json +4 -5
- package/src/dhKeyPair.ts +8 -0
- package/src/dsa.ts +8 -0
- package/src/ec.ts +52 -29
- package/src/ed.ts +95 -16
- package/src/expo-plugin/withXCode.ts +3 -3
- package/src/hash.ts +108 -5
- package/src/keys/classes.ts +46 -5
- package/src/keys/generateKeyPair.ts +151 -5
- package/src/keys/index.ts +73 -3
- package/src/keys/signVerify.ts +13 -2
- package/src/keys/utils.ts +78 -5
- package/src/random.ts +93 -9
- package/src/rsa.ts +8 -0
- package/src/slhdsa.ts +146 -0
- package/src/specs/keyObjectHandle.nitro.ts +17 -0
- package/src/specs/slhDsaKeyPair.nitro.ts +29 -0
- package/src/specs/turboshake.nitro.ts +21 -0
- package/src/subtle.ts +1191 -360
- package/src/utils/conversion.ts +80 -27
- package/src/utils/errors.ts +72 -4
- package/src/utils/types.ts +80 -15
- package/src/utils/validation.ts +70 -1
package/src/utils/conversion.ts
CHANGED
|
@@ -6,7 +6,12 @@ import type { ABV, BinaryLikeNode, BufferLike } from './types';
|
|
|
6
6
|
import { Platform } from 'react-native';
|
|
7
7
|
|
|
8
8
|
type UtilsWithStringConverter = Utils & {
|
|
9
|
-
bufferToString(
|
|
9
|
+
bufferToString(
|
|
10
|
+
buffer: ArrayBuffer,
|
|
11
|
+
encoding: string,
|
|
12
|
+
start?: number,
|
|
13
|
+
end?: number,
|
|
14
|
+
): string;
|
|
10
15
|
stringToBuffer(str: string, encoding: string): ArrayBuffer;
|
|
11
16
|
};
|
|
12
17
|
|
|
@@ -52,6 +57,34 @@ if (isHermes) {
|
|
|
52
57
|
}
|
|
53
58
|
}
|
|
54
59
|
|
|
60
|
+
// WebCrypto / Web IDL §BufferSource: SharedArrayBuffer-backed inputs must
|
|
61
|
+
// be rejected. Concurrent writes from another worker during async crypto
|
|
62
|
+
// can corrupt computations or leak intermediate state, so even copying
|
|
63
|
+
// the source isn't safe (the copy itself races). Reject at conversion.
|
|
64
|
+
// See Node's `lib/internal/webidl.js` BufferSource converter (commit
|
|
65
|
+
// bee10872588) — it throws TypeError, matching the WebIDL spec.
|
|
66
|
+
//
|
|
67
|
+
// We apply this guard to *every* conversion helper, not just the ones
|
|
68
|
+
// reached from `subtle.*`. That's deliberately stricter than Node, whose
|
|
69
|
+
// classic APIs (`createHash().update`, `createHmac().update`,
|
|
70
|
+
// `createCipheriv().update`, etc.) accept SAB-backed views. The TOCTOU
|
|
71
|
+
// concern is the same on either side of the WebCrypto / classic line, so
|
|
72
|
+
// we prefer the safer default everywhere.
|
|
73
|
+
export function rejectSharedArrayBuffer(buf: unknown): void {
|
|
74
|
+
if (typeof SharedArrayBuffer === 'undefined') return;
|
|
75
|
+
if (buf instanceof SharedArrayBuffer) {
|
|
76
|
+
throw new TypeError('SharedArrayBuffer is not a supported BufferSource');
|
|
77
|
+
}
|
|
78
|
+
if (
|
|
79
|
+
ArrayBuffer.isView(buf) &&
|
|
80
|
+
(buf as ArrayBufferView).buffer instanceof SharedArrayBuffer
|
|
81
|
+
) {
|
|
82
|
+
throw new TypeError(
|
|
83
|
+
'View on a SharedArrayBuffer is not a supported BufferSource',
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
55
88
|
/**
|
|
56
89
|
* Returns the underlying ArrayBuffer of a Buffer / TypedArray view **without
|
|
57
90
|
* copying**, ignoring `byteOffset`/`byteLength`. The full backing storage is
|
|
@@ -60,10 +93,11 @@ if (isHermes) {
|
|
|
60
93
|
* Only use this when the caller separately tracks `byteOffset`/`byteLength`
|
|
61
94
|
* and the native receiver needs to write back into the original memory
|
|
62
95
|
* (e.g. `randomFill`). For data that will be read by native crypto, use
|
|
63
|
-
* `binaryLikeToArrayBuffer`/`toArrayBuffer` instead — those
|
|
96
|
+
* `binaryLikeToArrayBuffer`/`toArrayBuffer` instead — those return only the
|
|
64
97
|
* view's region and won't leak unrelated bytes from the backing buffer.
|
|
65
98
|
*/
|
|
66
99
|
export const abvToArrayBuffer = (buf: ABV) => {
|
|
100
|
+
rejectSharedArrayBuffer(buf);
|
|
67
101
|
if (CraftzdogBuffer.isBuffer(buf)) {
|
|
68
102
|
return buf.buffer as ArrayBuffer;
|
|
69
103
|
}
|
|
@@ -74,8 +108,10 @@ export const abvToArrayBuffer = (buf: ABV) => {
|
|
|
74
108
|
};
|
|
75
109
|
|
|
76
110
|
/**
|
|
77
|
-
* Converts supplied argument to an ArrayBuffer.
|
|
78
|
-
*
|
|
111
|
+
* Converts supplied argument to an ArrayBuffer. Note this copies data
|
|
112
|
+
* only when the supplied view represents a subrange of the underlying
|
|
113
|
+
* ArrayBuffer; otherwise the backing buffer is returned directly
|
|
114
|
+
* (aliased — do not mutate after passing).
|
|
79
115
|
* @param buf
|
|
80
116
|
* @returns ArrayBuffer
|
|
81
117
|
*/
|
|
@@ -83,13 +119,13 @@ export function toArrayBuffer(
|
|
|
83
119
|
buf: CraftzdogBuffer | SafeBuffer | ArrayBufferView,
|
|
84
120
|
): ArrayBuffer {
|
|
85
121
|
if (CraftzdogBuffer.isBuffer(buf) || ArrayBuffer.isView(buf)) {
|
|
86
|
-
if (buf
|
|
122
|
+
if (buf.byteOffset === 0 && buf.byteLength === buf.buffer.byteLength) {
|
|
123
|
+
return buf.buffer as ArrayBuffer;
|
|
124
|
+
} else {
|
|
87
125
|
return buf.buffer.slice(
|
|
88
126
|
buf.byteOffset,
|
|
89
127
|
buf.byteOffset + buf.byteLength,
|
|
90
128
|
) as ArrayBuffer;
|
|
91
|
-
} else {
|
|
92
|
-
return buf.buffer as ArrayBuffer;
|
|
93
129
|
}
|
|
94
130
|
}
|
|
95
131
|
const ab = new ArrayBuffer(buf.length);
|
|
@@ -101,6 +137,8 @@ export function toArrayBuffer(
|
|
|
101
137
|
}
|
|
102
138
|
|
|
103
139
|
export function bufferLikeToArrayBuffer(buf: BufferLike): ArrayBuffer {
|
|
140
|
+
rejectSharedArrayBuffer(buf);
|
|
141
|
+
|
|
104
142
|
// Buffer
|
|
105
143
|
if (CraftzdogBuffer.isBuffer(buf) || SafeBuffer.isBuffer(buf)) {
|
|
106
144
|
return toArrayBuffer(buf);
|
|
@@ -115,22 +153,8 @@ export function bufferLikeToArrayBuffer(buf: BufferLike): ArrayBuffer {
|
|
|
115
153
|
return buf;
|
|
116
154
|
}
|
|
117
155
|
|
|
118
|
-
// If buf is a SharedArrayBuffer, convert it to ArrayBuffer.
|
|
119
|
-
// This typically involves a copy of the data.
|
|
120
|
-
if (
|
|
121
|
-
typeof SharedArrayBuffer !== 'undefined' &&
|
|
122
|
-
buf instanceof SharedArrayBuffer
|
|
123
|
-
) {
|
|
124
|
-
const arrayBuffer = new ArrayBuffer(buf.byteLength);
|
|
125
|
-
new Uint8Array(arrayBuffer).set(new Uint8Array(buf));
|
|
126
|
-
return arrayBuffer;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// If we reach here, 'buf' is of a type within BufferLike that has not been handled by the above checks.
|
|
130
|
-
// This indicates either an incomplete BufferLike definition or an unexpected input type.
|
|
131
|
-
// Throw an error to signal this, ensuring the function's contract (return ArrayBuffer or throw) is met.
|
|
132
156
|
throw new TypeError(
|
|
133
|
-
'Input must be a Buffer, ArrayBufferView,
|
|
157
|
+
'Input must be a Buffer, ArrayBufferView, or ArrayBuffer.',
|
|
134
158
|
);
|
|
135
159
|
}
|
|
136
160
|
|
|
@@ -138,6 +162,8 @@ export function binaryLikeToArrayBuffer(
|
|
|
138
162
|
input: BinaryLikeNode, // CipherKey adds compat with node types
|
|
139
163
|
encoding: string = 'utf-8',
|
|
140
164
|
): ArrayBuffer {
|
|
165
|
+
rejectSharedArrayBuffer(input);
|
|
166
|
+
|
|
141
167
|
// string
|
|
142
168
|
if (typeof input === 'string') {
|
|
143
169
|
if (encoding === 'buffer') {
|
|
@@ -204,19 +230,46 @@ export function binaryLikeToArrayBuffer(
|
|
|
204
230
|
);
|
|
205
231
|
}
|
|
206
232
|
|
|
207
|
-
export function ab2str(
|
|
233
|
+
export function ab2str(
|
|
234
|
+
buf: ArrayBuffer,
|
|
235
|
+
encoding: string = 'hex',
|
|
236
|
+
start?: number,
|
|
237
|
+
end?: number,
|
|
238
|
+
): string {
|
|
208
239
|
if (nativeBufferToStringEncodings.has(encoding)) {
|
|
209
|
-
return
|
|
240
|
+
return bufferToString(buf, encoding, start, end);
|
|
210
241
|
}
|
|
211
|
-
|
|
242
|
+
|
|
243
|
+
return CraftzdogBuffer.from(buf).toString(encoding, start, end);
|
|
212
244
|
}
|
|
213
245
|
|
|
214
|
-
/** Native C++ buffer-to-string
|
|
246
|
+
/** Native C++ buffer-to-string with arguments normalization*/
|
|
215
247
|
export function bufferToString(
|
|
216
248
|
buf: ArrayBuffer,
|
|
217
249
|
encoding: string = 'hex',
|
|
250
|
+
start?: number,
|
|
251
|
+
end?: number,
|
|
218
252
|
): string {
|
|
219
|
-
|
|
253
|
+
// https://github.com/nodejs/node/blob/v24.15.0/lib/buffer.js#L915-L928
|
|
254
|
+
if (start === undefined || start < 0) {
|
|
255
|
+
start = 0;
|
|
256
|
+
} else if (start >= buf.byteLength) {
|
|
257
|
+
return '';
|
|
258
|
+
} else {
|
|
259
|
+
start = Math.trunc(start) || 0;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (end === undefined || end > buf.byteLength) {
|
|
263
|
+
end = buf.byteLength;
|
|
264
|
+
} else {
|
|
265
|
+
end = Math.trunc(end) || 0;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (end <= start) {
|
|
269
|
+
return '';
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return utils.bufferToString(buf, encoding, start, end);
|
|
220
273
|
}
|
|
221
274
|
|
|
222
275
|
/** Native C++ string-to-buffer — exposed for benchmarking */
|
package/src/utils/errors.ts
CHANGED
|
@@ -5,11 +5,79 @@ type DOMName =
|
|
|
5
5
|
cause: unknown;
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
+
// Hermes (React Native) does not implement DOMException natively. Use it when
|
|
9
|
+
// the host provides one; otherwise fall back to an Error subclass that exposes
|
|
10
|
+
// the WebCrypto-relevant surface (.name, .message, .code) so consumers that
|
|
11
|
+
// branch on `err.name === 'InvalidAccessError'` see the spec-correct value.
|
|
12
|
+
const DOM_EXCEPTION_CODES: Record<string, number> = {
|
|
13
|
+
IndexSizeError: 1,
|
|
14
|
+
HierarchyRequestError: 3,
|
|
15
|
+
WrongDocumentError: 4,
|
|
16
|
+
InvalidCharacterError: 5,
|
|
17
|
+
NoModificationAllowedError: 7,
|
|
18
|
+
NotFoundError: 8,
|
|
19
|
+
NotSupportedError: 9,
|
|
20
|
+
InUseAttributeError: 10,
|
|
21
|
+
InvalidStateError: 11,
|
|
22
|
+
SyntaxError: 12,
|
|
23
|
+
InvalidModificationError: 13,
|
|
24
|
+
NamespaceError: 14,
|
|
25
|
+
InvalidAccessError: 15,
|
|
26
|
+
TypeMismatchError: 17,
|
|
27
|
+
SecurityError: 18,
|
|
28
|
+
NetworkError: 19,
|
|
29
|
+
AbortError: 20,
|
|
30
|
+
URLMismatchError: 21,
|
|
31
|
+
QuotaExceededError: 22,
|
|
32
|
+
TimeoutError: 23,
|
|
33
|
+
InvalidNodeTypeError: 24,
|
|
34
|
+
DataCloneError: 25,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const HostDOMException: typeof globalThis.DOMException | undefined = (
|
|
38
|
+
globalThis as { DOMException?: typeof globalThis.DOMException }
|
|
39
|
+
).DOMException;
|
|
40
|
+
|
|
41
|
+
class FallbackDOMException extends Error {
|
|
42
|
+
readonly code: number;
|
|
43
|
+
constructor(message: string, name: string) {
|
|
44
|
+
super(message);
|
|
45
|
+
this.name = name;
|
|
46
|
+
this.code = DOM_EXCEPTION_CODES[name] ?? 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
8
50
|
export function lazyDOMException(message: string, domName: DOMName): Error {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
51
|
+
const name = typeof domName === 'string' ? domName : domName.name;
|
|
52
|
+
const cause = typeof domName === 'string' ? undefined : domName.cause;
|
|
53
|
+
|
|
54
|
+
let err: Error;
|
|
55
|
+
if (HostDOMException) {
|
|
56
|
+
err =
|
|
57
|
+
cause !== undefined
|
|
58
|
+
? new HostDOMException(message, { name, cause } as never)
|
|
59
|
+
: new HostDOMException(message, name);
|
|
60
|
+
} else {
|
|
61
|
+
err = new FallbackDOMException(message, name);
|
|
62
|
+
if (cause !== undefined) {
|
|
63
|
+
(err as Error & { cause?: unknown }).cause = cause;
|
|
64
|
+
}
|
|
12
65
|
}
|
|
66
|
+
return err;
|
|
67
|
+
}
|
|
13
68
|
|
|
14
|
-
|
|
69
|
+
// QuotaExceededError carries `quota` and `requested` numeric fields per the
|
|
70
|
+
// WebIDL spec (https://webidl.spec.whatwg.org/#quotaexceedederror). DOMException
|
|
71
|
+
// in legacy hosts does not expose these, so always use our subclass.
|
|
72
|
+
export class QuotaExceededError extends FallbackDOMException {
|
|
73
|
+
readonly quota: number | null;
|
|
74
|
+
readonly requested: number | null;
|
|
75
|
+
constructor(
|
|
76
|
+
message: string,
|
|
77
|
+
options: { quota?: number; requested?: number } = {},
|
|
78
|
+
) {
|
|
79
|
+
super(message, 'QuotaExceededError');
|
|
80
|
+
this.quota = options.quota ?? null;
|
|
81
|
+
this.requested = options.requested ?? null;
|
|
82
|
+
}
|
|
15
83
|
}
|
package/src/utils/types.ts
CHANGED
|
@@ -49,7 +49,11 @@ export type DigestAlgorithm =
|
|
|
49
49
|
| 'SHA3-384'
|
|
50
50
|
| 'SHA3-512'
|
|
51
51
|
| 'cSHAKE128'
|
|
52
|
-
| 'cSHAKE256'
|
|
52
|
+
| 'cSHAKE256'
|
|
53
|
+
| 'TurboSHAKE128'
|
|
54
|
+
| 'TurboSHAKE256'
|
|
55
|
+
| 'KT128'
|
|
56
|
+
| 'KT256';
|
|
53
57
|
|
|
54
58
|
export type HashAlgorithm = DigestAlgorithm | 'SHA-224' | 'RIPEMD-160';
|
|
55
59
|
|
|
@@ -74,20 +78,50 @@ export type ECKeyPairAlgorithm = 'ECDSA' | 'ECDH';
|
|
|
74
78
|
export type CFRGKeyPairAlgorithm = 'Ed25519' | 'Ed448' | 'X25519' | 'X448';
|
|
75
79
|
export type CFRGKeyPairType = 'ed25519' | 'ed448' | 'x25519' | 'x448';
|
|
76
80
|
|
|
81
|
+
export type SlhDsaAlgorithm =
|
|
82
|
+
| 'SLH-DSA-SHA2-128s'
|
|
83
|
+
| 'SLH-DSA-SHA2-128f'
|
|
84
|
+
| 'SLH-DSA-SHA2-192s'
|
|
85
|
+
| 'SLH-DSA-SHA2-192f'
|
|
86
|
+
| 'SLH-DSA-SHA2-256s'
|
|
87
|
+
| 'SLH-DSA-SHA2-256f'
|
|
88
|
+
| 'SLH-DSA-SHAKE-128s'
|
|
89
|
+
| 'SLH-DSA-SHAKE-128f'
|
|
90
|
+
| 'SLH-DSA-SHAKE-192s'
|
|
91
|
+
| 'SLH-DSA-SHAKE-192f'
|
|
92
|
+
| 'SLH-DSA-SHAKE-256s'
|
|
93
|
+
| 'SLH-DSA-SHAKE-256f';
|
|
94
|
+
|
|
95
|
+
export type SlhDsaKeyPairType =
|
|
96
|
+
| 'slh-dsa-sha2-128s'
|
|
97
|
+
| 'slh-dsa-sha2-128f'
|
|
98
|
+
| 'slh-dsa-sha2-192s'
|
|
99
|
+
| 'slh-dsa-sha2-192f'
|
|
100
|
+
| 'slh-dsa-sha2-256s'
|
|
101
|
+
| 'slh-dsa-sha2-256f'
|
|
102
|
+
| 'slh-dsa-shake-128s'
|
|
103
|
+
| 'slh-dsa-shake-128f'
|
|
104
|
+
| 'slh-dsa-shake-192s'
|
|
105
|
+
| 'slh-dsa-shake-192f'
|
|
106
|
+
| 'slh-dsa-shake-256s'
|
|
107
|
+
| 'slh-dsa-shake-256f';
|
|
108
|
+
|
|
77
109
|
export type PQCKeyPairAlgorithm =
|
|
78
110
|
| 'ML-DSA-44'
|
|
79
111
|
| 'ML-DSA-65'
|
|
80
112
|
| 'ML-DSA-87'
|
|
81
113
|
| 'ML-KEM-512'
|
|
82
114
|
| 'ML-KEM-768'
|
|
83
|
-
| 'ML-KEM-1024'
|
|
115
|
+
| 'ML-KEM-1024'
|
|
116
|
+
| SlhDsaAlgorithm;
|
|
84
117
|
export type PQCKeyPairType =
|
|
85
118
|
| 'ml-dsa-44'
|
|
86
119
|
| 'ml-dsa-65'
|
|
87
120
|
| 'ml-dsa-87'
|
|
88
121
|
| 'ml-kem-512'
|
|
89
122
|
| 'ml-kem-768'
|
|
90
|
-
| 'ml-kem-1024'
|
|
123
|
+
| 'ml-kem-1024'
|
|
124
|
+
| SlhDsaKeyPairType;
|
|
91
125
|
|
|
92
126
|
export type MlKemAlgorithm = 'ML-KEM-512' | 'ML-KEM-768' | 'ML-KEM-1024';
|
|
93
127
|
|
|
@@ -128,7 +162,8 @@ export type SignVerifyAlgorithm =
|
|
|
128
162
|
| 'Ed448'
|
|
129
163
|
| 'ML-DSA-44'
|
|
130
164
|
| 'ML-DSA-65'
|
|
131
|
-
| 'ML-DSA-87'
|
|
165
|
+
| 'ML-DSA-87'
|
|
166
|
+
| SlhDsaAlgorithm;
|
|
132
167
|
|
|
133
168
|
export type Argon2Algorithm = 'Argon2d' | 'Argon2i' | 'Argon2id';
|
|
134
169
|
|
|
@@ -245,8 +280,13 @@ export type SubtleAlgorithm = {
|
|
|
245
280
|
secretValue?: BufferLike;
|
|
246
281
|
associatedData?: BufferLike;
|
|
247
282
|
version?: number;
|
|
248
|
-
// KMAC parameters
|
|
283
|
+
// KMAC / cSHAKE / KangarooTwelve parameters
|
|
249
284
|
customization?: BufferLike;
|
|
285
|
+
outputLength?: number;
|
|
286
|
+
// TurboSHAKE parameter (RFC 9861 §2.2): single-byte domain separator in
|
|
287
|
+
// [0x01, 0x7F]. Defaults to 0x1F per the WICG WebCrypto Modern Algorithms
|
|
288
|
+
// draft when omitted.
|
|
289
|
+
domainSeparation?: number;
|
|
250
290
|
};
|
|
251
291
|
|
|
252
292
|
export type KeyPairType =
|
|
@@ -254,7 +294,8 @@ export type KeyPairType =
|
|
|
254
294
|
| RSAKeyPairType
|
|
255
295
|
| ECKeyPairType
|
|
256
296
|
| DSAKeyPairType
|
|
257
|
-
| DHKeyPairType
|
|
297
|
+
| DHKeyPairType
|
|
298
|
+
| PQCKeyPairType;
|
|
258
299
|
|
|
259
300
|
export type KeyUsage =
|
|
260
301
|
| 'encrypt'
|
|
@@ -306,10 +347,13 @@ export const kNamedCurveAliases = {
|
|
|
306
347
|
} as const;
|
|
307
348
|
// end TODO
|
|
308
349
|
|
|
350
|
+
export type RawPublicFormat = 'raw-public';
|
|
351
|
+
export type RawPrivateFormat = 'raw-private' | 'raw-seed';
|
|
352
|
+
|
|
309
353
|
export type KeyPairGenConfig = {
|
|
310
|
-
publicFormat?: KFormatType | -1;
|
|
311
|
-
publicType?: KeyEncoding;
|
|
312
|
-
privateFormat?: KFormatType | -1;
|
|
354
|
+
publicFormat?: KFormatType | RawPublicFormat | -1;
|
|
355
|
+
publicType?: KeyEncoding | RawECPointType;
|
|
356
|
+
privateFormat?: KFormatType | RawPrivateFormat | -1;
|
|
313
357
|
privateType?: KeyEncoding;
|
|
314
358
|
cipher?: string;
|
|
315
359
|
passphrase?: ArrayBuffer;
|
|
@@ -324,7 +368,7 @@ export type AsymmetricKeyType =
|
|
|
324
368
|
| CFRGKeyPairType
|
|
325
369
|
| PQCKeyPairType;
|
|
326
370
|
|
|
327
|
-
type JWKkty = 'AES' | 'RSA' | 'EC' | 'oct' | 'OKP';
|
|
371
|
+
type JWKkty = 'AES' | 'RSA' | 'EC' | 'oct' | 'OKP' | 'AKP';
|
|
328
372
|
type JWKuse = 'sig' | 'enc';
|
|
329
373
|
|
|
330
374
|
export interface JWK {
|
|
@@ -349,6 +393,8 @@ export interface JWK {
|
|
|
349
393
|
dp?: string;
|
|
350
394
|
dq?: string;
|
|
351
395
|
qi?: string;
|
|
396
|
+
pub?: string;
|
|
397
|
+
priv?: string;
|
|
352
398
|
ext?: boolean;
|
|
353
399
|
}
|
|
354
400
|
|
|
@@ -356,14 +402,22 @@ export type KTypePrivate = 'pkcs1' | 'pkcs8' | 'sec1';
|
|
|
356
402
|
export type KTypePublic = 'pkcs1' | 'spki';
|
|
357
403
|
export type KType = KTypePrivate | KTypePublic;
|
|
358
404
|
|
|
359
|
-
export type KFormat =
|
|
405
|
+
export type KFormat =
|
|
406
|
+
| 'der'
|
|
407
|
+
| 'pem'
|
|
408
|
+
| 'jwk'
|
|
409
|
+
| 'raw-public'
|
|
410
|
+
| 'raw-private'
|
|
411
|
+
| 'raw-seed';
|
|
360
412
|
|
|
361
413
|
export type DSAEncoding = 'der' | 'ieee-p1363';
|
|
362
414
|
|
|
415
|
+
export type RawECPointType = 'compressed' | 'uncompressed';
|
|
416
|
+
|
|
363
417
|
export type EncodingOptions = {
|
|
364
418
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
365
419
|
key?: any;
|
|
366
|
-
type?: KType;
|
|
420
|
+
type?: KType | RawECPointType;
|
|
367
421
|
encoding?: string;
|
|
368
422
|
dsaEncoding?: DSAEncoding;
|
|
369
423
|
format?: KFormat;
|
|
@@ -373,6 +427,8 @@ export type EncodingOptions = {
|
|
|
373
427
|
saltLength?: number;
|
|
374
428
|
oaepHash?: string;
|
|
375
429
|
oaepLabel?: BinaryLike;
|
|
430
|
+
asymmetricKeyType?: string;
|
|
431
|
+
namedCurve?: string;
|
|
376
432
|
};
|
|
377
433
|
|
|
378
434
|
export interface KeyDetail {
|
|
@@ -407,6 +463,7 @@ export type GenerateKeyPairOptions = {
|
|
|
407
463
|
export type KeyPairKey =
|
|
408
464
|
| ArrayBuffer
|
|
409
465
|
| Buffer
|
|
466
|
+
| CraftzdogBuffer
|
|
410
467
|
| string
|
|
411
468
|
| KeyObject
|
|
412
469
|
| KeyObjectHandle
|
|
@@ -494,9 +551,16 @@ export type CipherOFBType = 'aes-128-ofb' | 'aes-192-ofb' | 'aes-256-ofb';
|
|
|
494
551
|
|
|
495
552
|
export type KeyObjectHandle = KeyObjectHandleType;
|
|
496
553
|
|
|
554
|
+
export type RawDiffieHellmanKeyInput = {
|
|
555
|
+
key: ArrayBuffer | ArrayBufferView | string;
|
|
556
|
+
format: 'raw-public' | 'raw-private' | 'raw-seed';
|
|
557
|
+
asymmetricKeyType: string;
|
|
558
|
+
namedCurve?: string;
|
|
559
|
+
};
|
|
560
|
+
|
|
497
561
|
export type DiffieHellmanOptions = {
|
|
498
|
-
privateKey: KeyObject;
|
|
499
|
-
publicKey: KeyObject;
|
|
562
|
+
privateKey: KeyObject | RawDiffieHellmanKeyInput;
|
|
563
|
+
publicKey: KeyObject | RawDiffieHellmanKeyInput;
|
|
500
564
|
};
|
|
501
565
|
|
|
502
566
|
export type DiffieHellmanCallback = (
|
|
@@ -530,7 +594,8 @@ export type Operation =
|
|
|
530
594
|
| 'encapsulateBits'
|
|
531
595
|
| 'decapsulateBits'
|
|
532
596
|
| 'encapsulateKey'
|
|
533
|
-
| 'decapsulateKey'
|
|
597
|
+
| 'decapsulateKey'
|
|
598
|
+
| 'get key length';
|
|
534
599
|
|
|
535
600
|
export interface KeyPairOptions {
|
|
536
601
|
namedCurve: string;
|
package/src/utils/validation.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Buffer as SBuffer } from 'safe-buffer';
|
|
2
|
-
import type { BinaryLike, BufferLike, KeyUsage } from './types';
|
|
2
|
+
import type { BinaryLike, BufferLike, JWK, KeyUsage } from './types';
|
|
3
3
|
import { lazyDOMException } from './errors';
|
|
4
4
|
|
|
5
5
|
// The maximum buffer size that we'll support in the WebCrypto impl
|
|
@@ -57,6 +57,9 @@ export const validateMaxBufferLength = (
|
|
|
57
57
|
}
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
+
// Returns the intersection of `usageSet` and the spread `usages`, preserving
|
|
61
|
+
// the spread order. Dedup and canonical ordering are not performed here —
|
|
62
|
+
// the `CryptoKey` constructor runs `getSortedUsages` on every input.
|
|
60
63
|
export const getUsagesUnion = (usageSet: KeyUsage[], ...usages: KeyUsage[]) => {
|
|
61
64
|
const newset: KeyUsage[] = [];
|
|
62
65
|
for (let n = 0; n < usages.length; n++) {
|
|
@@ -67,6 +70,26 @@ export const getUsagesUnion = (usageSet: KeyUsage[], ...usages: KeyUsage[]) => {
|
|
|
67
70
|
return newset;
|
|
68
71
|
};
|
|
69
72
|
|
|
73
|
+
const kCanonicalUsageOrder: readonly KeyUsage[] = [
|
|
74
|
+
'encrypt',
|
|
75
|
+
'decrypt',
|
|
76
|
+
'sign',
|
|
77
|
+
'verify',
|
|
78
|
+
'deriveKey',
|
|
79
|
+
'deriveBits',
|
|
80
|
+
'wrapKey',
|
|
81
|
+
'unwrapKey',
|
|
82
|
+
'encapsulateKey',
|
|
83
|
+
'encapsulateBits',
|
|
84
|
+
'decapsulateKey',
|
|
85
|
+
'decapsulateBits',
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
export function getSortedUsages(usages: KeyUsage[]): KeyUsage[] {
|
|
89
|
+
const set = new Set<KeyUsage>(usages);
|
|
90
|
+
return kCanonicalUsageOrder.filter(usage => set.has(usage));
|
|
91
|
+
}
|
|
92
|
+
|
|
70
93
|
const kKeyOps: {
|
|
71
94
|
[key in KeyUsage]: number;
|
|
72
95
|
} = {
|
|
@@ -120,6 +143,52 @@ export const validateKeyOps = (
|
|
|
120
143
|
}
|
|
121
144
|
};
|
|
122
145
|
|
|
146
|
+
// WebCrypto JWK import structural validation, mirroring Node's
|
|
147
|
+
// `internal/crypto/webcrypto_util.validateJwk` + `validateKeyOps`:
|
|
148
|
+
// - `ext`: if present and false, `extractable` must also be false
|
|
149
|
+
// - `use`: if `keyUsages` is non-empty and `use` is present, must equal
|
|
150
|
+
// the algorithm's expected use ('sig' or 'enc')
|
|
151
|
+
// - `key_ops`: must be an array, must not contain duplicates, and every
|
|
152
|
+
// requested usage must appear in it
|
|
153
|
+
export function validateJwkStructure(
|
|
154
|
+
jwk: JWK,
|
|
155
|
+
extractable: boolean,
|
|
156
|
+
keyUsages: KeyUsage[],
|
|
157
|
+
expectedUse: 'sig' | 'enc',
|
|
158
|
+
): void {
|
|
159
|
+
if (jwk.ext === false && extractable) {
|
|
160
|
+
throw lazyDOMException(
|
|
161
|
+
'JWK "ext" is false but extractable was requested',
|
|
162
|
+
'DataError',
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
if (keyUsages.length > 0 && jwk.use !== undefined) {
|
|
166
|
+
if (jwk.use !== expectedUse) {
|
|
167
|
+
throw lazyDOMException('Invalid JWK "use" Parameter', 'DataError');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (jwk.key_ops !== undefined) {
|
|
171
|
+
if (!Array.isArray(jwk.key_ops)) {
|
|
172
|
+
throw lazyDOMException('JWK "key_ops" must be an array', 'DataError');
|
|
173
|
+
}
|
|
174
|
+
const seen = new Set<string>();
|
|
175
|
+
for (const op of jwk.key_ops) {
|
|
176
|
+
if (seen.has(op)) {
|
|
177
|
+
throw lazyDOMException('Duplicate key operation', 'DataError');
|
|
178
|
+
}
|
|
179
|
+
seen.add(op);
|
|
180
|
+
}
|
|
181
|
+
for (const usage of keyUsages) {
|
|
182
|
+
if (!jwk.key_ops.includes(usage)) {
|
|
183
|
+
throw lazyDOMException(
|
|
184
|
+
`JWK "key_ops" does not include requested usage "${usage}"`,
|
|
185
|
+
'DataError',
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
123
192
|
export function hasAnyNotIn(set: string[], checks: string[]) {
|
|
124
193
|
for (const s of set) {
|
|
125
194
|
if (!checks.includes(s)) {
|