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/ed.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
PrivateKeyObject as PrivateKeyObjectClass,
|
|
9
9
|
} from './keys/classes';
|
|
10
10
|
import type { EdKeyPair } from './specs/edKeyPair.nitro';
|
|
11
|
+
import type { KeyObjectHandle as KeyObjectHandleSpec } from './specs/keyObjectHandle.nitro';
|
|
11
12
|
import type {
|
|
12
13
|
BinaryLike,
|
|
13
14
|
CFRGKeyPairType,
|
|
@@ -31,6 +32,10 @@ import {
|
|
|
31
32
|
} from './utils';
|
|
32
33
|
import { ECDH } from './ecdh';
|
|
33
34
|
|
|
35
|
+
function coerceToNumeric(value: unknown): number {
|
|
36
|
+
return typeof value === 'number' ? value : -1;
|
|
37
|
+
}
|
|
38
|
+
|
|
34
39
|
export class Ed {
|
|
35
40
|
type: CFRGKeyPairType;
|
|
36
41
|
config: KeyPairGenConfig;
|
|
@@ -86,10 +91,10 @@ export class Ed {
|
|
|
86
91
|
|
|
87
92
|
async generateKeyPair(): Promise<void> {
|
|
88
93
|
await this.native.generateKeyPair(
|
|
89
|
-
this.config.publicFormat
|
|
90
|
-
this.config.publicType
|
|
91
|
-
this.config.privateFormat
|
|
92
|
-
this.config.privateType
|
|
94
|
+
coerceToNumeric(this.config.publicFormat),
|
|
95
|
+
coerceToNumeric(this.config.publicType),
|
|
96
|
+
coerceToNumeric(this.config.privateFormat),
|
|
97
|
+
coerceToNumeric(this.config.privateType),
|
|
93
98
|
this.config.cipher,
|
|
94
99
|
this.config.passphrase as ArrayBuffer,
|
|
95
100
|
);
|
|
@@ -97,10 +102,10 @@ export class Ed {
|
|
|
97
102
|
|
|
98
103
|
generateKeyPairSync(): void {
|
|
99
104
|
this.native.generateKeyPairSync(
|
|
100
|
-
this.config.publicFormat
|
|
101
|
-
this.config.publicType
|
|
102
|
-
this.config.privateFormat
|
|
103
|
-
this.config.privateType
|
|
105
|
+
coerceToNumeric(this.config.publicFormat),
|
|
106
|
+
coerceToNumeric(this.config.publicType),
|
|
107
|
+
coerceToNumeric(this.config.privateFormat),
|
|
108
|
+
coerceToNumeric(this.config.privateType),
|
|
104
109
|
this.config.cipher,
|
|
105
110
|
this.config.passphrase as ArrayBuffer,
|
|
106
111
|
);
|
|
@@ -166,18 +171,86 @@ export function diffieHellman(
|
|
|
166
171
|
options: DiffieHellmanOptions,
|
|
167
172
|
callback?: DiffieHellmanCallback,
|
|
168
173
|
): Buffer | void {
|
|
169
|
-
|
|
174
|
+
if (!options || typeof options !== 'object') {
|
|
175
|
+
throw new TypeError('options must be an object');
|
|
176
|
+
}
|
|
177
|
+
if (callback !== undefined && typeof callback !== 'function') {
|
|
178
|
+
throw new TypeError('callback must be a function');
|
|
179
|
+
}
|
|
170
180
|
|
|
171
|
-
const
|
|
181
|
+
const resolvedOptions: DiffieHellmanOptions = {
|
|
182
|
+
publicKey: resolveDhKeyInput(options.publicKey, 'publicKey'),
|
|
183
|
+
privateKey: resolveDhKeyInput(options.privateKey, 'privateKey'),
|
|
184
|
+
};
|
|
185
|
+
checkDiffieHellmanOptions(resolvedOptions);
|
|
186
|
+
|
|
187
|
+
const privateKey = resolvedOptions.privateKey as PrivateKeyObject;
|
|
172
188
|
const keyType = privateKey.asymmetricKeyType;
|
|
173
189
|
|
|
174
190
|
if (keyType === 'ec') {
|
|
175
|
-
return ecDiffieHellman(
|
|
191
|
+
return ecDiffieHellman(resolvedOptions, callback);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (keyType === 'dh') {
|
|
195
|
+
throw new Error(
|
|
196
|
+
'crypto.diffieHellman with DH KeyObjects is not supported yet — use the DiffieHellman class for now',
|
|
197
|
+
);
|
|
176
198
|
}
|
|
177
199
|
|
|
178
200
|
const type = keyType as CFRGKeyPairType;
|
|
179
201
|
const ed = new Ed(type, {});
|
|
180
|
-
return ed.diffieHellman(
|
|
202
|
+
return ed.diffieHellman(resolvedOptions, callback);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function isRawKeyInput(value: unknown): value is {
|
|
206
|
+
key: ArrayBuffer | ArrayBufferView | string;
|
|
207
|
+
format: 'raw-public' | 'raw-private' | 'raw-seed';
|
|
208
|
+
asymmetricKeyType: string;
|
|
209
|
+
namedCurve?: string;
|
|
210
|
+
} {
|
|
211
|
+
if (!value || typeof value !== 'object') return false;
|
|
212
|
+
const obj = value as { format?: string };
|
|
213
|
+
return (
|
|
214
|
+
obj.format === 'raw-public' ||
|
|
215
|
+
obj.format === 'raw-private' ||
|
|
216
|
+
obj.format === 'raw-seed'
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function resolveDhKeyInput(
|
|
221
|
+
input: DiffieHellmanOptions['publicKey'],
|
|
222
|
+
name: 'publicKey' | 'privateKey',
|
|
223
|
+
): AsymmetricKeyObject {
|
|
224
|
+
if (isRawKeyInput(input)) {
|
|
225
|
+
const expectedKeyType = name === 'publicKey' ? 'public' : 'private';
|
|
226
|
+
if (input.format === 'raw-public' && expectedKeyType !== 'public') {
|
|
227
|
+
throw new Error(`Invalid format 'raw-public' for ${name}`);
|
|
228
|
+
}
|
|
229
|
+
if (
|
|
230
|
+
(input.format === 'raw-private' || input.format === 'raw-seed') &&
|
|
231
|
+
expectedKeyType !== 'private'
|
|
232
|
+
) {
|
|
233
|
+
throw new Error(`Invalid format '${input.format}' for ${name}`);
|
|
234
|
+
}
|
|
235
|
+
if (input.asymmetricKeyType === 'ec' && !input.namedCurve) {
|
|
236
|
+
throw new Error(`namedCurve is required for EC raw key in ${name}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const handle =
|
|
240
|
+
NitroModules.createHybridObject<KeyObjectHandleSpec>('KeyObjectHandle');
|
|
241
|
+
const keyData = toAB(input.key as BinaryLike);
|
|
242
|
+
if (input.format === 'raw-public') {
|
|
243
|
+
handle.initRawPublic(input.asymmetricKeyType, keyData, input.namedCurve);
|
|
244
|
+
return new PublicKeyObject(handle);
|
|
245
|
+
}
|
|
246
|
+
if (input.format === 'raw-seed') {
|
|
247
|
+
handle.initRawSeed(input.asymmetricKeyType, keyData);
|
|
248
|
+
return new PrivateKeyObjectClass(handle);
|
|
249
|
+
}
|
|
250
|
+
handle.initRawPrivate(input.asymmetricKeyType, keyData, input.namedCurve);
|
|
251
|
+
return new PrivateKeyObjectClass(handle);
|
|
252
|
+
}
|
|
253
|
+
return input as AsymmetricKeyObject;
|
|
181
254
|
}
|
|
182
255
|
|
|
183
256
|
function ed_createKeyObjects(ed: Ed): {
|
|
@@ -206,17 +279,19 @@ function ed_formatKeyPairOutput(
|
|
|
206
279
|
ed: Ed,
|
|
207
280
|
encoding: KeyPairGenConfig,
|
|
208
281
|
): {
|
|
209
|
-
publicKey: PublicKeyObject | string | ArrayBuffer;
|
|
210
|
-
privateKey: PrivateKeyObjectClass | string | ArrayBuffer;
|
|
282
|
+
publicKey: PublicKeyObject | string | ArrayBuffer | Buffer;
|
|
283
|
+
privateKey: PrivateKeyObjectClass | string | ArrayBuffer | Buffer;
|
|
211
284
|
} {
|
|
212
285
|
const { publicFormat, privateFormat, cipher, passphrase } = encoding;
|
|
213
286
|
const { pub, priv } = ed_createKeyObjects(ed);
|
|
214
287
|
|
|
215
|
-
let publicKey: PublicKeyObject | string | ArrayBuffer;
|
|
216
|
-
let privateKey: PrivateKeyObjectClass | string | ArrayBuffer;
|
|
288
|
+
let publicKey: PublicKeyObject | string | ArrayBuffer | Buffer;
|
|
289
|
+
let privateKey: PrivateKeyObjectClass | string | ArrayBuffer | Buffer;
|
|
217
290
|
|
|
218
291
|
if (publicFormat == null || publicFormat === -1) {
|
|
219
292
|
publicKey = pub;
|
|
293
|
+
} else if (publicFormat === 'raw-public') {
|
|
294
|
+
publicKey = Buffer.from(pub.handle.exportRawPublic());
|
|
220
295
|
} else {
|
|
221
296
|
const format =
|
|
222
297
|
publicFormat === KFormatType.PEM ? KFormatType.PEM : KFormatType.DER;
|
|
@@ -230,6 +305,10 @@ function ed_formatKeyPairOutput(
|
|
|
230
305
|
|
|
231
306
|
if (privateFormat == null || privateFormat === -1) {
|
|
232
307
|
privateKey = priv;
|
|
308
|
+
} else if (privateFormat === 'raw-private') {
|
|
309
|
+
privateKey = Buffer.from(priv.handle.exportRawPrivate());
|
|
310
|
+
} else if (privateFormat === 'raw-seed') {
|
|
311
|
+
privateKey = Buffer.from(priv.handle.exportRawSeed());
|
|
233
312
|
} else {
|
|
234
313
|
const format =
|
|
235
314
|
privateFormat === KFormatType.PEM ? KFormatType.PEM : KFormatType.DER;
|
package/src/hash.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { NitroModules } from 'react-native-nitro-modules';
|
|
|
3
3
|
import type { TransformOptions } from 'readable-stream';
|
|
4
4
|
import { Buffer } from '@craftzdog/react-native-buffer';
|
|
5
5
|
import type { Hash as NativeHash } from './specs/hash.nitro';
|
|
6
|
+
import type { TurboShake as NativeTurboShake } from './specs/turboshake.nitro';
|
|
6
7
|
import type {
|
|
7
8
|
BinaryLike,
|
|
8
9
|
Encoding,
|
|
@@ -267,19 +268,33 @@ export const asyncDigest = async (
|
|
|
267
268
|
}
|
|
268
269
|
|
|
269
270
|
if (name === 'cSHAKE128' || name === 'cSHAKE256') {
|
|
270
|
-
|
|
271
|
+
// CShakeParams.outputLength is required (in bits) per the WICG modern-algos
|
|
272
|
+
// spec, renamed from `length` (commit ab8dc2b84c2). Mirror Node's
|
|
273
|
+
// hash.js:223-228 / webidl.js:570-595.
|
|
274
|
+
if (
|
|
275
|
+
typeof algorithm.outputLength !== 'number' ||
|
|
276
|
+
algorithm.outputLength <= 0
|
|
277
|
+
) {
|
|
271
278
|
throw lazyDOMException(
|
|
272
|
-
'
|
|
279
|
+
'CShakeParams.outputLength is required',
|
|
273
280
|
'OperationError',
|
|
274
281
|
);
|
|
275
282
|
}
|
|
276
|
-
if (algorithm.
|
|
283
|
+
if (algorithm.outputLength % 8) {
|
|
277
284
|
throw lazyDOMException(
|
|
278
|
-
'Unsupported CShakeParams
|
|
285
|
+
'Unsupported CShakeParams outputLength',
|
|
279
286
|
'NotSupportedError',
|
|
280
287
|
);
|
|
281
288
|
}
|
|
282
|
-
return internalDigest(algorithm, data, algorithm.
|
|
289
|
+
return internalDigest(algorithm, data, algorithm.outputLength / 8);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (name === 'TurboSHAKE128' || name === 'TurboSHAKE256') {
|
|
293
|
+
return turboShakeDigest(name, algorithm, data);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (name === 'KT128' || name === 'KT256') {
|
|
297
|
+
return kangarooTwelveDigest(name, algorithm, data);
|
|
283
298
|
}
|
|
284
299
|
|
|
285
300
|
throw lazyDOMException(
|
|
@@ -288,6 +303,94 @@ export const asyncDigest = async (
|
|
|
288
303
|
);
|
|
289
304
|
};
|
|
290
305
|
|
|
306
|
+
// TurboSHAKE / KangarooTwelve are not exposed by OpenSSL EVP, so we route
|
|
307
|
+
// them to a dedicated Nitro module (cpp/turboshake) that ports the Node.js
|
|
308
|
+
// reference implementation. Lazy-load to keep the module out of the hot path
|
|
309
|
+
// for callers that only use SHA-2/SHA-3.
|
|
310
|
+
let nativeTurboShake: NativeTurboShake | undefined;
|
|
311
|
+
const getTurboShake = (): NativeTurboShake => {
|
|
312
|
+
if (!nativeTurboShake) {
|
|
313
|
+
nativeTurboShake =
|
|
314
|
+
NitroModules.createHybridObject<NativeTurboShake>('TurboShake');
|
|
315
|
+
}
|
|
316
|
+
return nativeTurboShake;
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
// RFC 9861 §2.2 default per the WICG Modern Algos draft for TurboSHAKE.
|
|
320
|
+
const kDefaultTurboShakeDomainSeparation = 0x1f;
|
|
321
|
+
|
|
322
|
+
const turboShakeDigest = async (
|
|
323
|
+
name: 'TurboSHAKE128' | 'TurboSHAKE256',
|
|
324
|
+
algorithm: SubtleAlgorithm,
|
|
325
|
+
data: BufferLike,
|
|
326
|
+
): Promise<ArrayBuffer> => {
|
|
327
|
+
if (
|
|
328
|
+
typeof algorithm.outputLength !== 'number' ||
|
|
329
|
+
algorithm.outputLength <= 0
|
|
330
|
+
) {
|
|
331
|
+
throw lazyDOMException(
|
|
332
|
+
'TurboShakeParams.outputLength is required',
|
|
333
|
+
'OperationError',
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
if (algorithm.outputLength % 8) {
|
|
337
|
+
throw lazyDOMException(
|
|
338
|
+
'Invalid TurboShakeParams outputLength',
|
|
339
|
+
'OperationError',
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
const ds = algorithm.domainSeparation ?? kDefaultTurboShakeDomainSeparation;
|
|
343
|
+
if (
|
|
344
|
+
typeof ds !== 'number' ||
|
|
345
|
+
!Number.isInteger(ds) ||
|
|
346
|
+
ds < 0x01 ||
|
|
347
|
+
ds > 0x7f
|
|
348
|
+
) {
|
|
349
|
+
throw lazyDOMException(
|
|
350
|
+
'TurboShakeParams.domainSeparation must be in range 0x01-0x7f',
|
|
351
|
+
'OperationError',
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
return getTurboShake().turboShake(
|
|
355
|
+
name,
|
|
356
|
+
ds,
|
|
357
|
+
algorithm.outputLength / 8,
|
|
358
|
+
bufferLikeToArrayBuffer(data),
|
|
359
|
+
);
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
const kangarooTwelveDigest = async (
|
|
363
|
+
name: 'KT128' | 'KT256',
|
|
364
|
+
algorithm: SubtleAlgorithm,
|
|
365
|
+
data: BufferLike,
|
|
366
|
+
): Promise<ArrayBuffer> => {
|
|
367
|
+
if (
|
|
368
|
+
typeof algorithm.outputLength !== 'number' ||
|
|
369
|
+
algorithm.outputLength <= 0
|
|
370
|
+
) {
|
|
371
|
+
throw lazyDOMException(
|
|
372
|
+
'KangarooTwelveParams.outputLength is required',
|
|
373
|
+
'OperationError',
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
if (algorithm.outputLength % 8) {
|
|
377
|
+
throw lazyDOMException(
|
|
378
|
+
'Invalid KangarooTwelveParams outputLength',
|
|
379
|
+
'OperationError',
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
const customization =
|
|
383
|
+
algorithm.customization !== undefined
|
|
384
|
+
? bufferLikeToArrayBuffer(algorithm.customization)
|
|
385
|
+
: undefined;
|
|
386
|
+
return getTurboShake().kangarooTwelve(
|
|
387
|
+
name,
|
|
388
|
+
algorithm.outputLength / 8,
|
|
389
|
+
bufferLikeToArrayBuffer(data),
|
|
390
|
+
customization,
|
|
391
|
+
);
|
|
392
|
+
};
|
|
393
|
+
|
|
291
394
|
const internalDigest = (
|
|
292
395
|
algorithm: SubtleAlgorithm,
|
|
293
396
|
data: BufferLike,
|
package/src/keys/classes.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Buffer } from 'buffer';
|
|
1
|
+
import { Buffer } from '@craftzdog/react-native-buffer';
|
|
2
2
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
3
3
|
import type {
|
|
4
4
|
AsymmetricKeyType,
|
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
KeyUsage,
|
|
10
10
|
SubtleAlgorithm,
|
|
11
11
|
} from '../utils';
|
|
12
|
-
import { KeyType, KFormatType, KeyEncoding } from '../utils';
|
|
12
|
+
import { KeyType, KFormatType, KeyEncoding, getSortedUsages } from '../utils';
|
|
13
13
|
import { parsePrivateKeyEncoding, parsePublicKeyEncoding } from './utils';
|
|
14
14
|
|
|
15
15
|
export class CryptoKey {
|
|
@@ -30,7 +30,8 @@ export class CryptoKey {
|
|
|
30
30
|
) {
|
|
31
31
|
this.keyObject = keyObject;
|
|
32
32
|
this.keyAlgorithm = keyAlgorithm;
|
|
33
|
-
|
|
33
|
+
// Frozen so external code can't mutate `key.usages` (per WebCrypto spec).
|
|
34
|
+
this.keyUsages = Object.freeze(getSortedUsages(keyUsages)) as KeyUsage[];
|
|
34
35
|
this.keyExtractable = keyExtractable;
|
|
35
36
|
}
|
|
36
37
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -286,15 +287,36 @@ export class PublicKeyObject extends AsymmetricKeyObject {
|
|
|
286
287
|
export(options: { format: 'pem' } & EncodingOptions): string;
|
|
287
288
|
export(options: { format: 'der' } & EncodingOptions): Buffer;
|
|
288
289
|
export(options: { format: 'jwk' } & EncodingOptions): JWK;
|
|
290
|
+
export(options: { format: 'raw-public' } & EncodingOptions): Buffer;
|
|
289
291
|
export(options: EncodingOptions): string | Buffer | JWK {
|
|
290
292
|
if (options?.format === 'jwk') {
|
|
291
293
|
return this.handle.exportJwk({}, false);
|
|
292
294
|
}
|
|
295
|
+
if (options?.format === 'raw-public') {
|
|
296
|
+
if (this.asymmetricKeyType === 'ec') {
|
|
297
|
+
const pointType = options.type ?? 'uncompressed';
|
|
298
|
+
if (pointType !== 'compressed' && pointType !== 'uncompressed') {
|
|
299
|
+
throw new Error(
|
|
300
|
+
`Invalid options.type for raw-public EC export: ${pointType}`,
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
return Buffer.from(
|
|
304
|
+
this.handle.exportECPublicRaw(pointType === 'compressed'),
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
return Buffer.from(this.handle.exportRawPublic());
|
|
308
|
+
}
|
|
293
309
|
const { format, type } = parsePublicKeyEncoding(
|
|
294
310
|
options,
|
|
295
311
|
this.asymmetricKeyType,
|
|
296
312
|
);
|
|
297
|
-
|
|
313
|
+
if (typeof format !== 'number') {
|
|
314
|
+
throw new Error(`Unexpected format ${format} after raw-format dispatch`);
|
|
315
|
+
}
|
|
316
|
+
const key = this.handle.exportKey(
|
|
317
|
+
format,
|
|
318
|
+
typeof type === 'string' ? undefined : type,
|
|
319
|
+
);
|
|
298
320
|
const buffer = Buffer.from(key);
|
|
299
321
|
if (options?.format === 'pem') {
|
|
300
322
|
return buffer.toString('utf-8');
|
|
@@ -311,6 +333,8 @@ export class PrivateKeyObject extends AsymmetricKeyObject {
|
|
|
311
333
|
export(options: { format: 'pem' } & EncodingOptions): string;
|
|
312
334
|
export(options: { format: 'der' } & EncodingOptions): Buffer;
|
|
313
335
|
export(options: { format: 'jwk' } & EncodingOptions): JWK;
|
|
336
|
+
export(options: { format: 'raw-private' } & EncodingOptions): Buffer;
|
|
337
|
+
export(options: { format: 'raw-seed' } & EncodingOptions): Buffer;
|
|
314
338
|
export(options: EncodingOptions): string | Buffer | JWK {
|
|
315
339
|
if (options?.format === 'jwk') {
|
|
316
340
|
if (options.passphrase !== undefined) {
|
|
@@ -318,11 +342,28 @@ export class PrivateKeyObject extends AsymmetricKeyObject {
|
|
|
318
342
|
}
|
|
319
343
|
return this.handle.exportJwk({}, false);
|
|
320
344
|
}
|
|
345
|
+
if (options?.format === 'raw-private') {
|
|
346
|
+
if (this.asymmetricKeyType === 'ec') {
|
|
347
|
+
return Buffer.from(this.handle.exportECPrivateRaw());
|
|
348
|
+
}
|
|
349
|
+
return Buffer.from(this.handle.exportRawPrivate());
|
|
350
|
+
}
|
|
351
|
+
if (options?.format === 'raw-seed') {
|
|
352
|
+
return Buffer.from(this.handle.exportRawSeed());
|
|
353
|
+
}
|
|
321
354
|
const { format, type, cipher, passphrase } = parsePrivateKeyEncoding(
|
|
322
355
|
options,
|
|
323
356
|
this.asymmetricKeyType,
|
|
324
357
|
);
|
|
325
|
-
|
|
358
|
+
if (typeof format !== 'number') {
|
|
359
|
+
throw new Error(`Unexpected format ${format} after raw-format dispatch`);
|
|
360
|
+
}
|
|
361
|
+
const key = this.handle.exportKey(
|
|
362
|
+
format,
|
|
363
|
+
typeof type === 'string' ? undefined : type,
|
|
364
|
+
cipher,
|
|
365
|
+
passphrase,
|
|
366
|
+
);
|
|
326
367
|
const buffer = Buffer.from(key);
|
|
327
368
|
if (options?.format === 'pem') {
|
|
328
369
|
return buffer.toString('utf-8');
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ed_generateKeyPair } from '../ed';
|
|
2
|
+
import { Buffer } from '@craftzdog/react-native-buffer';
|
|
2
3
|
import { rsa_generateKeyPairNode, rsa_generateKeyPairNodeSync } from '../rsa';
|
|
3
4
|
import { ec_generateKeyPairNode, ec_generateKeyPairNodeSync } from '../ec';
|
|
4
5
|
import { dsa_generateKeyPairNode, dsa_generateKeyPairNodeSync } from '../dsa';
|
|
@@ -6,6 +7,7 @@ import {
|
|
|
6
7
|
dh_generateKeyPairNode,
|
|
7
8
|
dh_generateKeyPairNodeSync,
|
|
8
9
|
} from '../dhKeyPair';
|
|
10
|
+
import { SlhDsa, type SlhDsaVariant } from '../slhdsa';
|
|
9
11
|
import {
|
|
10
12
|
kEmptyObject,
|
|
11
13
|
validateFunction,
|
|
@@ -17,9 +19,129 @@ import {
|
|
|
17
19
|
type KeyPairGenConfig,
|
|
18
20
|
type KeyPairKey,
|
|
19
21
|
type KeyPairType,
|
|
22
|
+
type SlhDsaKeyPairType,
|
|
23
|
+
KFormatType,
|
|
24
|
+
KeyEncoding,
|
|
20
25
|
} from '../utils';
|
|
26
|
+
import {
|
|
27
|
+
KeyObject,
|
|
28
|
+
type PublicKeyObject,
|
|
29
|
+
type PrivateKeyObject,
|
|
30
|
+
} from './classes';
|
|
21
31
|
import { parsePrivateKeyEncoding, parsePublicKeyEncoding } from './utils';
|
|
22
32
|
|
|
33
|
+
const SLH_DSA_TYPE_TO_VARIANT: Readonly<
|
|
34
|
+
Record<SlhDsaKeyPairType, SlhDsaVariant>
|
|
35
|
+
> = {
|
|
36
|
+
'slh-dsa-sha2-128s': 'SLH-DSA-SHA2-128s',
|
|
37
|
+
'slh-dsa-sha2-128f': 'SLH-DSA-SHA2-128f',
|
|
38
|
+
'slh-dsa-sha2-192s': 'SLH-DSA-SHA2-192s',
|
|
39
|
+
'slh-dsa-sha2-192f': 'SLH-DSA-SHA2-192f',
|
|
40
|
+
'slh-dsa-sha2-256s': 'SLH-DSA-SHA2-256s',
|
|
41
|
+
'slh-dsa-sha2-256f': 'SLH-DSA-SHA2-256f',
|
|
42
|
+
'slh-dsa-shake-128s': 'SLH-DSA-SHAKE-128s',
|
|
43
|
+
'slh-dsa-shake-128f': 'SLH-DSA-SHAKE-128f',
|
|
44
|
+
'slh-dsa-shake-192s': 'SLH-DSA-SHAKE-192s',
|
|
45
|
+
'slh-dsa-shake-192f': 'SLH-DSA-SHAKE-192f',
|
|
46
|
+
'slh-dsa-shake-256s': 'SLH-DSA-SHAKE-256s',
|
|
47
|
+
'slh-dsa-shake-256f': 'SLH-DSA-SHAKE-256f',
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
function isSlhDsaType(type: string): type is SlhDsaKeyPairType {
|
|
51
|
+
return type in SLH_DSA_TYPE_TO_VARIANT;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function slhDsaFormatKeyPairOutput(
|
|
55
|
+
slhdsa: SlhDsa,
|
|
56
|
+
encoding: KeyPairGenConfig,
|
|
57
|
+
): {
|
|
58
|
+
publicKey: PublicKeyObject | string | ArrayBuffer | Buffer;
|
|
59
|
+
privateKey: PrivateKeyObject | string | ArrayBuffer | Buffer;
|
|
60
|
+
} {
|
|
61
|
+
const { publicFormat, privateFormat, cipher, passphrase } = encoding;
|
|
62
|
+
|
|
63
|
+
const publicKey = KeyObject.createKeyObject(
|
|
64
|
+
'public',
|
|
65
|
+
slhdsa.getPublicKey(),
|
|
66
|
+
KFormatType.DER,
|
|
67
|
+
KeyEncoding.SPKI,
|
|
68
|
+
) as PublicKeyObject;
|
|
69
|
+
const privateKey = KeyObject.createKeyObject(
|
|
70
|
+
'private',
|
|
71
|
+
slhdsa.getPrivateKey(),
|
|
72
|
+
KFormatType.DER,
|
|
73
|
+
KeyEncoding.PKCS8,
|
|
74
|
+
) as PrivateKeyObject;
|
|
75
|
+
|
|
76
|
+
let publicKeyOutput: PublicKeyObject | string | ArrayBuffer | Buffer;
|
|
77
|
+
let privateKeyOutput: PrivateKeyObject | string | ArrayBuffer | Buffer;
|
|
78
|
+
|
|
79
|
+
if (publicFormat === -1) {
|
|
80
|
+
publicKeyOutput = publicKey;
|
|
81
|
+
} else if (publicFormat === 'raw-public') {
|
|
82
|
+
publicKeyOutput = Buffer.from(publicKey.handle.exportRawPublic());
|
|
83
|
+
} else {
|
|
84
|
+
const format =
|
|
85
|
+
publicFormat === KFormatType.PEM ? KFormatType.PEM : KFormatType.DER;
|
|
86
|
+
const exported = publicKey.handle.exportKey(format, KeyEncoding.SPKI);
|
|
87
|
+
if (format === KFormatType.PEM) {
|
|
88
|
+
publicKeyOutput = Buffer.from(new Uint8Array(exported)).toString('utf-8');
|
|
89
|
+
} else {
|
|
90
|
+
publicKeyOutput = exported;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (privateFormat === -1) {
|
|
95
|
+
privateKeyOutput = privateKey;
|
|
96
|
+
} else if (privateFormat === 'raw-private') {
|
|
97
|
+
privateKeyOutput = Buffer.from(privateKey.handle.exportRawPrivate());
|
|
98
|
+
} else if (privateFormat === 'raw-seed') {
|
|
99
|
+
privateKeyOutput = Buffer.from(privateKey.handle.exportRawSeed());
|
|
100
|
+
} else {
|
|
101
|
+
const format =
|
|
102
|
+
privateFormat === KFormatType.PEM ? KFormatType.PEM : KFormatType.DER;
|
|
103
|
+
const exported = privateKey.handle.exportKey(
|
|
104
|
+
format,
|
|
105
|
+
KeyEncoding.PKCS8,
|
|
106
|
+
cipher,
|
|
107
|
+
passphrase,
|
|
108
|
+
);
|
|
109
|
+
if (format === KFormatType.PEM) {
|
|
110
|
+
privateKeyOutput = Buffer.from(new Uint8Array(exported)).toString(
|
|
111
|
+
'utf-8',
|
|
112
|
+
);
|
|
113
|
+
} else {
|
|
114
|
+
privateKeyOutput = exported;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return { publicKey: publicKeyOutput, privateKey: privateKeyOutput };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function slhDsaGenerateKeyPairNodeSync(
|
|
122
|
+
type: SlhDsaKeyPairType,
|
|
123
|
+
encoding: KeyPairGenConfig,
|
|
124
|
+
): {
|
|
125
|
+
publicKey: PublicKeyObject | string | ArrayBuffer | Buffer;
|
|
126
|
+
privateKey: PrivateKeyObject | string | ArrayBuffer | Buffer;
|
|
127
|
+
} {
|
|
128
|
+
const slhdsa = new SlhDsa(SLH_DSA_TYPE_TO_VARIANT[type]);
|
|
129
|
+
slhdsa.generateKeyPairSync();
|
|
130
|
+
return slhDsaFormatKeyPairOutput(slhdsa, encoding);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async function slhDsaGenerateKeyPairNode(
|
|
134
|
+
type: SlhDsaKeyPairType,
|
|
135
|
+
encoding: KeyPairGenConfig,
|
|
136
|
+
): Promise<{
|
|
137
|
+
publicKey: PublicKeyObject | string | ArrayBuffer | Buffer;
|
|
138
|
+
privateKey: PrivateKeyObject | string | ArrayBuffer | Buffer;
|
|
139
|
+
}> {
|
|
140
|
+
const slhdsa = new SlhDsa(SLH_DSA_TYPE_TO_VARIANT[type]);
|
|
141
|
+
await slhdsa.generateKeyPair();
|
|
142
|
+
return slhDsaFormatKeyPairOutput(slhdsa, encoding);
|
|
143
|
+
}
|
|
144
|
+
|
|
23
145
|
export const generateKeyPair = (
|
|
24
146
|
type: KeyPairType,
|
|
25
147
|
options: GenerateKeyPairOptions,
|
|
@@ -47,7 +169,24 @@ export const generateKeyPairPromise = (
|
|
|
47
169
|
};
|
|
48
170
|
|
|
49
171
|
// generateKeyPairSync
|
|
50
|
-
export
|
|
172
|
+
export type KeyObjectKeyPair = {
|
|
173
|
+
publicKey: PublicKeyObject;
|
|
174
|
+
privateKey: PrivateKeyObject;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
type KeyObjectGenerateKeyPairOptions = Omit<
|
|
178
|
+
GenerateKeyPairOptions,
|
|
179
|
+
'publicKeyEncoding' | 'privateKeyEncoding'
|
|
180
|
+
> & {
|
|
181
|
+
publicKeyEncoding?: undefined;
|
|
182
|
+
privateKeyEncoding?: undefined;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
export function generateKeyPairSync(type: KeyPairType): KeyObjectKeyPair;
|
|
186
|
+
export function generateKeyPairSync(
|
|
187
|
+
type: KeyPairType,
|
|
188
|
+
options: KeyObjectGenerateKeyPairOptions,
|
|
189
|
+
): KeyObjectKeyPair;
|
|
51
190
|
export function generateKeyPairSync(
|
|
52
191
|
type: KeyPairType,
|
|
53
192
|
options: GenerateKeyPairOptions,
|
|
@@ -117,10 +256,10 @@ function parseKeyPairEncoding(
|
|
|
117
256
|
}
|
|
118
257
|
|
|
119
258
|
return {
|
|
120
|
-
publicFormat,
|
|
121
|
-
publicType,
|
|
122
|
-
privateFormat,
|
|
123
|
-
privateType,
|
|
259
|
+
publicFormat: publicFormat as KeyPairGenConfig['publicFormat'],
|
|
260
|
+
publicType: publicType as KeyPairGenConfig['publicType'],
|
|
261
|
+
privateFormat: privateFormat as KeyPairGenConfig['privateFormat'],
|
|
262
|
+
privateType: privateType as KeyPairGenConfig['privateType'],
|
|
124
263
|
cipher,
|
|
125
264
|
passphrase,
|
|
126
265
|
};
|
|
@@ -147,6 +286,9 @@ function internalGenerateKeyPair(
|
|
|
147
286
|
case 'dh':
|
|
148
287
|
break;
|
|
149
288
|
default: {
|
|
289
|
+
if (isSlhDsaType(type)) {
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
150
292
|
const err = new Error(`
|
|
151
293
|
Invalid Argument options: '${type}' scheme not supported for
|
|
152
294
|
generateKeyPair(). Currently not all encryption methods are supported in
|
|
@@ -168,6 +310,8 @@ function internalGenerateKeyPair(
|
|
|
168
310
|
result = await dsa_generateKeyPairNode(options, encoding);
|
|
169
311
|
} else if (type === 'dh') {
|
|
170
312
|
result = await dh_generateKeyPairNode(options, encoding);
|
|
313
|
+
} else if (isSlhDsaType(type)) {
|
|
314
|
+
result = await slhDsaGenerateKeyPairNode(type, encoding);
|
|
171
315
|
} else {
|
|
172
316
|
throw new Error(`Unsupported key type: ${type}`);
|
|
173
317
|
}
|
|
@@ -198,6 +342,8 @@ function internalGenerateKeyPair(
|
|
|
198
342
|
result = dsa_generateKeyPairNodeSync(options, encoding);
|
|
199
343
|
} else if (type === 'dh') {
|
|
200
344
|
result = dh_generateKeyPairNodeSync(options, encoding);
|
|
345
|
+
} else if (isSlhDsaType(type)) {
|
|
346
|
+
result = slhDsaGenerateKeyPairNodeSync(type, encoding);
|
|
201
347
|
} else {
|
|
202
348
|
throw new Error(`Unsupported key type: ${type}`);
|
|
203
349
|
}
|