react-native-quick-crypto 1.0.6 → 1.0.8
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 +6 -1
- package/README.md +11 -7
- package/android/CMakeLists.txt +4 -0
- package/cpp/blake3/HybridBlake3.cpp +1 -1
- package/cpp/cipher/CCMCipher.cpp +1 -1
- package/cpp/cipher/ChaCha20Cipher.cpp +1 -1
- package/cpp/cipher/ChaCha20Poly1305Cipher.cpp +1 -1
- package/cpp/cipher/GCMCipher.cpp +1 -1
- package/cpp/cipher/HybridCipher.cpp +1 -1
- package/cpp/cipher/HybridCipherFactory.hpp +1 -1
- package/cpp/cipher/HybridRsaCipher.cpp +1 -1
- package/cpp/cipher/OCBCipher.cpp +1 -1
- package/cpp/cipher/XSalsa20Cipher.cpp +1 -1
- package/cpp/dh/HybridDiffieHellman.cpp +438 -0
- package/cpp/dh/HybridDiffieHellman.hpp +41 -0
- package/cpp/ec/HybridEcKeyPair.cpp +1 -1
- package/cpp/ec/HybridEcKeyPair.hpp +1 -1
- package/cpp/ecdh/HybridECDH.cpp +306 -0
- package/cpp/ecdh/HybridECDH.hpp +42 -0
- package/cpp/ed25519/HybridEdKeyPair.hpp +1 -1
- package/cpp/hash/HybridHash.cpp +1 -1
- package/cpp/hkdf/HybridHkdf.cpp +1 -1
- package/cpp/keys/HybridKeyObjectHandle.cpp +1 -1
- package/cpp/keys/KeyObjectData.cpp +1 -1
- package/cpp/keys/KeyObjectData.hpp +1 -1
- package/cpp/mldsa/HybridMlDsaKeyPair.cpp +1 -1
- package/cpp/pbkdf2/HybridPbkdf2.cpp +1 -1
- package/cpp/random/HybridRandom.cpp +1 -1
- package/cpp/rsa/HybridRsaKeyPair.cpp +1 -1
- package/cpp/scrypt/HybridScrypt.cpp +1 -1
- package/cpp/sign/HybridSignHandle.cpp +1 -1
- package/cpp/sign/HybridVerifyHandle.cpp +1 -1
- package/cpp/utils/{Utils.hpp → QuickCryptoUtils.hpp} +14 -0
- package/lib/commonjs/dh-groups.js +29 -0
- package/lib/commonjs/dh-groups.js.map +1 -0
- package/lib/commonjs/diffie-hellman.js +147 -0
- package/lib/commonjs/diffie-hellman.js.map +1 -0
- package/lib/commonjs/ec.js +68 -180
- package/lib/commonjs/ec.js.map +1 -1
- package/lib/commonjs/ecdh.js +71 -0
- package/lib/commonjs/ecdh.js.map +1 -0
- package/lib/commonjs/index.js +26 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/keys/generateKeyPair.js.map +1 -1
- package/lib/commonjs/keys/index.js +12 -0
- package/lib/commonjs/keys/index.js.map +1 -1
- package/lib/commonjs/keys/signVerify.js +42 -0
- package/lib/commonjs/keys/signVerify.js.map +1 -1
- package/lib/commonjs/specs/diffie-hellman.nitro.js +6 -0
- package/lib/commonjs/specs/diffie-hellman.nitro.js.map +1 -0
- package/lib/commonjs/specs/ecdh.nitro.js +6 -0
- package/lib/commonjs/specs/ecdh.nitro.js.map +1 -0
- package/lib/commonjs/subtle.js +2 -0
- package/lib/commonjs/subtle.js.map +1 -1
- package/lib/module/dh-groups.js +25 -0
- package/lib/module/dh-groups.js.map +1 -0
- package/lib/module/diffie-hellman.js +140 -0
- package/lib/module/diffie-hellman.js.map +1 -0
- package/lib/module/ec.js +65 -178
- package/lib/module/ec.js.map +1 -1
- package/lib/module/ecdh.js +65 -0
- package/lib/module/ecdh.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/keys/generateKeyPair.js.map +1 -1
- package/lib/module/keys/index.js +2 -2
- package/lib/module/keys/index.js.map +1 -1
- package/lib/module/keys/signVerify.js +40 -0
- package/lib/module/keys/signVerify.js.map +1 -1
- package/lib/module/specs/diffie-hellman.nitro.js +4 -0
- package/lib/module/specs/diffie-hellman.nitro.js.map +1 -0
- package/lib/module/specs/ecdh.nitro.js +4 -0
- package/lib/module/specs/ecdh.nitro.js.map +1 -0
- package/lib/module/subtle.js +3 -1
- package/lib/module/subtle.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/typescript/dh-groups.d.ts +5 -0
- package/lib/typescript/dh-groups.d.ts.map +1 -0
- package/lib/typescript/diffie-hellman.d.ts +16 -0
- package/lib/typescript/diffie-hellman.d.ts.map +1 -0
- package/lib/typescript/ec.d.ts +2 -1
- package/lib/typescript/ec.d.ts.map +1 -1
- package/lib/typescript/ecdh.d.ts +16 -0
- package/lib/typescript/ecdh.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +11 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/keys/generateKeyPair.d.ts.map +1 -1
- package/lib/typescript/keys/index.d.ts +2 -2
- package/lib/typescript/keys/index.d.ts.map +1 -1
- package/lib/typescript/keys/signVerify.d.ts +6 -0
- package/lib/typescript/keys/signVerify.d.ts.map +1 -1
- package/lib/typescript/specs/diffie-hellman.nitro.d.ts +17 -0
- package/lib/typescript/specs/diffie-hellman.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/ecdh.nitro.d.ts +14 -0
- package/lib/typescript/specs/ecdh.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++/HybridDiffieHellmanSpec.cpp +30 -0
- package/nitrogen/generated/shared/c++/HybridDiffieHellmanSpec.hpp +72 -0
- package/nitrogen/generated/shared/c++/HybridECDHSpec.cpp +27 -0
- package/nitrogen/generated/shared/c++/HybridECDHSpec.hpp +70 -0
- package/package.json +1 -1
- package/src/dh-groups.ts +27 -0
- package/src/diffie-hellman.ts +191 -0
- package/src/ec.ts +73 -177
- package/src/ecdh.ts +76 -0
- package/src/index.ts +6 -0
- package/src/keys/generateKeyPair.ts +11 -2
- package/src/keys/index.ts +10 -1
- package/src/keys/signVerify.ts +84 -0
- package/src/specs/diffie-hellman.nitro.ts +15 -0
- package/src/specs/ecdh.nitro.ts +11 -0
- package/src/subtle.ts +8 -1
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { NitroModules } from 'react-native-nitro-modules';
|
|
2
|
+
import type { DiffieHellman as DiffieHellmanInterface } from './specs/diffie-hellman.nitro';
|
|
3
|
+
import { Buffer } from '@craftzdog/react-native-buffer';
|
|
4
|
+
import { DH_GROUPS } from './dh-groups';
|
|
5
|
+
|
|
6
|
+
export class DiffieHellman {
|
|
7
|
+
private _hybrid: DiffieHellmanInterface;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
sizeOrPrime: number | Buffer | string,
|
|
11
|
+
generator?: number | Buffer | string,
|
|
12
|
+
encoding?: BufferEncoding,
|
|
13
|
+
) {
|
|
14
|
+
this._hybrid =
|
|
15
|
+
NitroModules.createHybridObject<DiffieHellmanInterface>('DiffieHellman');
|
|
16
|
+
|
|
17
|
+
if (typeof sizeOrPrime === 'number') {
|
|
18
|
+
const gen = typeof generator === 'number' ? generator : 2;
|
|
19
|
+
this._hybrid.initWithSize(sizeOrPrime, gen);
|
|
20
|
+
} else {
|
|
21
|
+
let primeBuf: Buffer;
|
|
22
|
+
if (Buffer.isBuffer(sizeOrPrime)) {
|
|
23
|
+
primeBuf = sizeOrPrime;
|
|
24
|
+
} else {
|
|
25
|
+
primeBuf = Buffer.from(sizeOrPrime, encoding as BufferEncoding);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let genBuf: Buffer;
|
|
29
|
+
if (generator === undefined) {
|
|
30
|
+
genBuf = Buffer.from([2]);
|
|
31
|
+
} else if (typeof generator === 'number') {
|
|
32
|
+
genBuf = Buffer.from([generator]);
|
|
33
|
+
} else if (Buffer.isBuffer(generator)) {
|
|
34
|
+
genBuf = generator;
|
|
35
|
+
} else {
|
|
36
|
+
genBuf = Buffer.from(generator, encoding as BufferEncoding);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
this._hybrid.init(
|
|
40
|
+
primeBuf.buffer as ArrayBuffer,
|
|
41
|
+
genBuf.buffer as ArrayBuffer,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
generateKeys(encoding?: BufferEncoding): Buffer | string {
|
|
47
|
+
const keys = Buffer.from(this._hybrid.generateKeys());
|
|
48
|
+
if (encoding) return keys.toString(encoding);
|
|
49
|
+
return keys;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
computeSecret(
|
|
53
|
+
otherPublicKey: Buffer | string,
|
|
54
|
+
inputEncoding?: BufferEncoding,
|
|
55
|
+
outputEncoding?: BufferEncoding,
|
|
56
|
+
): Buffer | string {
|
|
57
|
+
let keyBuf: Buffer;
|
|
58
|
+
if (Buffer.isBuffer(otherPublicKey)) {
|
|
59
|
+
keyBuf = otherPublicKey;
|
|
60
|
+
} else {
|
|
61
|
+
keyBuf = Buffer.from(otherPublicKey, inputEncoding);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const secret = Buffer.from(
|
|
65
|
+
this._hybrid.computeSecret(keyBuf.buffer as ArrayBuffer),
|
|
66
|
+
);
|
|
67
|
+
if (outputEncoding) return secret.toString(outputEncoding);
|
|
68
|
+
return secret;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getPrime(encoding?: BufferEncoding): Buffer | string {
|
|
72
|
+
const p = Buffer.from(this._hybrid.getPrime());
|
|
73
|
+
if (encoding) return p.toString(encoding);
|
|
74
|
+
return p;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getGenerator(encoding?: BufferEncoding): Buffer | string {
|
|
78
|
+
const g = Buffer.from(this._hybrid.getGenerator());
|
|
79
|
+
if (encoding) return g.toString(encoding);
|
|
80
|
+
return g;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
getPublicKey(encoding?: BufferEncoding): Buffer | string {
|
|
84
|
+
const p = Buffer.from(this._hybrid.getPublicKey());
|
|
85
|
+
if (encoding) return p.toString(encoding);
|
|
86
|
+
return p;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
getPrivateKey(encoding?: BufferEncoding): Buffer | string {
|
|
90
|
+
const p = Buffer.from(this._hybrid.getPrivateKey());
|
|
91
|
+
if (encoding) return p.toString(encoding);
|
|
92
|
+
return p;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
setPublicKey(publicKey: Buffer | string, encoding?: BufferEncoding): void {
|
|
96
|
+
let keyBuf: Buffer;
|
|
97
|
+
if (Buffer.isBuffer(publicKey)) {
|
|
98
|
+
keyBuf = publicKey;
|
|
99
|
+
} else {
|
|
100
|
+
keyBuf = Buffer.from(publicKey, encoding);
|
|
101
|
+
}
|
|
102
|
+
this._hybrid.setPublicKey(keyBuf.buffer as ArrayBuffer);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
setPrivateKey(privateKey: Buffer | string, encoding?: BufferEncoding): void {
|
|
106
|
+
let keyBuf: Buffer;
|
|
107
|
+
if (Buffer.isBuffer(privateKey)) {
|
|
108
|
+
keyBuf = privateKey;
|
|
109
|
+
} else {
|
|
110
|
+
keyBuf = Buffer.from(privateKey, encoding);
|
|
111
|
+
}
|
|
112
|
+
this._hybrid.setPrivateKey(keyBuf.buffer as ArrayBuffer);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function createDiffieHellman(
|
|
117
|
+
primeOrSize: number | string | Buffer,
|
|
118
|
+
primeEncodingOrGenerator?: string | number | Buffer,
|
|
119
|
+
generator?: number | string | Buffer,
|
|
120
|
+
_generatorEncoding?: string,
|
|
121
|
+
): DiffieHellman {
|
|
122
|
+
if (typeof primeOrSize === 'number') {
|
|
123
|
+
const gen =
|
|
124
|
+
typeof primeEncodingOrGenerator === 'number'
|
|
125
|
+
? primeEncodingOrGenerator
|
|
126
|
+
: 2;
|
|
127
|
+
return new DiffieHellman(primeOrSize, gen);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Standardize arguments for String/Buffer prime
|
|
131
|
+
// createDiffieHellman(prime, [encoding], [generator], [encoding])
|
|
132
|
+
|
|
133
|
+
let prime: Buffer;
|
|
134
|
+
let generatorVal: Buffer | number | undefined;
|
|
135
|
+
|
|
136
|
+
if (Buffer.isBuffer(primeOrSize)) {
|
|
137
|
+
prime = primeOrSize;
|
|
138
|
+
// 2nd arg is generator if not string (encoding)
|
|
139
|
+
if (
|
|
140
|
+
primeEncodingOrGenerator !== undefined &&
|
|
141
|
+
typeof primeEncodingOrGenerator !== 'string'
|
|
142
|
+
) {
|
|
143
|
+
generatorVal = primeEncodingOrGenerator as Buffer | number;
|
|
144
|
+
} else if (generator !== undefined) {
|
|
145
|
+
generatorVal = generator as Buffer | number;
|
|
146
|
+
} else {
|
|
147
|
+
generatorVal = 2;
|
|
148
|
+
}
|
|
149
|
+
} else {
|
|
150
|
+
// String prime
|
|
151
|
+
const encoding =
|
|
152
|
+
typeof primeEncodingOrGenerator === 'string'
|
|
153
|
+
? primeEncodingOrGenerator
|
|
154
|
+
: 'utf8'; // Defaulting to utf8 or hex? Node default is 'binary' usually but utf8 safer for TS. Node docs say: "If no encoding is specified, 'binary' is used."
|
|
155
|
+
// We'll trust user passed encoding if it's a string, otherwise handle it.
|
|
156
|
+
prime = Buffer.from(primeOrSize, encoding as BufferEncoding);
|
|
157
|
+
|
|
158
|
+
// Generator handling in this case
|
|
159
|
+
if (generator !== undefined) {
|
|
160
|
+
generatorVal = generator as Buffer | number;
|
|
161
|
+
if (typeof generator === 'string' && _generatorEncoding) {
|
|
162
|
+
generatorVal = Buffer.from(
|
|
163
|
+
generator,
|
|
164
|
+
_generatorEncoding as BufferEncoding,
|
|
165
|
+
);
|
|
166
|
+
} else if (typeof generator === 'string') {
|
|
167
|
+
// string with no encoding, assume same as prime? or utf8?
|
|
168
|
+
generatorVal = Buffer.from(generator, encoding as BufferEncoding);
|
|
169
|
+
}
|
|
170
|
+
} else if (
|
|
171
|
+
typeof primeEncodingOrGenerator !== 'string' &&
|
|
172
|
+
primeEncodingOrGenerator !== undefined
|
|
173
|
+
) {
|
|
174
|
+
// 2nd arg was generator
|
|
175
|
+
generatorVal = primeEncodingOrGenerator as number;
|
|
176
|
+
} else {
|
|
177
|
+
generatorVal = 2;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return new DiffieHellman(prime, generatorVal);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function getDiffieHellman(groupName: string): DiffieHellman {
|
|
185
|
+
const group = DH_GROUPS[groupName];
|
|
186
|
+
if (!group) {
|
|
187
|
+
throw new Error(`Unknown group: ${groupName}`);
|
|
188
|
+
}
|
|
189
|
+
// group.prime and group.generator are hex strings
|
|
190
|
+
return new DiffieHellman(group.prime, group.generator, 'hex');
|
|
191
|
+
}
|
package/src/ec.ts
CHANGED
|
@@ -31,7 +31,8 @@ import {
|
|
|
31
31
|
KeyEncoding,
|
|
32
32
|
KFormatType,
|
|
33
33
|
} from './utils';
|
|
34
|
-
import { Buffer } from 'buffer';
|
|
34
|
+
import { Buffer } from '@craftzdog/react-native-buffer';
|
|
35
|
+
import { ECDH } from './ecdh';
|
|
35
36
|
|
|
36
37
|
export class Ec {
|
|
37
38
|
native: EcKeyPair;
|
|
@@ -58,57 +59,6 @@ export class Ec {
|
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
// function verifyAcceptableEcKeyUse(
|
|
62
|
-
// name: AnyAlgorithm,
|
|
63
|
-
// isPublic: boolean,
|
|
64
|
-
// usages: KeyUsage[],
|
|
65
|
-
// ): void {
|
|
66
|
-
// let checkSet;
|
|
67
|
-
// switch (name) {
|
|
68
|
-
// case 'ECDH':
|
|
69
|
-
// checkSet = isPublic ? [] : ['deriveKey', 'deriveBits'];
|
|
70
|
-
// break;
|
|
71
|
-
// case 'ECDSA':
|
|
72
|
-
// checkSet = isPublic ? ['verify'] : ['sign'];
|
|
73
|
-
// break;
|
|
74
|
-
// default:
|
|
75
|
-
// throw lazyDOMException(
|
|
76
|
-
// 'The algorithm is not supported',
|
|
77
|
-
// 'NotSupportedError',
|
|
78
|
-
// );
|
|
79
|
-
// }
|
|
80
|
-
// if (hasAnyNotIn(usages, checkSet)) {
|
|
81
|
-
// throw lazyDOMException(
|
|
82
|
-
// `Unsupported key usage for a ${name} key`,
|
|
83
|
-
// 'SyntaxError',
|
|
84
|
-
// );
|
|
85
|
-
// }
|
|
86
|
-
// }
|
|
87
|
-
|
|
88
|
-
// function createECPublicKeyRaw(
|
|
89
|
-
// namedCurve: NamedCurve | undefined,
|
|
90
|
-
// keyDataBuffer: ArrayBuffer,
|
|
91
|
-
// ): PublicKeyObject {
|
|
92
|
-
// if (!namedCurve) {
|
|
93
|
-
// throw new Error('Invalid namedCurve');
|
|
94
|
-
// }
|
|
95
|
-
// const handle = NitroModules.createHybridObject(
|
|
96
|
-
// 'KeyObjectHandle',
|
|
97
|
-
// ) as KeyObjectHandle;
|
|
98
|
-
|
|
99
|
-
// if (!handle.initECRaw(kNamedCurveAliases[namedCurve], keyDataBuffer)) {
|
|
100
|
-
// console.log('keyData', ab2str(keyDataBuffer));
|
|
101
|
-
// throw new Error('Invalid keyData 1');
|
|
102
|
-
// }
|
|
103
|
-
|
|
104
|
-
// return new PublicKeyObject(handle);
|
|
105
|
-
// }
|
|
106
|
-
|
|
107
|
-
// // Node API
|
|
108
|
-
// export function ec_exportKey(key: CryptoKey, format: KeyFormat): ArrayBuffer {
|
|
109
|
-
// return ec.native.exportKey(format, key.keyObject.handle);
|
|
110
|
-
// }
|
|
111
|
-
|
|
112
62
|
// Node API
|
|
113
63
|
export function ecImportKey(
|
|
114
64
|
format: ImportFormat,
|
|
@@ -169,7 +119,7 @@ export function ecImportKey(
|
|
|
169
119
|
expectedAlg = 'ECDH-ES';
|
|
170
120
|
}
|
|
171
121
|
|
|
172
|
-
if (expectedAlg && jwk.alg !== expectedAlg) {
|
|
122
|
+
if (expectedAlg && jwk.alg !== undefined && jwk.alg !== expectedAlg) {
|
|
173
123
|
throw lazyDOMException(
|
|
174
124
|
'JWK "alg" does not match the requested algorithm',
|
|
175
125
|
'DataError',
|
|
@@ -245,6 +195,7 @@ export function ecImportKey(
|
|
|
245
195
|
NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
|
|
246
196
|
const curveAlias =
|
|
247
197
|
kNamedCurveAliases[namedCurve as keyof typeof kNamedCurveAliases];
|
|
198
|
+
// Only throw if initialization explicitly fails
|
|
248
199
|
if (!handle.initECRaw(curveAlias, keyBuffer)) {
|
|
249
200
|
throw lazyDOMException('Failed to import EC raw key', 'DataError');
|
|
250
201
|
}
|
|
@@ -260,131 +211,8 @@ export function ecImportKey(
|
|
|
260
211
|
}
|
|
261
212
|
|
|
262
213
|
return new CryptoKey(keyObject, algorithm, keyUsages, extractable);
|
|
263
|
-
// // // verifyAcceptableEcKeyUse(name, true, usagesSet);
|
|
264
|
-
// // try {
|
|
265
|
-
// // keyObject = createPublicKey({
|
|
266
|
-
// // key: keyData,
|
|
267
|
-
// // format: 'der',
|
|
268
|
-
// // type: 'spki',
|
|
269
|
-
// // });
|
|
270
|
-
// // } catch (err) {
|
|
271
|
-
// // throw new Error(`Invalid keyData 2: ${err}`);
|
|
272
|
-
// // }
|
|
273
|
-
// // break;
|
|
274
|
-
// // }
|
|
275
|
-
// // case 'pkcs8': {
|
|
276
|
-
// // // verifyAcceptableEcKeyUse(name, false, usagesSet);
|
|
277
|
-
// // try {
|
|
278
|
-
// // keyObject = createPrivateKey({
|
|
279
|
-
// // key: keyData,
|
|
280
|
-
// // format: 'der',
|
|
281
|
-
// // type: 'pkcs8',
|
|
282
|
-
// // });
|
|
283
|
-
// // } catch (err) {
|
|
284
|
-
// // throw new Error(`Invalid keyData 3 ${err}`);
|
|
285
|
-
// // }
|
|
286
|
-
// // break;
|
|
287
|
-
// // }
|
|
288
214
|
}
|
|
289
215
|
|
|
290
|
-
// case 'jwk': {
|
|
291
|
-
// const data = keyData as JWK;
|
|
292
|
-
|
|
293
|
-
// if (!data.kty) throw lazyDOMException('Invalid keyData 4', 'DataError');
|
|
294
|
-
// if (data.kty !== 'EC')
|
|
295
|
-
// throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError');
|
|
296
|
-
// if (data.crv !== namedCurve)
|
|
297
|
-
// throw lazyDOMException(
|
|
298
|
-
// 'JWK "crv" does not match the requested algorithm',
|
|
299
|
-
// 'DataError',
|
|
300
|
-
// );
|
|
301
|
-
|
|
302
|
-
// verifyAcceptableEcKeyUse(name, data.d === undefined, keyUsages);
|
|
303
|
-
|
|
304
|
-
// if (keyUsages.length > 0 && data.use !== undefined) {
|
|
305
|
-
// const checkUse = name === 'ECDH' ? 'enc' : 'sig';
|
|
306
|
-
// if (data.use !== checkUse)
|
|
307
|
-
// throw lazyDOMException('Invalid JWK "use" Parameter', 'DataError');
|
|
308
|
-
// }
|
|
309
|
-
|
|
310
|
-
// validateKeyOps(data.key_ops, keyUsages);
|
|
311
|
-
|
|
312
|
-
// if (
|
|
313
|
-
// data.ext !== undefined &&
|
|
314
|
-
// data.ext === false &&
|
|
315
|
-
// extractable === true
|
|
316
|
-
// ) {
|
|
317
|
-
// throw lazyDOMException(
|
|
318
|
-
// 'JWK "ext" Parameter and extractable mismatch',
|
|
319
|
-
// 'DataError',
|
|
320
|
-
// );
|
|
321
|
-
// }
|
|
322
|
-
|
|
323
|
-
// if (algorithm.name === 'ECDSA' && data.alg !== undefined) {
|
|
324
|
-
// let algNamedCurve;
|
|
325
|
-
// switch (data.alg) {
|
|
326
|
-
// case 'ES256':
|
|
327
|
-
// algNamedCurve = 'P-256';
|
|
328
|
-
// break;
|
|
329
|
-
// case 'ES384':
|
|
330
|
-
// algNamedCurve = 'P-384';
|
|
331
|
-
// break;
|
|
332
|
-
// case 'ES512':
|
|
333
|
-
// algNamedCurve = 'P-521';
|
|
334
|
-
// break;
|
|
335
|
-
// }
|
|
336
|
-
// if (algNamedCurve !== namedCurve)
|
|
337
|
-
// throw lazyDOMException(
|
|
338
|
-
// 'JWK "alg" does not match the requested algorithm',
|
|
339
|
-
// 'DataError',
|
|
340
|
-
// );
|
|
341
|
-
// }
|
|
342
|
-
|
|
343
|
-
// const handle = NativeQuickCrypto.webcrypto.createKeyObjectHandle();
|
|
344
|
-
// const type = handle.initJwk(data, namedCurve);
|
|
345
|
-
// if (type === undefined)
|
|
346
|
-
// throw lazyDOMException('Invalid JWK', 'DataError');
|
|
347
|
-
// keyObject =
|
|
348
|
-
// type === KeyType.PRIVATE
|
|
349
|
-
// ? new PrivateKeyObject(handle)
|
|
350
|
-
// : new PublicKeyObject(handle);
|
|
351
|
-
// break;
|
|
352
|
-
// }
|
|
353
|
-
// case 'raw': {
|
|
354
|
-
// const data = keyData as BufferLike | BinaryLike;
|
|
355
|
-
// verifyAcceptableEcKeyUse(name, true, keyUsages);
|
|
356
|
-
// const buffer =
|
|
357
|
-
// typeof data === 'string'
|
|
358
|
-
// ? binaryLikeToArrayBuffer(data)
|
|
359
|
-
// : bufferLikeToArrayBuffer(data);
|
|
360
|
-
// keyObject = createECPublicKeyRaw(namedCurve, buffer);
|
|
361
|
-
// break;
|
|
362
|
-
// }
|
|
363
|
-
// default: {
|
|
364
|
-
// throw new Error(`Unknown EC import format: ${format}`);
|
|
365
|
-
// }
|
|
366
|
-
// }
|
|
367
|
-
|
|
368
|
-
// switch (algorithm.name) {
|
|
369
|
-
// case 'ECDSA':
|
|
370
|
-
// // Fall through
|
|
371
|
-
// case 'ECDH':
|
|
372
|
-
// if (keyObject.asymmetricKeyType !== ('ec' as AsymmetricKeyType))
|
|
373
|
-
// throw new Error('Invalid key type');
|
|
374
|
-
// break;
|
|
375
|
-
// }
|
|
376
|
-
|
|
377
|
-
// // if (!keyObject[kHandle].checkEcKeyData()) {
|
|
378
|
-
// // throw new Error('Invalid keyData 5');
|
|
379
|
-
// // }
|
|
380
|
-
|
|
381
|
-
// // const { namedCurve: checkNamedCurve } = keyObject[kHandle].keyDetail({});
|
|
382
|
-
// // if (kNamedCurveAliases[namedCurve] !== checkNamedCurve)
|
|
383
|
-
// // throw new Error('Named curve mismatch');
|
|
384
|
-
|
|
385
|
-
// return new CryptoKey(keyObject, { name, namedCurve }, keyUsages, extractable);
|
|
386
|
-
// }
|
|
387
|
-
|
|
388
216
|
// Node API
|
|
389
217
|
export const ecdsaSignVerify = (
|
|
390
218
|
key: CryptoKey,
|
|
@@ -462,7 +290,6 @@ export async function ec_generateKeyPair(
|
|
|
462
290
|
);
|
|
463
291
|
}
|
|
464
292
|
|
|
465
|
-
// const usageSet = new SafeSet(keyUsages);
|
|
466
293
|
switch (name) {
|
|
467
294
|
case 'ECDSA':
|
|
468
295
|
if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
|
|
@@ -655,3 +482,72 @@ export function ec_generateKeyPairNodeSync(
|
|
|
655
482
|
ec.generateKeyPairSync();
|
|
656
483
|
return ec_formatKeyPairOutput(ec, encoding);
|
|
657
484
|
}
|
|
485
|
+
|
|
486
|
+
export function ecDeriveBits(
|
|
487
|
+
algorithm: SubtleAlgorithm,
|
|
488
|
+
baseKey: CryptoKey,
|
|
489
|
+
length: number | null,
|
|
490
|
+
): ArrayBuffer {
|
|
491
|
+
const publicParams = algorithm as SubtleAlgorithm & { public?: CryptoKey };
|
|
492
|
+
const publicKey = publicParams.public;
|
|
493
|
+
|
|
494
|
+
if (!publicKey) {
|
|
495
|
+
throw new Error('Public key is required for ECDH derivation');
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (baseKey.algorithm.name !== publicKey.algorithm.name) {
|
|
499
|
+
throw new Error('Keys must be of the same algorithm');
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (baseKey.algorithm.namedCurve !== publicKey.algorithm.namedCurve) {
|
|
503
|
+
throw new Error('Keys must use the same curve');
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const namedCurve = baseKey.algorithm.namedCurve;
|
|
507
|
+
if (!namedCurve) {
|
|
508
|
+
throw new Error('Curve name is missing');
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Create new ECDH instance (Node.js style wrapper)
|
|
512
|
+
const ecdh = new ECDH(namedCurve);
|
|
513
|
+
|
|
514
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
515
|
+
const jwkPrivate = baseKey.keyObject.export({ format: 'jwk' }) as any;
|
|
516
|
+
if (!jwkPrivate.d) throw new Error('Invalid private key');
|
|
517
|
+
const privateBytes = Buffer.from(jwkPrivate.d, 'base64');
|
|
518
|
+
|
|
519
|
+
ecdh.setPrivateKey(privateBytes);
|
|
520
|
+
|
|
521
|
+
// Public key
|
|
522
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
523
|
+
const jwkPublic = publicKey.keyObject.export({ format: 'jwk' }) as any;
|
|
524
|
+
|
|
525
|
+
// HybridECDH `computeSecret` takes public key.
|
|
526
|
+
// My implementation `HybridECDH.cpp` `computeSecret` expects what?
|
|
527
|
+
// `derive_secret` -> `EVP_PKEY_derive_set_peer`
|
|
528
|
+
// `computeSecret` calls `EC_POINT_oct2point`. So it expects an uncompressed/compressed point (04... or 02/03...).
|
|
529
|
+
// JWK gives `x` and `y`. We can construct the uncompressed point 04 + x + y.
|
|
530
|
+
|
|
531
|
+
if (!jwkPublic.x || !jwkPublic.y) throw new Error('Invalid public key');
|
|
532
|
+
const x = Buffer.from(jwkPublic.x, 'base64');
|
|
533
|
+
const y = Buffer.from(jwkPublic.y, 'base64');
|
|
534
|
+
|
|
535
|
+
// Uncompressed point: 0x04 || x || y
|
|
536
|
+
const publicBytes = Buffer.concat([Buffer.from([0x04]), x, y]);
|
|
537
|
+
|
|
538
|
+
const secret = ecdh.computeSecret(publicBytes);
|
|
539
|
+
const secretBuf = Buffer.from(secret);
|
|
540
|
+
|
|
541
|
+
// If length is null, return full secret
|
|
542
|
+
if (length === null) {
|
|
543
|
+
return secretBuf.buffer;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// If length is specified, truncate
|
|
547
|
+
const byteLength = Math.ceil(length / 8);
|
|
548
|
+
if (secretBuf.byteLength >= byteLength) {
|
|
549
|
+
return secretBuf.subarray(0, byteLength).buffer as ArrayBuffer;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
throw new Error('Derived key is shorter than requested length');
|
|
553
|
+
}
|
package/src/ecdh.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { NitroModules } from 'react-native-nitro-modules';
|
|
2
|
+
import type { ECDH as ECDHInterface } from './specs/ecdh.nitro';
|
|
3
|
+
import { Buffer } from '@craftzdog/react-native-buffer';
|
|
4
|
+
|
|
5
|
+
export class ECDH {
|
|
6
|
+
private _hybrid: ECDHInterface;
|
|
7
|
+
|
|
8
|
+
constructor(curveName: string) {
|
|
9
|
+
this._hybrid = NitroModules.createHybridObject<ECDHInterface>('ECDH');
|
|
10
|
+
this._hybrid.init(curveName);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
generateKeys(): Buffer {
|
|
14
|
+
const key = this._hybrid.generateKeys();
|
|
15
|
+
return Buffer.from(key);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
computeSecret(
|
|
19
|
+
otherPublicKey: Buffer | string | { code: number; byteLength: number },
|
|
20
|
+
inputEncoding?: BufferEncoding,
|
|
21
|
+
): Buffer {
|
|
22
|
+
let keyBuf: Buffer;
|
|
23
|
+
if (Buffer.isBuffer(otherPublicKey)) {
|
|
24
|
+
keyBuf = otherPublicKey;
|
|
25
|
+
} else if (typeof otherPublicKey === 'string') {
|
|
26
|
+
keyBuf = Buffer.from(otherPublicKey, inputEncoding);
|
|
27
|
+
} else {
|
|
28
|
+
// Handle array view or other types if necessary, but Node.js typically expects Buffer or string + encoding
|
|
29
|
+
throw new TypeError('Invalid otherPublicKey type');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ECDH.computeSecret in Node.js returns Buffer
|
|
33
|
+
const secret = this._hybrid.computeSecret(keyBuf.buffer as ArrayBuffer);
|
|
34
|
+
return Buffer.from(secret);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getPrivateKey(): Buffer {
|
|
38
|
+
return Buffer.from(this._hybrid.getPrivateKey());
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
setPrivateKey(privateKey: Buffer | string, encoding?: BufferEncoding): void {
|
|
42
|
+
let keyBuf: Buffer;
|
|
43
|
+
if (Buffer.isBuffer(privateKey)) {
|
|
44
|
+
keyBuf = privateKey;
|
|
45
|
+
} else {
|
|
46
|
+
keyBuf = Buffer.from(privateKey, encoding);
|
|
47
|
+
}
|
|
48
|
+
this._hybrid.setPrivateKey(keyBuf.buffer as ArrayBuffer);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
getPublicKey(encoding?: BufferEncoding): Buffer | string {
|
|
52
|
+
// Node.js getPublicKey([encoding[, format]])
|
|
53
|
+
// If encoding is provided, returns string. If not, Buffer.
|
|
54
|
+
// Our C++ returns ArrayBuffer (Buffer).
|
|
55
|
+
// We ignore format for now as C++ implementation defaults to uncompressed.
|
|
56
|
+
const pub = Buffer.from(this._hybrid.getPublicKey());
|
|
57
|
+
if (encoding) {
|
|
58
|
+
return pub.toString(encoding);
|
|
59
|
+
}
|
|
60
|
+
return pub;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
setPublicKey(publicKey: Buffer | string, encoding?: BufferEncoding): void {
|
|
64
|
+
let keyBuf: Buffer;
|
|
65
|
+
if (Buffer.isBuffer(publicKey)) {
|
|
66
|
+
keyBuf = publicKey;
|
|
67
|
+
} else {
|
|
68
|
+
keyBuf = Buffer.from(publicKey, encoding);
|
|
69
|
+
}
|
|
70
|
+
this._hybrid.setPublicKey(keyBuf.buffer as ArrayBuffer);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function createECDH(curveName: string): ECDH {
|
|
75
|
+
return new ECDH(curveName);
|
|
76
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -12,6 +12,8 @@ import * as hkdf from './hkdf';
|
|
|
12
12
|
import * as pbkdf2 from './pbkdf2';
|
|
13
13
|
import * as scrypt from './scrypt';
|
|
14
14
|
import * as random from './random';
|
|
15
|
+
import * as ecdh from './ecdh';
|
|
16
|
+
import * as dh from './diffie-hellman';
|
|
15
17
|
import { constants } from './constants';
|
|
16
18
|
|
|
17
19
|
// utils import
|
|
@@ -33,6 +35,8 @@ const QuickCrypto = {
|
|
|
33
35
|
...pbkdf2,
|
|
34
36
|
...scrypt,
|
|
35
37
|
...random,
|
|
38
|
+
...ecdh,
|
|
39
|
+
...dh,
|
|
36
40
|
...utils,
|
|
37
41
|
...subtle,
|
|
38
42
|
constants,
|
|
@@ -71,6 +75,8 @@ export * from './hkdf';
|
|
|
71
75
|
export * from './pbkdf2';
|
|
72
76
|
export * from './scrypt';
|
|
73
77
|
export * from './random';
|
|
78
|
+
export * from './ecdh';
|
|
79
|
+
export * from './diffie-hellman';
|
|
74
80
|
export * from './utils';
|
|
75
81
|
export * from './subtle';
|
|
76
82
|
export { subtle, isCryptoKeyPair } from './subtle';
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type GenerateKeyPairPromiseReturn,
|
|
11
11
|
type GenerateKeyPairReturn,
|
|
12
12
|
type KeyPairGenConfig,
|
|
13
|
+
type KeyPairKey,
|
|
13
14
|
type KeyPairType,
|
|
14
15
|
} from '../utils';
|
|
15
16
|
import { parsePrivateKeyEncoding, parsePublicKeyEncoding } from './utils';
|
|
@@ -160,7 +161,11 @@ function internalGenerateKeyPair(
|
|
|
160
161
|
} else {
|
|
161
162
|
throw new Error(`Unsupported key type: ${type}`);
|
|
162
163
|
}
|
|
163
|
-
return [
|
|
164
|
+
return [
|
|
165
|
+
undefined,
|
|
166
|
+
result.publicKey as KeyPairKey,
|
|
167
|
+
result.privateKey as KeyPairKey,
|
|
168
|
+
];
|
|
164
169
|
} catch (error) {
|
|
165
170
|
return [error as Error, undefined, undefined];
|
|
166
171
|
}
|
|
@@ -182,7 +187,11 @@ function internalGenerateKeyPair(
|
|
|
182
187
|
} else {
|
|
183
188
|
throw new Error(`Unsupported key type: ${type}`);
|
|
184
189
|
}
|
|
185
|
-
return [
|
|
190
|
+
return [
|
|
191
|
+
undefined,
|
|
192
|
+
result.publicKey as KeyPairKey,
|
|
193
|
+
result.privateKey as KeyPairKey,
|
|
194
|
+
];
|
|
186
195
|
} catch (error) {
|
|
187
196
|
return [error as Error, undefined, undefined];
|
|
188
197
|
}
|
package/src/keys/index.ts
CHANGED
|
@@ -7,7 +7,14 @@ import {
|
|
|
7
7
|
PrivateKeyObject,
|
|
8
8
|
} from './classes';
|
|
9
9
|
import { generateKeyPair, generateKeyPairSync } from './generateKeyPair';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
createSign,
|
|
12
|
+
createVerify,
|
|
13
|
+
sign,
|
|
14
|
+
verify,
|
|
15
|
+
Sign,
|
|
16
|
+
Verify,
|
|
17
|
+
} from './signVerify';
|
|
11
18
|
import {
|
|
12
19
|
publicEncrypt,
|
|
13
20
|
publicDecrypt,
|
|
@@ -236,6 +243,8 @@ export {
|
|
|
236
243
|
KeyObject,
|
|
237
244
|
createSign,
|
|
238
245
|
createVerify,
|
|
246
|
+
sign,
|
|
247
|
+
verify,
|
|
239
248
|
Sign,
|
|
240
249
|
Verify,
|
|
241
250
|
publicEncrypt,
|