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/keys/index.ts
CHANGED
|
@@ -40,14 +40,68 @@ import { randomBytes } from '../random';
|
|
|
40
40
|
|
|
41
41
|
interface KeyInputObject {
|
|
42
42
|
key: BinaryLike | KeyObject | CryptoKey | JWK;
|
|
43
|
-
format?: 'pem' | 'der' | 'jwk';
|
|
43
|
+
format?: 'pem' | 'der' | 'jwk' | 'raw-public' | 'raw-private' | 'raw-seed';
|
|
44
44
|
type?: 'pkcs1' | 'pkcs8' | 'spki' | 'sec1';
|
|
45
45
|
passphrase?: BinaryLike;
|
|
46
46
|
encoding?: BufferEncoding;
|
|
47
|
+
asymmetricKeyType?: string;
|
|
48
|
+
namedCurve?: string;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
type KeyInput = BinaryLike | KeyInputObject | KeyObject | CryptoKey;
|
|
50
52
|
|
|
53
|
+
function isRawFormat(
|
|
54
|
+
format: string | undefined,
|
|
55
|
+
): format is 'raw-public' | 'raw-private' | 'raw-seed' {
|
|
56
|
+
return (
|
|
57
|
+
format === 'raw-public' || format === 'raw-private' || format === 'raw-seed'
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function createPublicKeyFromRaw(input: KeyInputObject): PublicKeyObject {
|
|
62
|
+
if (input.format !== 'raw-public') {
|
|
63
|
+
throw new Error('Invalid format for createPublicKey raw import');
|
|
64
|
+
}
|
|
65
|
+
if (typeof input.asymmetricKeyType !== 'string') {
|
|
66
|
+
throw new Error('options.asymmetricKeyType is required for raw key import');
|
|
67
|
+
}
|
|
68
|
+
if (input.asymmetricKeyType === 'ec' && !input.namedCurve) {
|
|
69
|
+
throw new Error('options.namedCurve is required for EC raw key import');
|
|
70
|
+
}
|
|
71
|
+
const handle =
|
|
72
|
+
NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
|
|
73
|
+
handle.initRawPublic(
|
|
74
|
+
input.asymmetricKeyType,
|
|
75
|
+
toAB(input.key as BinaryLike),
|
|
76
|
+
input.namedCurve,
|
|
77
|
+
);
|
|
78
|
+
return new PublicKeyObject(handle);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function createPrivateKeyFromRaw(input: KeyInputObject): PrivateKeyObject {
|
|
82
|
+
if (input.format !== 'raw-private' && input.format !== 'raw-seed') {
|
|
83
|
+
throw new Error('Invalid format for createPrivateKey raw import');
|
|
84
|
+
}
|
|
85
|
+
if (typeof input.asymmetricKeyType !== 'string') {
|
|
86
|
+
throw new Error('options.asymmetricKeyType is required for raw key import');
|
|
87
|
+
}
|
|
88
|
+
if (input.asymmetricKeyType === 'ec' && !input.namedCurve) {
|
|
89
|
+
throw new Error('options.namedCurve is required for EC raw key import');
|
|
90
|
+
}
|
|
91
|
+
const handle =
|
|
92
|
+
NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
|
|
93
|
+
if (input.format === 'raw-seed') {
|
|
94
|
+
handle.initRawSeed(input.asymmetricKeyType, toAB(input.key as BinaryLike));
|
|
95
|
+
} else {
|
|
96
|
+
handle.initRawPrivate(
|
|
97
|
+
input.asymmetricKeyType,
|
|
98
|
+
toAB(input.key as BinaryLike),
|
|
99
|
+
input.namedCurve,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
return new PrivateKeyObject(handle);
|
|
103
|
+
}
|
|
104
|
+
|
|
51
105
|
function createSecretKey(key: BinaryLike): SecretKeyObject {
|
|
52
106
|
const keyBuffer = toAB(key);
|
|
53
107
|
return KeyObject.createKeyObject('secret', keyBuffer) as SecretKeyObject;
|
|
@@ -116,8 +170,10 @@ function prepareAsymmetricKey(
|
|
|
116
170
|
return { data: toAB(data), format: 'pem', type };
|
|
117
171
|
}
|
|
118
172
|
|
|
119
|
-
// Filter
|
|
120
|
-
|
|
173
|
+
// Filter to only 'pem' or 'der' — JWK and raw formats are handled
|
|
174
|
+
// separately via dedicated paths.
|
|
175
|
+
const filteredFormat: 'pem' | 'der' | undefined =
|
|
176
|
+
format === 'pem' || format === 'der' ? format : undefined;
|
|
121
177
|
return { data: toAB(data), format: filteredFormat, type };
|
|
122
178
|
}
|
|
123
179
|
|
|
@@ -125,6 +181,14 @@ function prepareAsymmetricKey(
|
|
|
125
181
|
}
|
|
126
182
|
|
|
127
183
|
function createPublicKey(key: KeyInput): PublicKeyObject {
|
|
184
|
+
if (typeof key === 'object' && 'key' in key && isRawFormat(key.format)) {
|
|
185
|
+
if (key.format !== 'raw-public') {
|
|
186
|
+
throw new Error(
|
|
187
|
+
`Invalid format ${key.format} for createPublicKey — only 'raw-public' is allowed`,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
return createPublicKeyFromRaw(key as KeyInputObject);
|
|
191
|
+
}
|
|
128
192
|
if (typeof key === 'object' && 'key' in key && key.format === 'jwk') {
|
|
129
193
|
const handle =
|
|
130
194
|
NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
|
|
@@ -169,6 +233,12 @@ function createPublicKey(key: KeyInput): PublicKeyObject {
|
|
|
169
233
|
}
|
|
170
234
|
|
|
171
235
|
function createPrivateKey(key: KeyInput): PrivateKeyObject {
|
|
236
|
+
if (typeof key === 'object' && 'key' in key && isRawFormat(key.format)) {
|
|
237
|
+
if (key.format === 'raw-public') {
|
|
238
|
+
throw new Error("Invalid format 'raw-public' for createPrivateKey");
|
|
239
|
+
}
|
|
240
|
+
return createPrivateKeyFromRaw(key as KeyInputObject);
|
|
241
|
+
}
|
|
172
242
|
if (typeof key === 'object' && 'key' in key && key.format === 'jwk') {
|
|
173
243
|
const handle =
|
|
174
244
|
NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
|
package/src/keys/signVerify.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
KFormatType,
|
|
14
14
|
KeyEncoding,
|
|
15
15
|
} from '../utils';
|
|
16
|
+
import { constants } from '../constants';
|
|
16
17
|
|
|
17
18
|
type KeyInput = BinaryLike | KeyObject | CryptoKey | KeyInputObject;
|
|
18
19
|
|
|
@@ -144,6 +145,16 @@ function dsaEncodingToNumber(
|
|
|
144
145
|
return undefined;
|
|
145
146
|
}
|
|
146
147
|
|
|
148
|
+
function getSaltLength(options?: SignOptions): number | undefined {
|
|
149
|
+
if (
|
|
150
|
+
options?.padding === constants.RSA_PKCS1_PSS_PADDING &&
|
|
151
|
+
options?.saltLength === undefined
|
|
152
|
+
) {
|
|
153
|
+
return constants.RSA_PSS_SALTLEN_MAX_SIGN;
|
|
154
|
+
}
|
|
155
|
+
return options?.saltLength;
|
|
156
|
+
}
|
|
157
|
+
|
|
147
158
|
export class Sign {
|
|
148
159
|
private handle: SignHandleSpec;
|
|
149
160
|
|
|
@@ -169,7 +180,7 @@ export class Sign {
|
|
|
169
180
|
const signature = this.handle.sign(
|
|
170
181
|
keyObject.handle,
|
|
171
182
|
options?.padding,
|
|
172
|
-
options
|
|
183
|
+
getSaltLength(options),
|
|
173
184
|
dsaEncodingToNumber(options?.dsaEncoding),
|
|
174
185
|
);
|
|
175
186
|
|
|
@@ -219,7 +230,7 @@ export class Verify {
|
|
|
219
230
|
keyObject.handle,
|
|
220
231
|
sigBuffer,
|
|
221
232
|
options?.padding,
|
|
222
|
-
options
|
|
233
|
+
getSaltLength(options),
|
|
223
234
|
dsaEncodingToNumber(options?.dsaEncoding),
|
|
224
235
|
);
|
|
225
236
|
}
|
package/src/keys/utils.ts
CHANGED
|
@@ -5,13 +5,36 @@ import {
|
|
|
5
5
|
KFormatType,
|
|
6
6
|
} from '../utils';
|
|
7
7
|
import type { CryptoKeyPair, EncodingOptions } from '../utils';
|
|
8
|
-
import type { CryptoKey } from './classes';
|
|
8
|
+
import type { CryptoKey, PublicKeyObject, PrivateKeyObject } from './classes';
|
|
9
9
|
|
|
10
10
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
11
|
export const isCryptoKey = (obj: any): boolean => {
|
|
12
12
|
return obj !== null && obj?.keyObject !== undefined;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
export function exportPublicKeyRaw(
|
|
16
|
+
pub: PublicKeyObject,
|
|
17
|
+
pointType: 'compressed' | 'uncompressed' | undefined,
|
|
18
|
+
): ArrayBuffer {
|
|
19
|
+
if (pub.asymmetricKeyType === 'ec') {
|
|
20
|
+
return pub.handle.exportECPublicRaw(pointType === 'compressed');
|
|
21
|
+
}
|
|
22
|
+
return pub.handle.exportRawPublic();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function exportPrivateKeyRaw(
|
|
26
|
+
priv: PrivateKeyObject,
|
|
27
|
+
format: 'raw-private' | 'raw-seed',
|
|
28
|
+
): ArrayBuffer {
|
|
29
|
+
if (format === 'raw-seed') {
|
|
30
|
+
return priv.handle.exportRawSeed();
|
|
31
|
+
}
|
|
32
|
+
if (priv.asymmetricKeyType === 'ec') {
|
|
33
|
+
return priv.handle.exportECPrivateRaw();
|
|
34
|
+
}
|
|
35
|
+
return priv.handle.exportRawPrivate();
|
|
36
|
+
}
|
|
37
|
+
|
|
15
38
|
export function getCryptoKeyPair(
|
|
16
39
|
key: CryptoKey | CryptoKeyPair,
|
|
17
40
|
): CryptoKeyPair {
|
|
@@ -62,6 +85,19 @@ export function parseKeyEncoding(
|
|
|
62
85
|
objName,
|
|
63
86
|
);
|
|
64
87
|
|
|
88
|
+
if (
|
|
89
|
+
format === 'raw-public' ||
|
|
90
|
+
format === 'raw-private' ||
|
|
91
|
+
format === 'raw-seed'
|
|
92
|
+
) {
|
|
93
|
+
if (enc.cipher != null || enc.passphrase !== undefined) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`Incompatible key options: ${format} does not support encryption`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
return { format, type, cipher: undefined, passphrase: undefined };
|
|
99
|
+
}
|
|
100
|
+
|
|
65
101
|
let cipher, passphrase, encoding;
|
|
66
102
|
if (isPublic !== true) {
|
|
67
103
|
({ cipher, passphrase, encoding } = enc);
|
|
@@ -77,7 +113,7 @@ export function parseKeyEncoding(
|
|
|
77
113
|
(type === KeyEncoding.PKCS1 || type === KeyEncoding.SEC1)
|
|
78
114
|
) {
|
|
79
115
|
throw new Error(
|
|
80
|
-
`Incompatible key options ${encodingNames[type]} does not support encryption`,
|
|
116
|
+
`Incompatible key options ${encodingNames[type as KeyEncoding]} does not support encryption`,
|
|
81
117
|
);
|
|
82
118
|
}
|
|
83
119
|
} else if (passphrase !== undefined) {
|
|
@@ -120,12 +156,15 @@ function parseKeyFormat(
|
|
|
120
156
|
formatStr?: string,
|
|
121
157
|
defaultFormat?: KFormatType,
|
|
122
158
|
optionName?: string,
|
|
123
|
-
) {
|
|
159
|
+
): KFormatType | 'raw-public' | 'raw-private' | 'raw-seed' {
|
|
124
160
|
if (formatStr === undefined && defaultFormat !== undefined)
|
|
125
161
|
return defaultFormat;
|
|
126
162
|
else if (formatStr === 'pem') return KFormatType.PEM;
|
|
127
163
|
else if (formatStr === 'der') return KFormatType.DER;
|
|
128
164
|
else if (formatStr === 'jwk') return KFormatType.JWK;
|
|
165
|
+
else if (formatStr === 'raw-public') return 'raw-public';
|
|
166
|
+
else if (formatStr === 'raw-private') return 'raw-private';
|
|
167
|
+
else if (formatStr === 'raw-seed') return 'raw-seed';
|
|
129
168
|
throw new Error(`Invalid key format str: ${optionName}`);
|
|
130
169
|
}
|
|
131
170
|
|
|
@@ -166,7 +205,10 @@ function parseKeyFormatAndType(
|
|
|
166
205
|
keyType?: string,
|
|
167
206
|
isPublic?: boolean,
|
|
168
207
|
objName?: string,
|
|
169
|
-
) {
|
|
208
|
+
): {
|
|
209
|
+
format: KFormatType | 'raw-public' | 'raw-private' | 'raw-seed';
|
|
210
|
+
type: KeyEncoding | 'compressed' | 'uncompressed' | undefined;
|
|
211
|
+
} {
|
|
170
212
|
const { format: formatStr, type: typeStr } = enc;
|
|
171
213
|
|
|
172
214
|
const isInput = keyType === undefined;
|
|
@@ -176,11 +218,42 @@ function parseKeyFormatAndType(
|
|
|
176
218
|
option('format', objName),
|
|
177
219
|
);
|
|
178
220
|
|
|
221
|
+
if (format === 'raw-public') {
|
|
222
|
+
if (isPublic === false) {
|
|
223
|
+
throw new Error(
|
|
224
|
+
`Invalid format 'raw-public' for ${option('format', objName)}`,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
if (typeStr === undefined || typeStr === 'uncompressed') {
|
|
228
|
+
return { format, type: 'uncompressed' };
|
|
229
|
+
}
|
|
230
|
+
if (typeStr === 'compressed') {
|
|
231
|
+
return { format, type: 'compressed' };
|
|
232
|
+
}
|
|
233
|
+
throw new Error(
|
|
234
|
+
`Invalid ${option('type', objName)} for raw-public: ${typeStr}`,
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (format === 'raw-private' || format === 'raw-seed') {
|
|
239
|
+
if (isPublic === true) {
|
|
240
|
+
throw new Error(
|
|
241
|
+
`Invalid format '${format}' for ${option('format', objName)}`,
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
if (typeStr !== undefined) {
|
|
245
|
+
throw new Error(
|
|
246
|
+
`Invalid ${option('type', objName)} for ${format}: ${typeStr}`,
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
return { format, type: undefined };
|
|
250
|
+
}
|
|
251
|
+
|
|
179
252
|
const isRequired =
|
|
180
253
|
(!isInput || format === KFormatType.DER) && format !== KFormatType.JWK;
|
|
181
254
|
|
|
182
255
|
const type = parseKeyType(
|
|
183
|
-
typeStr,
|
|
256
|
+
typeStr as string | undefined,
|
|
184
257
|
isRequired,
|
|
185
258
|
keyType,
|
|
186
259
|
isPublic,
|
package/src/random.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { Buffer } from '@craftzdog/react-native-buffer';
|
|
2
2
|
import type { ABV, RandomCallback } from './utils';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
abvToArrayBuffer,
|
|
5
|
+
lazyDOMException,
|
|
6
|
+
QuotaExceededError,
|
|
7
|
+
rejectSharedArrayBuffer,
|
|
8
|
+
} from './utils';
|
|
4
9
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
5
10
|
import type { Random } from './specs/random.nitro';
|
|
6
11
|
|
|
@@ -288,6 +293,27 @@ export type RandomTypedArrays =
|
|
|
288
293
|
| Uint16Array
|
|
289
294
|
| Uint32Array;
|
|
290
295
|
|
|
296
|
+
// WebCrypto §getRandomValues only accepts integer-typed views. Float and
|
|
297
|
+
// non-TypedArray ABVs (DataView) must be rejected with a TypeMismatchError
|
|
298
|
+
// DOMException — see https://w3c.github.io/webcrypto/#Crypto-method-getRandomValues
|
|
299
|
+
const INTEGER_TYPED_ARRAY_TAGS = new Set([
|
|
300
|
+
'Int8Array',
|
|
301
|
+
'Int16Array',
|
|
302
|
+
'Int32Array',
|
|
303
|
+
'Uint8Array',
|
|
304
|
+
'Uint8ClampedArray',
|
|
305
|
+
'Uint16Array',
|
|
306
|
+
'Uint32Array',
|
|
307
|
+
'BigInt64Array',
|
|
308
|
+
'BigUint64Array',
|
|
309
|
+
]);
|
|
310
|
+
|
|
311
|
+
function isIntegerTypedArray(value: unknown): boolean {
|
|
312
|
+
if (!ArrayBuffer.isView(value)) return false;
|
|
313
|
+
const tag = (value as { [Symbol.toStringTag]?: string })[Symbol.toStringTag];
|
|
314
|
+
return tag !== undefined && INTEGER_TYPED_ARRAY_TAGS.has(tag);
|
|
315
|
+
}
|
|
316
|
+
|
|
291
317
|
/**
|
|
292
318
|
* Fills the provided typed array with cryptographically strong random values.
|
|
293
319
|
*
|
|
@@ -295,8 +321,24 @@ export type RandomTypedArrays =
|
|
|
295
321
|
* @returns The filled data
|
|
296
322
|
*/
|
|
297
323
|
export function getRandomValues(data: RandomTypedArrays) {
|
|
324
|
+
// WebIDL BufferSource conversion (TypeError) must run before the
|
|
325
|
+
// WebCrypto-specific integer-type / size checks (TypeMismatchError /
|
|
326
|
+
// QuotaExceededError). `randomFillSync` below also rejects SAB via
|
|
327
|
+
// `abvToArrayBuffer`, but by then we'd already have thrown the wrong
|
|
328
|
+
// error type for a non-integer SAB-view, so the explicit early call is
|
|
329
|
+
// load-bearing for spec compliance — not redundant.
|
|
330
|
+
rejectSharedArrayBuffer(data);
|
|
331
|
+
if (!isIntegerTypedArray(data)) {
|
|
332
|
+
throw lazyDOMException(
|
|
333
|
+
'The data argument must be an integer-type TypedArray',
|
|
334
|
+
'TypeMismatchError',
|
|
335
|
+
);
|
|
336
|
+
}
|
|
298
337
|
if (data.byteLength > 65536) {
|
|
299
|
-
throw new
|
|
338
|
+
throw new QuotaExceededError('The requested length exceeds 65,536 bytes', {
|
|
339
|
+
quota: 65536,
|
|
340
|
+
requested: data.byteLength,
|
|
341
|
+
});
|
|
300
342
|
}
|
|
301
343
|
randomFillSync(data, 0);
|
|
302
344
|
return data;
|
|
@@ -308,14 +350,28 @@ for (let i = 0; i < 256; ++i) {
|
|
|
308
350
|
byteToHex.push((i + 0x100).toString(16).slice(1));
|
|
309
351
|
}
|
|
310
352
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
353
|
+
export interface RandomUUIDOptions {
|
|
354
|
+
// Accepted for Node.js parity. RNQC does not buffer entropy, so this is a
|
|
355
|
+
// no-op: every UUID already pulls fresh bytes from the OS CSPRNG.
|
|
356
|
+
disableEntropyCache?: boolean;
|
|
357
|
+
}
|
|
316
358
|
|
|
317
|
-
|
|
318
|
-
|
|
359
|
+
function validateRandomUUIDOptions(options?: RandomUUIDOptions): void {
|
|
360
|
+
if (options === undefined) return;
|
|
361
|
+
if (typeof options !== 'object' || options === null) {
|
|
362
|
+
throw new TypeError('options must be an object');
|
|
363
|
+
}
|
|
364
|
+
if (
|
|
365
|
+
options.disableEntropyCache !== undefined &&
|
|
366
|
+
typeof options.disableEntropyCache !== 'boolean'
|
|
367
|
+
) {
|
|
368
|
+
throw new TypeError('options.disableEntropyCache must be a boolean');
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// RFC 9562 variant 10xx is shared by v4 and v7.
|
|
373
|
+
function serializeUUID(buffer: Buffer, version: number): string {
|
|
374
|
+
buffer[6] = (buffer[6]! & 0x0f) | (version << 4);
|
|
319
375
|
buffer[8] = (buffer[8]! & 0x3f) | 0x80;
|
|
320
376
|
|
|
321
377
|
return (
|
|
@@ -341,3 +397,31 @@ export function randomUUID() {
|
|
|
341
397
|
byteToHex[buffer[15]!]
|
|
342
398
|
).toLowerCase();
|
|
343
399
|
}
|
|
400
|
+
|
|
401
|
+
// RFC 9562 §5.4 — random UUID (v4).
|
|
402
|
+
export function randomUUID(options?: RandomUUIDOptions): string {
|
|
403
|
+
validateRandomUUIDOptions(options);
|
|
404
|
+
const buffer = new Buffer(16);
|
|
405
|
+
randomFillSync(buffer, 0, 16);
|
|
406
|
+
return serializeUUID(buffer, 4);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// RFC 9562 §5.7 — Unix-ms timestamped UUID (v7).
|
|
410
|
+
// Layout: 48-bit big-endian Unix-ms timestamp | 4-bit version (7) |
|
|
411
|
+
// 12 bits random | 2-bit variant (10) | 62 bits random.
|
|
412
|
+
export function randomUUIDv7(options?: RandomUUIDOptions): string {
|
|
413
|
+
validateRandomUUIDOptions(options);
|
|
414
|
+
const buffer = new Buffer(16);
|
|
415
|
+
randomFillSync(buffer, 6, 10);
|
|
416
|
+
|
|
417
|
+
const now = Date.now();
|
|
418
|
+
const msb = Math.floor(now / 0x100000000);
|
|
419
|
+
buffer[0] = (msb >>> 8) & 0xff;
|
|
420
|
+
buffer[1] = msb & 0xff;
|
|
421
|
+
buffer[2] = (now >>> 24) & 0xff;
|
|
422
|
+
buffer[3] = (now >>> 16) & 0xff;
|
|
423
|
+
buffer[4] = (now >>> 8) & 0xff;
|
|
424
|
+
buffer[5] = now & 0xff;
|
|
425
|
+
|
|
426
|
+
return serializeUUID(buffer, 7);
|
|
427
|
+
}
|
package/src/rsa.ts
CHANGED
|
@@ -260,6 +260,14 @@ function rsa_formatKeyPairOutput(
|
|
|
260
260
|
let publicKey: PublicKeyObject | Buffer | string | ArrayBuffer;
|
|
261
261
|
let privateKey: PrivateKeyObject | Buffer | string | ArrayBuffer;
|
|
262
262
|
|
|
263
|
+
if (
|
|
264
|
+
publicFormat === 'raw-public' ||
|
|
265
|
+
privateFormat === 'raw-private' ||
|
|
266
|
+
privateFormat === 'raw-seed'
|
|
267
|
+
) {
|
|
268
|
+
throw new Error('Raw key formats are not supported for RSA keys');
|
|
269
|
+
}
|
|
270
|
+
|
|
263
271
|
if (publicFormat === -1) {
|
|
264
272
|
publicKey = pub;
|
|
265
273
|
} else {
|
package/src/slhdsa.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { NitroModules } from 'react-native-nitro-modules';
|
|
2
|
+
import type { SlhDsaKeyPair } from './specs/slhDsaKeyPair.nitro';
|
|
3
|
+
import {
|
|
4
|
+
CryptoKey,
|
|
5
|
+
KeyObject,
|
|
6
|
+
PublicKeyObject,
|
|
7
|
+
PrivateKeyObject as PrivateKeyObjectClass,
|
|
8
|
+
} from './keys/classes';
|
|
9
|
+
import type {
|
|
10
|
+
CryptoKeyPair,
|
|
11
|
+
KeyUsage,
|
|
12
|
+
SubtleAlgorithm,
|
|
13
|
+
SlhDsaAlgorithm,
|
|
14
|
+
} from './utils';
|
|
15
|
+
import {
|
|
16
|
+
hasAnyNotIn,
|
|
17
|
+
lazyDOMException,
|
|
18
|
+
getUsagesUnion,
|
|
19
|
+
KFormatType,
|
|
20
|
+
KeyEncoding,
|
|
21
|
+
} from './utils';
|
|
22
|
+
|
|
23
|
+
export type SlhDsaVariant = SlhDsaAlgorithm;
|
|
24
|
+
|
|
25
|
+
export const SLH_DSA_VARIANTS: readonly SlhDsaVariant[] = [
|
|
26
|
+
'SLH-DSA-SHA2-128s',
|
|
27
|
+
'SLH-DSA-SHA2-128f',
|
|
28
|
+
'SLH-DSA-SHA2-192s',
|
|
29
|
+
'SLH-DSA-SHA2-192f',
|
|
30
|
+
'SLH-DSA-SHA2-256s',
|
|
31
|
+
'SLH-DSA-SHA2-256f',
|
|
32
|
+
'SLH-DSA-SHAKE-128s',
|
|
33
|
+
'SLH-DSA-SHAKE-128f',
|
|
34
|
+
'SLH-DSA-SHAKE-192s',
|
|
35
|
+
'SLH-DSA-SHAKE-192f',
|
|
36
|
+
'SLH-DSA-SHAKE-256s',
|
|
37
|
+
'SLH-DSA-SHAKE-256f',
|
|
38
|
+
] as const;
|
|
39
|
+
|
|
40
|
+
export class SlhDsa {
|
|
41
|
+
variant: SlhDsaVariant;
|
|
42
|
+
native: SlhDsaKeyPair;
|
|
43
|
+
|
|
44
|
+
constructor(variant: SlhDsaVariant) {
|
|
45
|
+
this.variant = variant;
|
|
46
|
+
this.native =
|
|
47
|
+
NitroModules.createHybridObject<SlhDsaKeyPair>('SlhDsaKeyPair');
|
|
48
|
+
this.native.setVariant(variant);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async generateKeyPair(): Promise<void> {
|
|
52
|
+
await this.native.generateKeyPair(
|
|
53
|
+
KFormatType.DER,
|
|
54
|
+
KeyEncoding.SPKI,
|
|
55
|
+
KFormatType.DER,
|
|
56
|
+
KeyEncoding.PKCS8,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
generateKeyPairSync(): void {
|
|
61
|
+
this.native.generateKeyPairSync(
|
|
62
|
+
KFormatType.DER,
|
|
63
|
+
KeyEncoding.SPKI,
|
|
64
|
+
KFormatType.DER,
|
|
65
|
+
KeyEncoding.PKCS8,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
getPublicKey(): ArrayBuffer {
|
|
70
|
+
return this.native.getPublicKey();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
getPrivateKey(): ArrayBuffer {
|
|
74
|
+
return this.native.getPrivateKey();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async sign(message: ArrayBuffer): Promise<ArrayBuffer> {
|
|
78
|
+
return this.native.sign(message);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
signSync(message: ArrayBuffer): ArrayBuffer {
|
|
82
|
+
return this.native.signSync(message);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async verify(signature: ArrayBuffer, message: ArrayBuffer): Promise<boolean> {
|
|
86
|
+
return this.native.verify(signature, message);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
verifySync(signature: ArrayBuffer, message: ArrayBuffer): boolean {
|
|
90
|
+
return this.native.verifySync(signature, message);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function slhdsa_generateKeyPairWebCrypto(
|
|
95
|
+
variant: SlhDsaVariant,
|
|
96
|
+
extractable: boolean,
|
|
97
|
+
keyUsages: KeyUsage[],
|
|
98
|
+
): Promise<CryptoKeyPair> {
|
|
99
|
+
if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
|
|
100
|
+
throw lazyDOMException(
|
|
101
|
+
`Unsupported key usage for ${variant}`,
|
|
102
|
+
'SyntaxError',
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const publicUsages = getUsagesUnion(keyUsages, 'verify');
|
|
107
|
+
const privateUsages = getUsagesUnion(keyUsages, 'sign');
|
|
108
|
+
|
|
109
|
+
if (privateUsages.length === 0) {
|
|
110
|
+
throw lazyDOMException('Usages cannot be empty', 'SyntaxError');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const slhdsa = new SlhDsa(variant);
|
|
114
|
+
await slhdsa.generateKeyPair();
|
|
115
|
+
|
|
116
|
+
const publicKeyData = slhdsa.getPublicKey();
|
|
117
|
+
const privateKeyData = slhdsa.getPrivateKey();
|
|
118
|
+
|
|
119
|
+
const pub = KeyObject.createKeyObject(
|
|
120
|
+
'public',
|
|
121
|
+
publicKeyData,
|
|
122
|
+
KFormatType.DER,
|
|
123
|
+
KeyEncoding.SPKI,
|
|
124
|
+
) as PublicKeyObject;
|
|
125
|
+
const publicKey = new CryptoKey(
|
|
126
|
+
pub,
|
|
127
|
+
{ name: variant } as SubtleAlgorithm,
|
|
128
|
+
publicUsages,
|
|
129
|
+
true,
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const priv = KeyObject.createKeyObject(
|
|
133
|
+
'private',
|
|
134
|
+
privateKeyData,
|
|
135
|
+
KFormatType.DER,
|
|
136
|
+
KeyEncoding.PKCS8,
|
|
137
|
+
) as PrivateKeyObjectClass;
|
|
138
|
+
const privateKey = new CryptoKey(
|
|
139
|
+
priv,
|
|
140
|
+
{ name: variant } as SubtleAlgorithm,
|
|
141
|
+
privateUsages,
|
|
142
|
+
extractable,
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
return { publicKey, privateKey };
|
|
146
|
+
}
|
|
@@ -18,6 +18,11 @@ export interface KeyObjectHandle
|
|
|
18
18
|
passphrase?: ArrayBuffer,
|
|
19
19
|
): ArrayBuffer;
|
|
20
20
|
exportJwk(key: JWK, handleRsaPss: boolean): JWK;
|
|
21
|
+
exportRawPublic(): ArrayBuffer;
|
|
22
|
+
exportRawPrivate(): ArrayBuffer;
|
|
23
|
+
exportRawSeed(): ArrayBuffer;
|
|
24
|
+
exportECPublicRaw(compressed: boolean): ArrayBuffer;
|
|
25
|
+
exportECPrivateRaw(): ArrayBuffer;
|
|
21
26
|
getAsymmetricKeyType(): AsymmetricKeyType;
|
|
22
27
|
init(
|
|
23
28
|
keyType: KeyType,
|
|
@@ -32,8 +37,20 @@ export interface KeyObjectHandle
|
|
|
32
37
|
keyData: ArrayBuffer,
|
|
33
38
|
isPublic: boolean,
|
|
34
39
|
): boolean;
|
|
40
|
+
initRawPublic(
|
|
41
|
+
asymmetricKeyType: string,
|
|
42
|
+
keyData: ArrayBuffer,
|
|
43
|
+
namedCurve?: string,
|
|
44
|
+
): boolean;
|
|
45
|
+
initRawPrivate(
|
|
46
|
+
asymmetricKeyType: string,
|
|
47
|
+
keyData: ArrayBuffer,
|
|
48
|
+
namedCurve?: string,
|
|
49
|
+
): boolean;
|
|
50
|
+
initRawSeed(asymmetricKeyType: string, keyData: ArrayBuffer): boolean;
|
|
35
51
|
initJwk(keyData: JWK, namedCurve?: NamedCurve): KeyType | undefined;
|
|
36
52
|
keyDetail(): KeyDetail;
|
|
37
53
|
keyEquals(other: KeyObjectHandle): boolean;
|
|
38
54
|
getSymmetricKeySize(): number;
|
|
55
|
+
checkEcKeyData(): boolean;
|
|
39
56
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { HybridObject } from 'react-native-nitro-modules';
|
|
2
|
+
|
|
3
|
+
export interface SlhDsaKeyPair
|
|
4
|
+
extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
5
|
+
generateKeyPair(
|
|
6
|
+
publicFormat: number,
|
|
7
|
+
publicType: number,
|
|
8
|
+
privateFormat: number,
|
|
9
|
+
privateType: number,
|
|
10
|
+
): Promise<void>;
|
|
11
|
+
|
|
12
|
+
generateKeyPairSync(
|
|
13
|
+
publicFormat: number,
|
|
14
|
+
publicType: number,
|
|
15
|
+
privateFormat: number,
|
|
16
|
+
privateType: number,
|
|
17
|
+
): void;
|
|
18
|
+
|
|
19
|
+
getPublicKey(): ArrayBuffer;
|
|
20
|
+
getPrivateKey(): ArrayBuffer;
|
|
21
|
+
|
|
22
|
+
sign(message: ArrayBuffer): Promise<ArrayBuffer>;
|
|
23
|
+
signSync(message: ArrayBuffer): ArrayBuffer;
|
|
24
|
+
|
|
25
|
+
verify(signature: ArrayBuffer, message: ArrayBuffer): Promise<boolean>;
|
|
26
|
+
verifySync(signature: ArrayBuffer, message: ArrayBuffer): boolean;
|
|
27
|
+
|
|
28
|
+
setVariant(variant: string): void;
|
|
29
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { HybridObject } from 'react-native-nitro-modules';
|
|
2
|
+
|
|
3
|
+
export type TurboShakeVariant = 'TurboSHAKE128' | 'TurboSHAKE256';
|
|
4
|
+
export type KangarooTwelveVariant = 'KT128' | 'KT256';
|
|
5
|
+
|
|
6
|
+
export interface TurboShake
|
|
7
|
+
extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
8
|
+
turboShake(
|
|
9
|
+
variant: TurboShakeVariant,
|
|
10
|
+
domainSeparation: number,
|
|
11
|
+
outputLength: number,
|
|
12
|
+
data: ArrayBuffer,
|
|
13
|
+
): Promise<ArrayBuffer>;
|
|
14
|
+
|
|
15
|
+
kangarooTwelve(
|
|
16
|
+
variant: KangarooTwelveVariant,
|
|
17
|
+
outputLength: number,
|
|
18
|
+
data: ArrayBuffer,
|
|
19
|
+
customization?: ArrayBuffer,
|
|
20
|
+
): Promise<ArrayBuffer>;
|
|
21
|
+
}
|