react-native-quick-crypto 1.1.1 → 1.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/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 +26 -14
- 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/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 +53 -19
- 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/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 +51 -19
- 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 +4 -3
- 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 +2 -3
- 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/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 +72 -21
- 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
|
|
@@ -64,6 +97,7 @@ if (isHermes) {
|
|
|
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
|
}
|
|
@@ -101,6 +135,8 @@ export function toArrayBuffer(
|
|
|
101
135
|
}
|
|
102
136
|
|
|
103
137
|
export function bufferLikeToArrayBuffer(buf: BufferLike): ArrayBuffer {
|
|
138
|
+
rejectSharedArrayBuffer(buf);
|
|
139
|
+
|
|
104
140
|
// Buffer
|
|
105
141
|
if (CraftzdogBuffer.isBuffer(buf) || SafeBuffer.isBuffer(buf)) {
|
|
106
142
|
return toArrayBuffer(buf);
|
|
@@ -115,22 +151,8 @@ export function bufferLikeToArrayBuffer(buf: BufferLike): ArrayBuffer {
|
|
|
115
151
|
return buf;
|
|
116
152
|
}
|
|
117
153
|
|
|
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
154
|
throw new TypeError(
|
|
133
|
-
'Input must be a Buffer, ArrayBufferView,
|
|
155
|
+
'Input must be a Buffer, ArrayBufferView, or ArrayBuffer.',
|
|
134
156
|
);
|
|
135
157
|
}
|
|
136
158
|
|
|
@@ -138,6 +160,8 @@ export function binaryLikeToArrayBuffer(
|
|
|
138
160
|
input: BinaryLikeNode, // CipherKey adds compat with node types
|
|
139
161
|
encoding: string = 'utf-8',
|
|
140
162
|
): ArrayBuffer {
|
|
163
|
+
rejectSharedArrayBuffer(input);
|
|
164
|
+
|
|
141
165
|
// string
|
|
142
166
|
if (typeof input === 'string') {
|
|
143
167
|
if (encoding === 'buffer') {
|
|
@@ -204,19 +228,46 @@ export function binaryLikeToArrayBuffer(
|
|
|
204
228
|
);
|
|
205
229
|
}
|
|
206
230
|
|
|
207
|
-
export function ab2str(
|
|
231
|
+
export function ab2str(
|
|
232
|
+
buf: ArrayBuffer,
|
|
233
|
+
encoding: string = 'hex',
|
|
234
|
+
start?: number,
|
|
235
|
+
end?: number,
|
|
236
|
+
): string {
|
|
208
237
|
if (nativeBufferToStringEncodings.has(encoding)) {
|
|
209
|
-
return
|
|
238
|
+
return bufferToString(buf, encoding, start, end);
|
|
210
239
|
}
|
|
211
|
-
|
|
240
|
+
|
|
241
|
+
return CraftzdogBuffer.from(buf).toString(encoding, start, end);
|
|
212
242
|
}
|
|
213
243
|
|
|
214
|
-
/** Native C++ buffer-to-string
|
|
244
|
+
/** Native C++ buffer-to-string with arguments normalization*/
|
|
215
245
|
export function bufferToString(
|
|
216
246
|
buf: ArrayBuffer,
|
|
217
247
|
encoding: string = 'hex',
|
|
248
|
+
start?: number,
|
|
249
|
+
end?: number,
|
|
218
250
|
): string {
|
|
219
|
-
|
|
251
|
+
// https://github.com/nodejs/node/blob/v24.15.0/lib/buffer.js#L915-L928
|
|
252
|
+
if (start === undefined || start < 0) {
|
|
253
|
+
start = 0;
|
|
254
|
+
} else if (start >= buf.byteLength) {
|
|
255
|
+
return '';
|
|
256
|
+
} else {
|
|
257
|
+
start = Math.trunc(start) || 0;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (end === undefined || end > buf.byteLength) {
|
|
261
|
+
end = buf.byteLength;
|
|
262
|
+
} else {
|
|
263
|
+
end = Math.trunc(end) || 0;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (end <= start) {
|
|
267
|
+
return '';
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return utils.bufferToString(buf, encoding, start, end);
|
|
220
271
|
}
|
|
221
272
|
|
|
222
273
|
/** 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)) {
|