react-native-quick-crypto 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/QuickCrypto.podspec +6 -47
  2. package/README.md +1 -1
  3. package/android/CMakeLists.txt +4 -0
  4. package/cpp/cipher/HybridCipher.cpp +17 -1
  5. package/cpp/ed25519/HybridEdKeyPair.cpp +8 -2
  6. package/cpp/hkdf/HybridHkdf.cpp +96 -0
  7. package/cpp/hkdf/HybridHkdf.hpp +28 -0
  8. package/cpp/scrypt/HybridScrypt.cpp +62 -0
  9. package/cpp/scrypt/HybridScrypt.hpp +28 -0
  10. package/lib/commonjs/ed.js +68 -0
  11. package/lib/commonjs/ed.js.map +1 -1
  12. package/lib/commonjs/hkdf.js +81 -0
  13. package/lib/commonjs/hkdf.js.map +1 -0
  14. package/lib/commonjs/index.js +33 -1
  15. package/lib/commonjs/index.js.map +1 -1
  16. package/lib/commonjs/scrypt.js +98 -0
  17. package/lib/commonjs/scrypt.js.map +1 -0
  18. package/lib/commonjs/specs/hkdf.nitro.js +6 -0
  19. package/lib/commonjs/specs/hkdf.nitro.js.map +1 -0
  20. package/lib/commonjs/specs/scrypt.nitro.js +6 -0
  21. package/lib/commonjs/specs/scrypt.nitro.js.map +1 -0
  22. package/lib/commonjs/subtle.js +400 -7
  23. package/lib/commonjs/subtle.js.map +1 -1
  24. package/lib/commonjs/utils/types.js.map +1 -1
  25. package/lib/module/ed.js +66 -0
  26. package/lib/module/ed.js.map +1 -1
  27. package/lib/module/hkdf.js +75 -0
  28. package/lib/module/hkdf.js.map +1 -0
  29. package/lib/module/index.js +13 -1
  30. package/lib/module/index.js.map +1 -1
  31. package/lib/module/scrypt.js +93 -0
  32. package/lib/module/scrypt.js.map +1 -0
  33. package/lib/module/specs/hkdf.nitro.js +4 -0
  34. package/lib/module/specs/hkdf.nitro.js.map +1 -0
  35. package/lib/module/specs/scrypt.nitro.js +4 -0
  36. package/lib/module/specs/scrypt.nitro.js.map +1 -0
  37. package/lib/module/subtle.js +401 -8
  38. package/lib/module/subtle.js.map +1 -1
  39. package/lib/module/utils/types.js.map +1 -1
  40. package/lib/tsconfig.tsbuildinfo +1 -1
  41. package/lib/typescript/ed.d.ts +4 -1
  42. package/lib/typescript/ed.d.ts.map +1 -1
  43. package/lib/typescript/hkdf.d.ts +26 -0
  44. package/lib/typescript/hkdf.d.ts.map +1 -0
  45. package/lib/typescript/index.d.ts +11 -0
  46. package/lib/typescript/index.d.ts.map +1 -1
  47. package/lib/typescript/scrypt.d.ts +18 -0
  48. package/lib/typescript/scrypt.d.ts.map +1 -0
  49. package/lib/typescript/specs/hkdf.nitro.d.ts +9 -0
  50. package/lib/typescript/specs/hkdf.nitro.d.ts.map +1 -0
  51. package/lib/typescript/specs/scrypt.nitro.d.ts +9 -0
  52. package/lib/typescript/specs/scrypt.nitro.d.ts.map +1 -0
  53. package/lib/typescript/subtle.d.ts +4 -1
  54. package/lib/typescript/subtle.d.ts.map +1 -1
  55. package/lib/typescript/utils/types.d.ts +9 -3
  56. package/lib/typescript/utils/types.d.ts.map +1 -1
  57. package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +2 -0
  58. package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +20 -0
  59. package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +20 -0
  60. package/nitrogen/generated/shared/c++/HybridHkdfSpec.cpp +22 -0
  61. package/nitrogen/generated/shared/c++/HybridHkdfSpec.hpp +66 -0
  62. package/nitrogen/generated/shared/c++/HybridScryptSpec.cpp +22 -0
  63. package/nitrogen/generated/shared/c++/HybridScryptSpec.hpp +65 -0
  64. package/package.json +1 -1
  65. package/src/ed.ts +102 -0
  66. package/src/hkdf.ts +152 -0
  67. package/src/index.ts +13 -1
  68. package/src/scrypt.ts +134 -0
  69. package/src/specs/hkdf.nitro.ts +19 -0
  70. package/src/specs/scrypt.nitro.ts +23 -0
  71. package/src/subtle.ts +564 -9
  72. package/src/utils/types.ts +16 -3
