react-native-quick-crypto 1.1.4 → 1.1.6
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 -1
- package/cpp/hkdf/HybridHkdf.cpp +25 -8
- package/cpp/hkdf/HybridHkdf.hpp +3 -2
- package/cpp/keys/HybridKeyObjectHandle.cpp +2 -1
- package/cpp/keys/KeyObjectData.cpp +47 -17
- package/lib/commonjs/hkdf.js +73 -3
- package/lib/commonjs/hkdf.js.map +1 -1
- package/lib/commonjs/keys/classes.js +2 -8
- package/lib/commonjs/keys/classes.js.map +1 -1
- package/lib/commonjs/keys/index.js +13 -7
- package/lib/commonjs/keys/index.js.map +1 -1
- package/lib/module/hkdf.js +69 -3
- package/lib/module/hkdf.js.map +1 -1
- package/lib/module/keys/classes.js +2 -8
- package/lib/module/keys/classes.js.map +1 -1
- package/lib/module/keys/index.js +13 -7
- package/lib/module/keys/index.js.map +1 -1
- package/lib/typescript/hkdf.d.ts +4 -0
- package/lib/typescript/hkdf.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +4 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/keys/classes.d.ts +1 -1
- package/lib/typescript/keys/classes.d.ts.map +1 -1
- package/lib/typescript/keys/index.d.ts.map +1 -1
- package/lib/typescript/specs/hkdf.nitro.d.ts +3 -2
- package/lib/typescript/specs/hkdf.nitro.d.ts.map +1 -1
- package/nitrogen/generated/shared/c++/HkdfMode.hpp +80 -0
- package/nitrogen/generated/shared/c++/HybridHkdfSpec.hpp +5 -3
- package/package.json +1 -1
- package/src/hkdf.ts +142 -0
- package/src/keys/classes.ts +2 -6
- package/src/keys/index.ts +20 -5
- package/src/specs/hkdf.nitro.ts +6 -0
package/src/hkdf.ts
CHANGED
|
@@ -62,6 +62,14 @@ const HKDF_HASH_BYTES: Readonly<Record<string, number>> = {
|
|
|
62
62
|
ripemd160: 20,
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
+
function hkdfHashLen(digest: string): number {
|
|
66
|
+
const hashLen = HKDF_HASH_BYTES[digest.toLowerCase()];
|
|
67
|
+
if (hashLen === undefined) {
|
|
68
|
+
throw new TypeError(`Unsupported HKDF digest: ${digest}`);
|
|
69
|
+
}
|
|
70
|
+
return hashLen;
|
|
71
|
+
}
|
|
72
|
+
|
|
65
73
|
function validateHkdfKeylen(digest: string, keylen: number): void {
|
|
66
74
|
if (
|
|
67
75
|
typeof keylen !== 'number' ||
|
|
@@ -111,6 +119,7 @@ export function hkdf(
|
|
|
111
119
|
sanitizedSalt,
|
|
112
120
|
sanitizedInfo,
|
|
113
121
|
keylen,
|
|
122
|
+
'full',
|
|
114
123
|
)
|
|
115
124
|
.then(
|
|
116
125
|
res => {
|
|
@@ -146,11 +155,143 @@ export function hkdfSync(
|
|
|
146
155
|
sanitizedSalt,
|
|
147
156
|
sanitizedInfo,
|
|
148
157
|
keylen,
|
|
158
|
+
'full',
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
return Buffer.from(result);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// RFC 5869 §2.2 HKDF-Extract (sync): PRK = HMAC(salt, IKM). Salt defaults to
|
|
165
|
+
// a string of HashLen zeros when omitted. Returns a PRK of HashLen bytes.
|
|
166
|
+
export function hkdfExtractSync(
|
|
167
|
+
digest: string,
|
|
168
|
+
ikm: KeyMaterial,
|
|
169
|
+
salt: Salt = new Uint8Array(0),
|
|
170
|
+
): Buffer {
|
|
171
|
+
const normalizedDigest = normalizeHashName(digest);
|
|
172
|
+
const hashLen = hkdfHashLen(normalizedDigest);
|
|
173
|
+
const sanitizedIkm = sanitizeInput(ikm, 'IKM');
|
|
174
|
+
const sanitizedSalt = sanitizeInput(salt, 'Salt');
|
|
175
|
+
|
|
176
|
+
const result = getNative().deriveKeySync(
|
|
177
|
+
normalizedDigest,
|
|
178
|
+
sanitizedIkm,
|
|
179
|
+
sanitizedSalt,
|
|
180
|
+
new ArrayBuffer(0),
|
|
181
|
+
hashLen,
|
|
182
|
+
'extract',
|
|
149
183
|
);
|
|
150
184
|
|
|
151
185
|
return Buffer.from(result);
|
|
152
186
|
}
|
|
153
187
|
|
|
188
|
+
// Async HKDF-Extract, mirroring `hkdf`. Unlike the sync form, `salt` is
|
|
189
|
+
// required here because the callback occupies the trailing argument.
|
|
190
|
+
export function hkdfExtract(
|
|
191
|
+
digest: string,
|
|
192
|
+
ikm: KeyMaterial,
|
|
193
|
+
salt: Salt,
|
|
194
|
+
callback: HkdfCallback,
|
|
195
|
+
): void {
|
|
196
|
+
validateCallback(callback);
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
const normalizedDigest = normalizeHashName(digest);
|
|
200
|
+
const hashLen = hkdfHashLen(normalizedDigest);
|
|
201
|
+
const sanitizedIkm = sanitizeInput(ikm, 'IKM');
|
|
202
|
+
const sanitizedSalt = sanitizeInput(salt, 'Salt');
|
|
203
|
+
|
|
204
|
+
getNative()
|
|
205
|
+
.deriveKey(
|
|
206
|
+
normalizedDigest,
|
|
207
|
+
sanitizedIkm,
|
|
208
|
+
sanitizedSalt,
|
|
209
|
+
new ArrayBuffer(0),
|
|
210
|
+
hashLen,
|
|
211
|
+
'extract',
|
|
212
|
+
)
|
|
213
|
+
.then(
|
|
214
|
+
res => callback(null, Buffer.from(res)),
|
|
215
|
+
err => callback(err),
|
|
216
|
+
);
|
|
217
|
+
} catch (err) {
|
|
218
|
+
callback(err as Error);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// RFC 5869 §2.3 HKDF-Expand (sync): OKM = expand(PRK, info, L). `prk` must be
|
|
223
|
+
// at least HashLen bytes (a pseudorandom key, e.g. from hkdfExtract).
|
|
224
|
+
export function hkdfExpandSync(
|
|
225
|
+
digest: string,
|
|
226
|
+
prk: KeyMaterial,
|
|
227
|
+
info: Info,
|
|
228
|
+
keylen: number,
|
|
229
|
+
): Buffer {
|
|
230
|
+
const normalizedDigest = normalizeHashName(digest);
|
|
231
|
+
const hashLen = hkdfHashLen(normalizedDigest);
|
|
232
|
+
const sanitizedPrk = sanitizeInput(prk, 'PRK');
|
|
233
|
+
if (sanitizedPrk.byteLength < hashLen) {
|
|
234
|
+
throw new RangeError(
|
|
235
|
+
`HKDF-Expand PRK must be at least HashLen (${hashLen}) bytes for ${digest}`,
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
const sanitizedInfo = sanitizeInput(info, 'Info');
|
|
239
|
+
|
|
240
|
+
validateHkdfKeylen(normalizedDigest, keylen);
|
|
241
|
+
|
|
242
|
+
const result = getNative().deriveKeySync(
|
|
243
|
+
normalizedDigest,
|
|
244
|
+
sanitizedPrk,
|
|
245
|
+
new ArrayBuffer(0),
|
|
246
|
+
sanitizedInfo,
|
|
247
|
+
keylen,
|
|
248
|
+
'expand',
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
return Buffer.from(result);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Async HKDF-Expand, mirroring `hkdf`.
|
|
255
|
+
export function hkdfExpand(
|
|
256
|
+
digest: string,
|
|
257
|
+
prk: KeyMaterial,
|
|
258
|
+
info: Info,
|
|
259
|
+
keylen: number,
|
|
260
|
+
callback: HkdfCallback,
|
|
261
|
+
): void {
|
|
262
|
+
validateCallback(callback);
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
const normalizedDigest = normalizeHashName(digest);
|
|
266
|
+
const hashLen = hkdfHashLen(normalizedDigest);
|
|
267
|
+
const sanitizedPrk = sanitizeInput(prk, 'PRK');
|
|
268
|
+
if (sanitizedPrk.byteLength < hashLen) {
|
|
269
|
+
throw new RangeError(
|
|
270
|
+
`HKDF-Expand PRK must be at least HashLen (${hashLen}) bytes for ${digest}`,
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
const sanitizedInfo = sanitizeInput(info, 'Info');
|
|
274
|
+
|
|
275
|
+
validateHkdfKeylen(normalizedDigest, keylen);
|
|
276
|
+
|
|
277
|
+
getNative()
|
|
278
|
+
.deriveKey(
|
|
279
|
+
normalizedDigest,
|
|
280
|
+
sanitizedPrk,
|
|
281
|
+
new ArrayBuffer(0),
|
|
282
|
+
sanitizedInfo,
|
|
283
|
+
keylen,
|
|
284
|
+
'expand',
|
|
285
|
+
)
|
|
286
|
+
.then(
|
|
287
|
+
res => callback(null, Buffer.from(res)),
|
|
288
|
+
err => callback(err),
|
|
289
|
+
);
|
|
290
|
+
} catch (err) {
|
|
291
|
+
callback(err as Error);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
154
295
|
export function hkdfDeriveBits(
|
|
155
296
|
algorithm: HkdfAlgorithm,
|
|
156
297
|
baseKey: CryptoKey,
|
|
@@ -179,6 +320,7 @@ export function hkdfDeriveBits(
|
|
|
179
320
|
binaryLikeToArrayBuffer(salt),
|
|
180
321
|
binaryLikeToArrayBuffer(info),
|
|
181
322
|
keylen,
|
|
323
|
+
'full',
|
|
182
324
|
);
|
|
183
325
|
|
|
184
326
|
return result;
|
package/src/keys/classes.ts
CHANGED
|
@@ -150,6 +150,7 @@ export class KeyObject {
|
|
|
150
150
|
key: ArrayBuffer,
|
|
151
151
|
format?: KFormatType,
|
|
152
152
|
encoding?: KeyEncoding,
|
|
153
|
+
passphrase?: ArrayBuffer,
|
|
153
154
|
): KeyObject {
|
|
154
155
|
if (type !== 'secret' && type !== 'public' && type !== 'private')
|
|
155
156
|
throw new Error(`invalid KeyObject type: ${type}`);
|
|
@@ -172,12 +173,7 @@ export class KeyObject {
|
|
|
172
173
|
throw new Error('invalid key type');
|
|
173
174
|
}
|
|
174
175
|
|
|
175
|
-
|
|
176
|
-
if (format !== undefined) {
|
|
177
|
-
handle.init(keyType, key, format, encoding);
|
|
178
|
-
} else {
|
|
179
|
-
handle.init(keyType, key);
|
|
180
|
-
}
|
|
176
|
+
handle.init(keyType, key, format, encoding, passphrase);
|
|
181
177
|
|
|
182
178
|
// For asymmetric keys, return the appropriate subclass
|
|
183
179
|
if (type === 'public' || type === 'private') {
|
package/src/keys/index.ts
CHANGED
|
@@ -114,6 +114,7 @@ function prepareAsymmetricKey(
|
|
|
114
114
|
data: ArrayBuffer;
|
|
115
115
|
format?: 'pem' | 'der';
|
|
116
116
|
type?: 'pkcs1' | 'pkcs8' | 'spki' | 'sec1';
|
|
117
|
+
passphrase?: ArrayBuffer;
|
|
117
118
|
} {
|
|
118
119
|
if (key instanceof KeyObject) {
|
|
119
120
|
if (isPublic) {
|
|
@@ -147,7 +148,9 @@ function prepareAsymmetricKey(
|
|
|
147
148
|
|
|
148
149
|
if (typeof key === 'object' && 'key' in key) {
|
|
149
150
|
const keyObj = key as KeyInputObject;
|
|
150
|
-
const { key: data, format, type } = keyObj;
|
|
151
|
+
const { key: data, format, type, passphrase } = keyObj;
|
|
152
|
+
const passphraseAB =
|
|
153
|
+
passphrase !== undefined ? toAB(passphrase) : undefined;
|
|
151
154
|
|
|
152
155
|
if (data instanceof KeyObject) {
|
|
153
156
|
return prepareAsymmetricKey(data, isPublic);
|
|
@@ -167,14 +170,24 @@ function prepareAsymmetricKey(
|
|
|
167
170
|
(typeof data === 'string' && data.includes('-----BEGIN'))) &&
|
|
168
171
|
typeof data === 'string'
|
|
169
172
|
) {
|
|
170
|
-
return {
|
|
173
|
+
return {
|
|
174
|
+
data: toAB(data),
|
|
175
|
+
format: 'pem',
|
|
176
|
+
type,
|
|
177
|
+
passphrase: passphraseAB,
|
|
178
|
+
};
|
|
171
179
|
}
|
|
172
180
|
|
|
173
181
|
// Filter to only 'pem' or 'der' — JWK and raw formats are handled
|
|
174
182
|
// separately via dedicated paths.
|
|
175
183
|
const filteredFormat: 'pem' | 'der' | undefined =
|
|
176
184
|
format === 'pem' || format === 'der' ? format : undefined;
|
|
177
|
-
return {
|
|
185
|
+
return {
|
|
186
|
+
data: toAB(data),
|
|
187
|
+
format: filteredFormat,
|
|
188
|
+
type,
|
|
189
|
+
passphrase: passphraseAB,
|
|
190
|
+
};
|
|
178
191
|
}
|
|
179
192
|
|
|
180
193
|
throw new Error('Invalid key input');
|
|
@@ -212,7 +225,7 @@ function createPublicKey(key: KeyInput): PublicKeyObject {
|
|
|
212
225
|
return new PublicKeyObject(handle);
|
|
213
226
|
}
|
|
214
227
|
|
|
215
|
-
const { data, format, type } = prepareAsymmetricKey(key, true);
|
|
228
|
+
const { data, format, type, passphrase } = prepareAsymmetricKey(key, true);
|
|
216
229
|
|
|
217
230
|
// Map format string to KFormatType enum
|
|
218
231
|
let kFormat: KFormatType | undefined;
|
|
@@ -229,6 +242,7 @@ function createPublicKey(key: KeyInput): PublicKeyObject {
|
|
|
229
242
|
data,
|
|
230
243
|
kFormat,
|
|
231
244
|
kType,
|
|
245
|
+
passphrase,
|
|
232
246
|
) as PublicKeyObject;
|
|
233
247
|
}
|
|
234
248
|
|
|
@@ -249,7 +263,7 @@ function createPrivateKey(key: KeyInput): PrivateKeyObject {
|
|
|
249
263
|
return new PrivateKeyObject(handle);
|
|
250
264
|
}
|
|
251
265
|
|
|
252
|
-
const { data, format, type } = prepareAsymmetricKey(key, false);
|
|
266
|
+
const { data, format, type, passphrase } = prepareAsymmetricKey(key, false);
|
|
253
267
|
|
|
254
268
|
// Map format string to KFormatType enum
|
|
255
269
|
let kFormat: KFormatType | undefined;
|
|
@@ -267,6 +281,7 @@ function createPrivateKey(key: KeyInput): PrivateKeyObject {
|
|
|
267
281
|
data,
|
|
268
282
|
kFormat,
|
|
269
283
|
kType,
|
|
284
|
+
passphrase,
|
|
270
285
|
) as PrivateKeyObject;
|
|
271
286
|
}
|
|
272
287
|
|
package/src/specs/hkdf.nitro.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { HybridObject } from 'react-native-nitro-modules';
|
|
2
2
|
|
|
3
|
+
// RFC 5869 stage: 'full' (extract+expand), 'extract' (PRK only), or
|
|
4
|
+
// 'expand' (from an existing PRK).
|
|
5
|
+
export type HkdfMode = 'full' | 'extract' | 'expand';
|
|
6
|
+
|
|
3
7
|
export interface Hkdf extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
4
8
|
deriveKeySync(
|
|
5
9
|
algorithm: string,
|
|
@@ -7,6 +11,7 @@ export interface Hkdf extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
|
7
11
|
salt: ArrayBuffer,
|
|
8
12
|
info: ArrayBuffer,
|
|
9
13
|
length: number,
|
|
14
|
+
mode: HkdfMode,
|
|
10
15
|
): ArrayBuffer;
|
|
11
16
|
|
|
12
17
|
deriveKey(
|
|
@@ -15,5 +20,6 @@ export interface Hkdf extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
|
15
20
|
salt: ArrayBuffer,
|
|
16
21
|
info: ArrayBuffer,
|
|
17
22
|
length: number,
|
|
23
|
+
mode: HkdfMode,
|
|
18
24
|
): Promise<ArrayBuffer>;
|
|
19
25
|
}
|