react-native-quick-crypto 1.0.2 → 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.
- package/QuickCrypto.podspec +1 -0
- package/README.md +1 -1
- package/android/CMakeLists.txt +4 -0
- package/cpp/hkdf/HybridHkdf.cpp +96 -0
- package/cpp/hkdf/HybridHkdf.hpp +28 -0
- package/cpp/scrypt/HybridScrypt.cpp +62 -0
- package/cpp/scrypt/HybridScrypt.hpp +28 -0
- package/lib/commonjs/hkdf.js +81 -0
- package/lib/commonjs/hkdf.js.map +1 -0
- package/lib/commonjs/index.js +33 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/scrypt.js +98 -0
- package/lib/commonjs/scrypt.js.map +1 -0
- package/lib/commonjs/specs/hkdf.nitro.js +6 -0
- package/lib/commonjs/specs/hkdf.nitro.js.map +1 -0
- package/lib/commonjs/specs/scrypt.nitro.js +6 -0
- package/lib/commonjs/specs/scrypt.nitro.js.map +1 -0
- package/lib/commonjs/subtle.js +28 -0
- package/lib/commonjs/subtle.js.map +1 -1
- package/lib/module/hkdf.js +75 -0
- package/lib/module/hkdf.js.map +1 -0
- package/lib/module/index.js +13 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/scrypt.js +93 -0
- package/lib/module/scrypt.js.map +1 -0
- package/lib/module/specs/hkdf.nitro.js +4 -0
- package/lib/module/specs/hkdf.nitro.js.map +1 -0
- package/lib/module/specs/scrypt.nitro.js +4 -0
- package/lib/module/specs/scrypt.nitro.js.map +1 -0
- package/lib/module/subtle.js +28 -0
- package/lib/module/subtle.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/typescript/hkdf.d.ts +26 -0
- package/lib/typescript/hkdf.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +9 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/scrypt.d.ts +18 -0
- package/lib/typescript/scrypt.d.ts.map +1 -0
- package/lib/typescript/specs/hkdf.nitro.d.ts +9 -0
- package/lib/typescript/specs/hkdf.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/scrypt.nitro.d.ts +9 -0
- package/lib/typescript/specs/scrypt.nitro.d.ts.map +1 -0
- package/lib/typescript/subtle.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++/HybridHkdfSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridHkdfSpec.hpp +66 -0
- package/nitrogen/generated/shared/c++/HybridScryptSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridScryptSpec.hpp +65 -0
- package/package.json +1 -1
- package/src/hkdf.ts +152 -0
- package/src/index.ts +13 -1
- package/src/scrypt.ts +134 -0
- package/src/specs/hkdf.nitro.ts +19 -0
- package/src/specs/scrypt.nitro.ts +23 -0
- package/src/subtle.ts +45 -0
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
|
+
}
|
package/src/subtle.ts
CHANGED
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
Ed,
|
|
50
50
|
} from './ed';
|
|
51
51
|
import { mldsa_generateKeyPairWebCrypto, type MlDsaVariant } from './mldsa';
|
|
52
|
+
import { hkdfDeriveBits, type HkdfAlgorithm } from './hkdf';
|
|
52
53
|
// import { pbkdf2DeriveBits } from './pbkdf2';
|
|
53
54
|
// import { aesCipher, aesGenerateKey, aesImportKey, getAlgorithmName } from './aes';
|
|
54
55
|
// import { rsaCipher, rsaExportKey, rsaImportKey, rsaKeyGenerate } from './rsa';
|
|
@@ -1235,6 +1236,28 @@ const importGenericSecretKey = async (
|
|
|
1235
1236
|
throw new Error(`Unable to import ${name} key with format ${format}`);
|
|
1236
1237
|
};
|
|
1237
1238
|
|
|
1239
|
+
const hkdfImportKey = async (
|
|
1240
|
+
format: ImportFormat,
|
|
1241
|
+
keyData: BufferLike | BinaryLike,
|
|
1242
|
+
algorithm: SubtleAlgorithm,
|
|
1243
|
+
extractable: boolean,
|
|
1244
|
+
keyUsages: KeyUsage[],
|
|
1245
|
+
): Promise<CryptoKey> => {
|
|
1246
|
+
const { name } = algorithm;
|
|
1247
|
+
if (hasAnyNotIn(keyUsages, ['deriveKey', 'deriveBits'])) {
|
|
1248
|
+
throw new Error(`Unsupported key usage for a ${name} key`);
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
switch (format) {
|
|
1252
|
+
case 'raw': {
|
|
1253
|
+
const keyObject = createSecretKey(keyData as BinaryLike);
|
|
1254
|
+
return new CryptoKey(keyObject, { name }, keyUsages, extractable);
|
|
1255
|
+
}
|
|
1256
|
+
default:
|
|
1257
|
+
throw new Error(`Unable to import ${name} key with format ${format}`);
|
|
1258
|
+
}
|
|
1259
|
+
};
|
|
1260
|
+
|
|
1238
1261
|
const checkCryptoKeyPairUsages = (pair: CryptoKeyPair) => {
|
|
1239
1262
|
if (
|
|
1240
1263
|
pair.privateKey &&
|
|
@@ -1536,6 +1559,12 @@ export class Subtle {
|
|
|
1536
1559
|
// Fall through
|
|
1537
1560
|
case 'X448':
|
|
1538
1561
|
return xDeriveBits(algorithm, baseKey, length);
|
|
1562
|
+
case 'HKDF':
|
|
1563
|
+
return hkdfDeriveBits(
|
|
1564
|
+
algorithm as unknown as HkdfAlgorithm,
|
|
1565
|
+
baseKey,
|
|
1566
|
+
length,
|
|
1567
|
+
);
|
|
1539
1568
|
}
|
|
1540
1569
|
throw new Error(
|
|
1541
1570
|
`'subtle.deriveBits()' for ${algorithm.name} is not implemented.`,
|
|
@@ -1577,6 +1606,13 @@ export class Subtle {
|
|
|
1577
1606
|
case 'X448':
|
|
1578
1607
|
derivedBits = await xDeriveBits(algorithm, baseKey, length);
|
|
1579
1608
|
break;
|
|
1609
|
+
case 'HKDF':
|
|
1610
|
+
derivedBits = hkdfDeriveBits(
|
|
1611
|
+
algorithm as unknown as HkdfAlgorithm,
|
|
1612
|
+
baseKey,
|
|
1613
|
+
length,
|
|
1614
|
+
);
|
|
1615
|
+
break;
|
|
1580
1616
|
default:
|
|
1581
1617
|
throw new Error(
|
|
1582
1618
|
`'subtle.deriveKey()' for ${algorithm.name} is not implemented.`,
|
|
@@ -1908,6 +1944,15 @@ export class Subtle {
|
|
|
1908
1944
|
keyUsages,
|
|
1909
1945
|
);
|
|
1910
1946
|
break;
|
|
1947
|
+
case 'HKDF':
|
|
1948
|
+
result = await hkdfImportKey(
|
|
1949
|
+
format,
|
|
1950
|
+
data as BufferLike | BinaryLike,
|
|
1951
|
+
normalizedAlgorithm,
|
|
1952
|
+
extractable,
|
|
1953
|
+
keyUsages,
|
|
1954
|
+
);
|
|
1955
|
+
break;
|
|
1911
1956
|
case 'X25519':
|
|
1912
1957
|
// Fall through
|
|
1913
1958
|
case 'X448':
|