package/src/ed.ts CHANGED
@@ -361,3 +361,105 @@ export async function ed_generateKeyPairWebCrypto(
361
361
 
362
362
  return { publicKey, privateKey };
363
363
  }
364
+
365
+ export async function x_generateKeyPairWebCrypto(
366
+ type: 'x25519' | 'x448',
367
+ extractable: boolean,
368
+ keyUsages: KeyUsage[],
369
+ ): Promise<CryptoKeyPair> {
370
+ if (hasAnyNotIn(keyUsages, ['deriveKey', 'deriveBits'])) {
371
+ throw lazyDOMException(`Unsupported key usage for ${type}`, 'SyntaxError');
372
+ }
373
+
374
+ const publicUsages = getUsagesUnion(keyUsages);
375
+ const privateUsages = getUsagesUnion(keyUsages, 'deriveKey', 'deriveBits');
376
+
377
+ if (privateUsages.length === 0) {
378
+ throw lazyDOMException('Usages cannot be empty', 'SyntaxError');
379
+ }
380
+
381
+ // Request DER-encoded SPKI for public key, PKCS8 for private key
382
+ const config = {
383
+ publicFormat: KFormatType.DER,
384
+ publicType: KeyEncoding.SPKI,
385
+ privateFormat: KFormatType.DER,
386
+ privateType: KeyEncoding.PKCS8,
387
+ };
388
+ const ed = new Ed(type, config);
389
+ await ed.generateKeyPair();
390
+
391
+ const algorithmName = type === 'x25519' ? 'X25519' : 'X448';
392
+
393
+ const publicKeyData = ed.getPublicKey();
394
+ const privateKeyData = ed.getPrivateKey();
395
+
396
+ const pub = KeyObject.createKeyObject(
397
+ 'public',
398
+ publicKeyData,
399
+ KFormatType.DER,
400
+ KeyEncoding.SPKI,
401
+ ) as PublicKeyObject;
402
+ const publicKey = new CryptoKey(
403
+ pub,
404
+ { name: algorithmName } as SubtleAlgorithm,
405
+ publicUsages,
406
+ true,
407
+ );
408
+
409
+ const priv = KeyObject.createKeyObject(
410
+ 'private',
411
+ privateKeyData,
412
+ KFormatType.DER,
413
+ KeyEncoding.PKCS8,
414
+ ) as PrivateKeyObjectClass;
415
+ const privateKey = new CryptoKey(
416
+ priv,
417
+ { name: algorithmName } as SubtleAlgorithm,
418
+ privateUsages,
419
+ extractable,
420
+ );
421
+
422
+ return { publicKey, privateKey };
423
+ }
424
+
425
+ export function xDeriveBits(
426
+ algorithm: SubtleAlgorithm,
427
+ baseKey: CryptoKey,
428
+ length: number | null,
429
+ ): ArrayBuffer {
430
+ const publicParams = algorithm as SubtleAlgorithm & { public?: CryptoKey };
431
+ const publicKey = publicParams.public;
432
+
433
+ if (!publicKey) {
434
+ throw new Error('Public key is required for X25519/X448 derivation');
435
+ }
436
+
437
+ if (baseKey.algorithm.name !== publicKey.algorithm.name) {
438
+ throw new Error('Keys must be of the same algorithm');
439
+ }
440
+
441
+ const type = baseKey.algorithm.name.toLowerCase() as 'x25519' | 'x448';
442
+ const ed = new Ed(type, {});
443
+
444
+ // Export raw keys
445
+ const privateKeyBytes = baseKey.keyObject.handle.exportKey();
446
+ const publicKeyBytes = publicKey.keyObject.handle.exportKey();
447
+
448
+ const privateKeyTyped = new Uint8Array(privateKeyBytes);
449
+ const publicKeyTyped = new Uint8Array(publicKeyBytes);
450
+
451
+ const secret = ed.getSharedSecret(privateKeyTyped, publicKeyTyped);
452
+
453
+ // If length is null, return the full secret
454
+ if (length === null) {
455
+ return secret;
456
+ }
457
+
458
+ // If length is specified, truncate
459
+ const byteLength = Math.ceil(length / 8);
460
+ if (secret.byteLength >= byteLength) {
461
+ return secret.slice(0, byteLength);
462
+ }
463
+
464
+ throw new Error('Derived key is shorter than requested length');
465
+ }
package/src/hkdf.ts ADDED
@@ -0,0 +1,152 @@
1
+ import { Buffer } from '@craftzdog/react-native-buffer';
2
+ import { NitroModules } from 'react-native-nitro-modules';
3
+ import type { Hkdf as HkdfNative } from './specs/hkdf.nitro';
4
+ import { binaryLikeToArrayBuffer, normalizeHashName } from './utils';
5
+ import type { BinaryLike } from './utils';
6
+
7
+ type KeyMaterial = BinaryLike;
8
+ type Salt = BinaryLike;
9
+ type Info = BinaryLike;
10
+
11
+ export interface HkdfAlgorithm {
12
+ name: string;
13
+ hash: string | { name: string };
14
+ salt: BinaryLike;
15
+ info: BinaryLike;
16
+ }
17
+
18
+ export interface CryptoKeyInternal {
19
+ keyObject: {
20
+ export: () => Buffer;
21
+ };
22
+ }
23
+
24
+ export interface HkdfCallback {
25
+ (err: Error | null, derivedKey?: Buffer): void;
26
+ }
27
+
28
+ // Lazy load native module
29
+ let native: HkdfNative;
30
+ function getNative(): HkdfNative {
31
+ if (native == null) {
32
+ native = NitroModules.createHybridObject<HkdfNative>('Hkdf');
33
+ }
34
+ return native;
35
+ }
36
+
37
+ function validateCallback(callback: HkdfCallback) {
38
+ if (callback === undefined || typeof callback !== 'function') {
39
+ throw new Error('No callback provided to hkdf');
40
+ }
41
+ }
42
+
43
+ function sanitizeInput(input: BinaryLike, name: string): ArrayBuffer {
44
+ try {
45
+ return binaryLikeToArrayBuffer(input);
46
+ } catch {
47
+ throw new Error(
48
+ `${name} must be a string, a Buffer, a typed array, or a DataView`,
49
+ );
50
+ }
51
+ }
52
+
53
+ export function hkdf(
54
+ digest: string,
55
+ key: KeyMaterial,
56
+ salt: Salt,
57
+ info: Info,
58
+ keylen: number,
59
+ callback: HkdfCallback,
60
+ ): void {
61
+ validateCallback(callback);
62
+
63
+ try {
64
+ const normalizedDigest = normalizeHashName(digest);
65
+ const sanitizedKey = sanitizeInput(key, 'Key');
66
+ const sanitizedSalt = sanitizeInput(salt, 'Salt');
67
+ const sanitizedInfo = sanitizeInput(info, 'Info');
68
+
69
+ if (keylen < 0) {
70
+ throw new TypeError('Bad key length');
71
+ }
72
+
73
+ const nativeMod = getNative();
74
+ nativeMod
75
+ .deriveKey(
76
+ normalizedDigest,
77
+ sanitizedKey,
78
+ sanitizedSalt,
79
+ sanitizedInfo,
80
+ keylen,
81
+ )
82
+ .then(
83
+ res => {
84
+ callback(null, Buffer.from(res));
85
+ },
86
+ err => {
87
+ callback(err);
88
+ },
89
+ );
90
+ } catch (err) {
91
+ callback(err as Error);
92
+ }
93
+ }
94
+
95
+ export function hkdfSync(
96
+ digest: string,
97
+ key: KeyMaterial,
98
+ salt: Salt,
99
+ info: Info,
100
+ keylen: number,
101
+ ): Buffer {
102
+ const normalizedDigest = normalizeHashName(digest);
103
+ const sanitizedKey = sanitizeInput(key, 'Key');
104
+ const sanitizedSalt = sanitizeInput(salt, 'Salt');
105
+ const sanitizedInfo = sanitizeInput(info, 'Info');
106
+
107
+ if (keylen < 0) {
108
+ throw new TypeError('Bad key length');
109
+ }
110
+
111
+ const nativeMod = getNative();
112
+ const result = nativeMod.deriveKeySync(
113
+ normalizedDigest,
114
+ sanitizedKey,
115
+ sanitizedSalt,
116
+ sanitizedInfo,
117
+ keylen,
118
+ );
119
+
120
+ return Buffer.from(result);
121
+ }
122
+
123
+ export function hkdfDeriveBits(
124
+ algorithm: HkdfAlgorithm,
125
+ baseKey: CryptoKeyInternal,
126
+ length: number,
127
+ ): ArrayBuffer {
128
+ const hash = algorithm.hash;
129
+ const salt = algorithm.salt;
130
+ const info = algorithm.info;
131
+
132
+ // Check if key is extractable or we can access its handle/buffer
133
+ // For raw keys, we can export.
134
+ const keyBuffer = baseKey.keyObject.export();
135
+
136
+ // length is in bits, native expects bytes
137
+ const keylen = Math.ceil(length / 8);
138
+
139
+ const hashName = typeof hash === 'string' ? hash : hash.name;
140
+ const normalizedDigest = normalizeHashName(hashName);
141
+
142
+ const nativeMod = getNative();
143
+ const result = nativeMod.deriveKeySync(
144
+ normalizedDigest,
145
+ binaryLikeToArrayBuffer(keyBuffer),
146
+ binaryLikeToArrayBuffer(salt),
147
+ binaryLikeToArrayBuffer(info),
148
+ keylen,
149
+ );
150
+
151
+ return result;
152
+ }
package/src/index.ts CHANGED
@@ -8,7 +8,9 @@ import * as cipher from './cipher';
8
8
  import * as ed from './ed';
9
9
  import { hashExports as hash } from './hash';
10
10
  import { hmacExports as hmac } from './hmac';
11
+ import * as hkdf from './hkdf';
11
12
  import * as pbkdf2 from './pbkdf2';
13
+ import * as scrypt from './scrypt';
12
14
  import * as random from './random';
13
15
  import { constants } from './constants';
14
16
 
@@ -27,7 +29,9 @@ const QuickCrypto = {
27
29
  ...ed,
28
30
  ...hash,
29
31
  ...hmac,
32
+ ...hkdf,
30
33
  ...pbkdf2,
34
+ ...scrypt,
31
35
  ...random,
32
36
  ...utils,
33
37
  ...subtle,
@@ -47,7 +51,13 @@ export const install = () => {
47
51
  };
48
52
 
49
53
  // random, cipher, hash use nextTick
50
- global.process.nextTick = setImmediate;
54
+ if (global.process == null) {
55
+ // @ts-expect-error - process is not defined
56
+ global.process = {};
57
+ }
58
+ if (global.process.nextTick == null) {
59
+ global.process.nextTick = setImmediate;
60
+ }
51
61
 
52
62
  // exports
53
63
  export default QuickCrypto;
@@ -57,7 +67,9 @@ export * from './ed';
57
67
  export * from './keys';
58
68
  export * from './hash';
59
69
  export * from './hmac';
70
+ export * from './hkdf';
60
71
  export * from './pbkdf2';
72
+ export * from './scrypt';
61
73
  export * from './random';
62
74
  export * from './utils';
63
75
  export * from './subtle';
package/src/scrypt.ts ADDED
@@ -0,0 +1,134 @@
1
+ import { Buffer } from '@craftzdog/react-native-buffer';
2
+ import { NitroModules } from 'react-native-nitro-modules';
3
+ import type { Scrypt as NativeScrypt } from './specs/scrypt.nitro';
4
+ import { binaryLikeToArrayBuffer } from './utils';
5
+ import type { BinaryLike } from './utils';
6
+
7
+ type Password = BinaryLike;
8
+ type Salt = BinaryLike;
9
+
10
+ export interface ScryptOptions {
11
+ N?: number;
12
+ r?: number;
13
+ p?: number;
14
+ cost?: number;
15
+ blockSize?: number;
16
+ parallelization?: number;
17
+ maxmem?: number;
18
+ }
19
+
20
+ type ScryptCallback = (err: Error | null, derivedKey?: Buffer) => void;
21
+
22
+ // Lazy load native module
23
+ let native: NativeScrypt;
24
+ function getNative(): NativeScrypt {
25
+ if (native == null) {
26
+ native = NitroModules.createHybridObject<NativeScrypt>('Scrypt');
27
+ }
28
+ return native;
29
+ }
30
+
31
+ const defaults = {
32
+ N: 16384,
33
+ r: 8,
34
+ p: 1,
35
+ maxmem: 32 * 1024 * 1024,
36
+ };
37
+
38
+ function getScryptParams(options?: ScryptOptions) {
39
+ const N = options?.N ?? options?.cost ?? defaults.N;
40
+ const r = options?.r ?? options?.blockSize ?? defaults.r;
41
+ const p = options?.p ?? options?.parallelization ?? defaults.p;
42
+ const maxmem = options?.maxmem ?? defaults.maxmem;
43
+
44
+ return { N, r, p, maxmem };
45
+ }
46
+
47
+ function validateCallback(callback: ScryptCallback) {
48
+ if (callback === undefined || typeof callback !== 'function') {
49
+ throw new Error('No callback provided to scrypt');
50
+ }
51
+ }
52
+
53
+ function sanitizeInput(input: BinaryLike, name: string): ArrayBuffer {
54
+ try {
55
+ return binaryLikeToArrayBuffer(input);
56
+ } catch {
57
+ throw new Error(
58
+ `${name} must be a string, a Buffer, a typed array, or a DataView`,
59
+ );
60
+ }
61
+ }
62
+
63
+ export function scrypt(
64
+ password: Password,
65
+ salt: Salt,
66
+ keylen: number,
67
+ options?: ScryptOptions | ScryptCallback,
68
+ callback?: ScryptCallback,
69
+ ): void {
70
+ let cb: ScryptCallback;
71
+ let opts: ScryptOptions | undefined;
72
+
73
+ if (typeof options === 'function') {
74
+ cb = options;
75
+ opts = undefined;
76
+ } else {
77
+ cb = callback!;
78
+ opts = options;
79
+ }
80
+
81
+ validateCallback(cb);
82
+
83
+ try {
84
+ const { N, r, p, maxmem } = getScryptParams(opts);
85
+ const sanitizedPassword = sanitizeInput(password, 'Password');
86
+ const sanitizedSalt = sanitizeInput(salt, 'Salt');
87
+
88
+ if (keylen < 0) {
89
+ throw new TypeError('Bad key length');
90
+ }
91
+
92
+ const nativeMod = getNative();
93
+ nativeMod
94
+ .deriveKey(sanitizedPassword, sanitizedSalt, N, r, p, maxmem, keylen)
95
+ .then(
96
+ res => {
97
+ cb(null, Buffer.from(res));
98
+ },
99
+ err => {
100
+ cb(err);
101
+ },
102
+ );
103
+ } catch (err) {
104
+ cb(err as Error);
105
+ }
106
+ }
107
+
108
+ export function scryptSync(
109
+ password: Password,
110
+ salt: Salt,
111
+ keylen: number,
112
+ options?: ScryptOptions,
113
+ ): Buffer {
114
+ const { N, r, p, maxmem } = getScryptParams(options);
115
+ const sanitizedPassword = sanitizeInput(password, 'Password');
116
+ const sanitizedSalt = sanitizeInput(salt, 'Salt');
117
+
118
+ if (keylen < 0) {
119
+ throw new TypeError('Bad key length');
120
+ }
121
+
122
+ const nativeMod = getNative();
123
+ const result = nativeMod.deriveKeySync(
124
+ sanitizedPassword,
125
+ sanitizedSalt,
126
+ N,
127
+ r,
128
+ p,
129
+ maxmem,
130
+ keylen,
131
+ );
132
+
133
+ return Buffer.from(result);
134
+ }
@@ -0,0 +1,19 @@
1
+ import type { HybridObject } from 'react-native-nitro-modules';
2
+
3
+ export interface Hkdf extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
4
+ deriveKeySync(
5
+ algorithm: string,
6
+ key: ArrayBuffer,
7
+ salt: ArrayBuffer,
8
+ info: ArrayBuffer,
9
+ length: number,
10
+ ): ArrayBuffer;
11
+
12
+ deriveKey(
13
+ algorithm: string,
14
+ key: ArrayBuffer,
15
+ salt: ArrayBuffer,
16
+ info: ArrayBuffer,
17
+ length: number,
18
+ ): Promise<ArrayBuffer>;
19
+ }
@@ -0,0 +1,23 @@
1
+ import type { HybridObject } from 'react-native-nitro-modules';
2
+
3
+ export interface Scrypt extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
4
+ deriveKey(
5
+ password: ArrayBuffer,
6
+ salt: ArrayBuffer,
7
+ N: number,
8
+ r: number,
9
+ p: number,
10
+ maxmem: number,
11
+ keylen: number,
12
+ ): Promise<ArrayBuffer>;
13
+
14
+ deriveKeySync(
15
+ password: ArrayBuffer,
16
+ salt: ArrayBuffer,
17
+ N: number,
18
+ r: number,
19
+ p: number,
20
+ maxmem: number,
21
+ keylen: number,
22
+ ): ArrayBuffer;
23
+ }