react-native-quick-crypto 0.7.0 → 0.7.1
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/android/CMakeLists.txt +2 -0
- package/cpp/Cipher/MGLRsa.cpp +179 -3
- package/cpp/Cipher/MGLRsa.h +40 -0
- package/cpp/JSIUtils/MGLJSIUtils.h +8 -0
- package/cpp/MGLKeys.cpp +41 -43
- package/cpp/MGLKeys.h +9 -2
- package/cpp/MGLQuickCryptoHostObject.cpp +6 -6
- package/cpp/Utils/MGLUtils.cpp +71 -1
- package/cpp/Utils/MGLUtils.h +55 -1
- package/cpp/webcrypto/MGLWebCrypto.cpp +89 -37
- package/cpp/webcrypto/MGLWebCrypto.h +5 -7
- package/cpp/webcrypto/crypto_aes.cpp +516 -0
- package/cpp/webcrypto/crypto_aes.h +79 -0
- package/cpp/webcrypto/crypto_ec.cpp +4 -20
- package/cpp/webcrypto/crypto_ec.h +0 -5
- package/cpp/webcrypto/crypto_keygen.cpp +86 -0
- package/cpp/webcrypto/crypto_keygen.h +38 -0
- package/lib/commonjs/Cipher.js +3 -1
- package/lib/commonjs/Cipher.js.map +1 -1
- package/lib/commonjs/Hashnames.js +20 -8
- package/lib/commonjs/Hashnames.js.map +1 -1
- package/lib/commonjs/NativeQuickCrypto/Cipher.js +13 -1
- package/lib/commonjs/NativeQuickCrypto/Cipher.js.map +1 -1
- package/lib/commonjs/NativeQuickCrypto/NativeQuickCrypto.js.map +1 -1
- package/lib/commonjs/NativeQuickCrypto/aes.js +6 -0
- package/lib/commonjs/NativeQuickCrypto/aes.js.map +1 -0
- package/lib/commonjs/NativeQuickCrypto/keygen.js +6 -0
- package/lib/commonjs/NativeQuickCrypto/keygen.js.map +1 -0
- package/lib/commonjs/NativeQuickCrypto/rsa.js +6 -0
- package/lib/commonjs/NativeQuickCrypto/rsa.js.map +1 -0
- package/lib/commonjs/Utils.js +30 -6
- package/lib/commonjs/Utils.js.map +1 -1
- package/lib/commonjs/aes.js +184 -227
- package/lib/commonjs/aes.js.map +1 -1
- package/lib/commonjs/index.js +12 -2
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/keygen.js +56 -0
- package/lib/commonjs/keygen.js.map +1 -0
- package/lib/commonjs/keys.js +74 -5
- package/lib/commonjs/keys.js.map +1 -1
- package/lib/commonjs/rsa.js +115 -196
- package/lib/commonjs/rsa.js.map +1 -1
- package/lib/commonjs/sig.js.map +1 -1
- package/lib/commonjs/subtle.js +140 -78
- package/lib/commonjs/subtle.js.map +1 -1
- package/lib/commonjs/webcrypto.js +14 -0
- package/lib/commonjs/webcrypto.js.map +1 -0
- package/lib/module/Cipher.js +3 -1
- package/lib/module/Cipher.js.map +1 -1
- package/lib/module/Hashnames.js +20 -8
- package/lib/module/Hashnames.js.map +1 -1
- package/lib/module/NativeQuickCrypto/Cipher.js +12 -0
- package/lib/module/NativeQuickCrypto/Cipher.js.map +1 -1
- package/lib/module/NativeQuickCrypto/NativeQuickCrypto.js.map +1 -1
- package/lib/module/NativeQuickCrypto/aes.js +2 -0
- package/lib/module/NativeQuickCrypto/aes.js.map +1 -0
- package/lib/module/NativeQuickCrypto/keygen.js +2 -0
- package/lib/module/NativeQuickCrypto/keygen.js.map +1 -0
- package/lib/module/NativeQuickCrypto/rsa.js +2 -0
- package/lib/module/NativeQuickCrypto/rsa.js.map +1 -0
- package/lib/module/Utils.js +26 -5
- package/lib/module/Utils.js.map +1 -1
- package/lib/module/aes.js +183 -228
- package/lib/module/aes.js.map +1 -1
- package/lib/module/index.js +11 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/keygen.js +47 -0
- package/lib/module/keygen.js.map +1 -0
- package/lib/module/keys.js +68 -4
- package/lib/module/keys.js.map +1 -1
- package/lib/module/rsa.js +115 -198
- package/lib/module/rsa.js.map +1 -1
- package/lib/module/sig.js.map +1 -1
- package/lib/module/subtle.js +143 -82
- package/lib/module/subtle.js.map +1 -1
- package/lib/module/webcrypto.js +8 -0
- package/lib/module/webcrypto.js.map +1 -0
- package/lib/typescript/Cipher.d.ts +0 -1
- package/lib/typescript/Cipher.d.ts.map +1 -1
- package/lib/typescript/Hash.d.ts.map +1 -1
- package/lib/typescript/Hashnames.d.ts +2 -2
- package/lib/typescript/Hashnames.d.ts.map +1 -1
- package/lib/typescript/NativeQuickCrypto/Cipher.d.ts +5 -0
- package/lib/typescript/NativeQuickCrypto/Cipher.d.ts.map +1 -1
- package/lib/typescript/NativeQuickCrypto/NativeQuickCrypto.d.ts +4 -1
- package/lib/typescript/NativeQuickCrypto/NativeQuickCrypto.d.ts.map +1 -1
- package/lib/typescript/NativeQuickCrypto/aes.d.ts +5 -0
- package/lib/typescript/NativeQuickCrypto/aes.d.ts.map +1 -0
- package/lib/typescript/NativeQuickCrypto/keygen.d.ts +4 -0
- package/lib/typescript/NativeQuickCrypto/keygen.d.ts.map +1 -0
- package/lib/typescript/NativeQuickCrypto/rsa.d.ts +5 -0
- package/lib/typescript/NativeQuickCrypto/rsa.d.ts.map +1 -0
- package/lib/typescript/NativeQuickCrypto/webcrypto.d.ts +12 -2
- package/lib/typescript/NativeQuickCrypto/webcrypto.d.ts.map +1 -1
- package/lib/typescript/Utils.d.ts +4 -4
- package/lib/typescript/Utils.d.ts.map +1 -1
- package/lib/typescript/aes.d.ts +18 -1
- package/lib/typescript/aes.d.ts.map +1 -1
- package/lib/typescript/ec.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +27 -24
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/keygen.d.ts +6 -0
- package/lib/typescript/keygen.d.ts.map +1 -0
- package/lib/typescript/keys.d.ts +55 -17
- package/lib/typescript/keys.d.ts.map +1 -1
- package/lib/typescript/rsa.d.ts +9 -1
- package/lib/typescript/rsa.d.ts.map +1 -1
- package/lib/typescript/sig.d.ts +3 -17
- package/lib/typescript/sig.d.ts.map +1 -1
- package/lib/typescript/subtle.d.ts +6 -5
- package/lib/typescript/subtle.d.ts.map +1 -1
- package/lib/typescript/webcrypto.d.ts +9 -0
- package/lib/typescript/webcrypto.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/Cipher.ts +1 -1
- package/src/Hashnames.ts +23 -21
- package/src/NativeQuickCrypto/Cipher.ts +32 -0
- package/src/NativeQuickCrypto/NativeQuickCrypto.ts +6 -0
- package/src/NativeQuickCrypto/aes.ts +14 -0
- package/src/NativeQuickCrypto/keygen.ts +7 -0
- package/src/NativeQuickCrypto/rsa.ts +12 -0
- package/src/NativeQuickCrypto/webcrypto.ts +26 -2
- package/src/Utils.ts +37 -8
- package/src/aes.ts +259 -222
- package/src/index.ts +10 -1
- package/src/keygen.ts +80 -0
- package/src/keys.ts +139 -30
- package/src/rsa.ts +161 -187
- package/src/sig.ts +7 -23
- package/src/subtle.ts +211 -93
- package/src/webcrypto.ts +8 -0
package/android/CMakeLists.txt
CHANGED
|
@@ -43,7 +43,9 @@ add_library(
|
|
|
43
43
|
"../cpp/Sig/MGLVerifyInstaller.cpp"
|
|
44
44
|
"../cpp/Sig/MGLSignHostObjects.cpp"
|
|
45
45
|
"../cpp/webcrypto/MGLWebCrypto.cpp"
|
|
46
|
+
"../cpp/webcrypto/crypto_aes.cpp"
|
|
46
47
|
"../cpp/webcrypto/crypto_ec.cpp"
|
|
48
|
+
"../cpp/webcrypto/crypto_keygen.cpp"
|
|
47
49
|
)
|
|
48
50
|
|
|
49
51
|
target_include_directories(
|
package/cpp/Cipher/MGLRsa.cpp
CHANGED
|
@@ -7,9 +7,15 @@
|
|
|
7
7
|
|
|
8
8
|
#include "MGLRsa.h"
|
|
9
9
|
#ifdef ANDROID
|
|
10
|
+
#include "Cipher/MGLPublicCipher.h"
|
|
10
11
|
#include "JSIUtils/MGLJSIMacros.h"
|
|
12
|
+
#include "JSIUtils/MGLJSIUtils.h"
|
|
13
|
+
#include "Utils/MGLUtils.h"
|
|
11
14
|
#else
|
|
15
|
+
#include "MGLPublicCipher.h"
|
|
12
16
|
#include "MGLJSIMacros.h"
|
|
17
|
+
#include "MGLJSIUtils.h"
|
|
18
|
+
#include "MGLUtils.h"
|
|
13
19
|
#endif
|
|
14
20
|
|
|
15
21
|
#include <string>
|
|
@@ -186,6 +192,125 @@ std::pair<jsi::Value, jsi::Value> generateRsaKeyPair(
|
|
|
186
192
|
return {std::move(publicBuffer), std::move(privateBuffer)};
|
|
187
193
|
}
|
|
188
194
|
|
|
195
|
+
template <MGLPublicCipher::EVP_PKEY_cipher_init_t init,
|
|
196
|
+
MGLPublicCipher::EVP_PKEY_cipher_t cipher>
|
|
197
|
+
WebCryptoCipherStatus RSA_Cipher(const RSACipherConfig& params, ByteSource* out) {
|
|
198
|
+
CHECK_NE(params.key->GetKeyType(), kKeyTypeSecret);
|
|
199
|
+
ManagedEVPPKey m_pkey = params.key->GetAsymmetricKey();
|
|
200
|
+
// Mutex::ScopedLock lock(*m_pkey.mutex());
|
|
201
|
+
|
|
202
|
+
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(m_pkey.get(), nullptr));
|
|
203
|
+
|
|
204
|
+
if (!ctx || init(ctx.get()) <= 0)
|
|
205
|
+
return WebCryptoCipherStatus::FAILED;
|
|
206
|
+
|
|
207
|
+
if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), params.padding) <= 0) {
|
|
208
|
+
return WebCryptoCipherStatus::FAILED;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (params.digest != nullptr &&
|
|
212
|
+
(EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), params.digest) <= 0 ||
|
|
213
|
+
EVP_PKEY_CTX_set_rsa_mgf1_md(ctx.get(), params.digest) <= 0)) {
|
|
214
|
+
return WebCryptoCipherStatus::FAILED;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (!SetRsaOaepLabel(ctx, params.label)) return WebCryptoCipherStatus::FAILED;
|
|
218
|
+
|
|
219
|
+
size_t out_len = 0;
|
|
220
|
+
if (cipher(
|
|
221
|
+
ctx.get(),
|
|
222
|
+
nullptr,
|
|
223
|
+
&out_len,
|
|
224
|
+
params.data.data<unsigned char>(),
|
|
225
|
+
params.data.size()) <= 0) {
|
|
226
|
+
return WebCryptoCipherStatus::FAILED;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
ByteSource::Builder buf(out_len);
|
|
230
|
+
|
|
231
|
+
if (cipher(ctx.get(),
|
|
232
|
+
buf.data<unsigned char>(),
|
|
233
|
+
&out_len,
|
|
234
|
+
params.data.data<unsigned char>(),
|
|
235
|
+
params.data.size()) <= 0) {
|
|
236
|
+
return WebCryptoCipherStatus::FAILED;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
*out = std::move(buf).release(out_len);
|
|
240
|
+
return WebCryptoCipherStatus::OK;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
RSACipherConfig RSACipher::GetParamsFromJS(jsi::Runtime &rt,
|
|
244
|
+
const jsi::Value *args) {
|
|
245
|
+
RSACipherConfig params;
|
|
246
|
+
unsigned int offset = 0;
|
|
247
|
+
|
|
248
|
+
// padding
|
|
249
|
+
params.padding = RSA_PKCS1_OAEP_PADDING;
|
|
250
|
+
|
|
251
|
+
// mode (encrypt/decrypt)
|
|
252
|
+
params.mode = static_cast<WebCryptoCipherMode>((int)args[offset].getNumber());
|
|
253
|
+
offset++;
|
|
254
|
+
|
|
255
|
+
// key (handle)
|
|
256
|
+
if (!args[offset].isObject()) {
|
|
257
|
+
throw std::runtime_error("arg is not a KeyObjectHandle: key");
|
|
258
|
+
}
|
|
259
|
+
std::shared_ptr<KeyObjectHandle> handle =
|
|
260
|
+
std::static_pointer_cast<KeyObjectHandle>(
|
|
261
|
+
args[offset].asObject(rt).getHostObject(rt));
|
|
262
|
+
params.key = handle->Data();
|
|
263
|
+
offset++;
|
|
264
|
+
|
|
265
|
+
// data
|
|
266
|
+
params.data = GetByteSourceFromJS(rt, args[offset], "data");
|
|
267
|
+
offset++;
|
|
268
|
+
|
|
269
|
+
// variant
|
|
270
|
+
if (CheckIsInt32(args[offset])) {
|
|
271
|
+
params.variant = static_cast<RSAKeyVariant>((int)args[offset].getNumber());
|
|
272
|
+
}
|
|
273
|
+
// offset++; // The below variant-dependent params advance offset themselves
|
|
274
|
+
|
|
275
|
+
std::string digest;
|
|
276
|
+
switch (params.variant) {
|
|
277
|
+
case kKeyVariantRSA_OAEP:
|
|
278
|
+
// hash (digest)
|
|
279
|
+
CHECK(args[offset + 1].isString());
|
|
280
|
+
digest = args[offset + 1].asString(rt).utf8(rt);
|
|
281
|
+
params.digest = EVP_get_digestbyname(digest.c_str());
|
|
282
|
+
if (params.digest == nullptr) {
|
|
283
|
+
throw jsi::JSError(rt, "invalid digest: " + digest);
|
|
284
|
+
return params;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// label
|
|
288
|
+
if (args[offset + 2].isUndefined()) {
|
|
289
|
+
params.label = ByteSource();
|
|
290
|
+
} else {
|
|
291
|
+
params.label = GetByteSourceFromJS(rt, args[offset + 2], "label");
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
break;
|
|
295
|
+
default:
|
|
296
|
+
throw jsi::JSError(rt, "Invalid RSA key variant");
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return params;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
WebCryptoCipherStatus RSACipher::DoCipher(const RSACipherConfig ¶ms,
|
|
303
|
+
ByteSource *out) {
|
|
304
|
+
switch (params.mode) {
|
|
305
|
+
case kEncrypt:
|
|
306
|
+
CHECK_EQ(params.key->GetKeyType(), kKeyTypePublic);
|
|
307
|
+
return RSA_Cipher<EVP_PKEY_encrypt_init, EVP_PKEY_encrypt>(params, out);
|
|
308
|
+
case kDecrypt:
|
|
309
|
+
CHECK_EQ(params.key->GetKeyType(), kKeyTypePrivate);
|
|
310
|
+
return RSA_Cipher<EVP_PKEY_decrypt_init, EVP_PKEY_decrypt>(params, out);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
189
314
|
jsi::Value ExportJWKRsaKey(jsi::Runtime &rt,
|
|
190
315
|
std::shared_ptr<KeyObjectData> key,
|
|
191
316
|
jsi::Object &target) {
|
|
@@ -330,12 +455,11 @@ jsi::Value GetRsaKeyDetail(jsi::Runtime &rt,
|
|
|
330
455
|
RSA_get0_key(rsa, &n, &e, nullptr);
|
|
331
456
|
|
|
332
457
|
size_t modulus_length = BN_num_bits(n);
|
|
333
|
-
// TODO: should this be modulusLength or n?
|
|
334
458
|
target.setProperty(rt, "modulusLength", static_cast<double>(modulus_length));
|
|
335
459
|
|
|
336
460
|
size_t exp_size = BN_num_bytes(e);
|
|
337
|
-
|
|
338
|
-
target.setProperty(rt, "publicExponent",
|
|
461
|
+
ByteSource public_exponent = ByteSource::FromBN(e, exp_size);
|
|
462
|
+
target.setProperty(rt, "publicExponent", toJSI(rt, std::move(public_exponent)));
|
|
339
463
|
|
|
340
464
|
if (type == EVP_PKEY_RSA_PSS) {
|
|
341
465
|
// Due to the way ASN.1 encoding works, default values are omitted when
|
|
@@ -394,4 +518,56 @@ jsi::Value GetRsaKeyDetail(jsi::Runtime &rt,
|
|
|
394
518
|
return target;
|
|
395
519
|
}
|
|
396
520
|
|
|
521
|
+
bool RsaKeyExport::GetParamsFromJS(jsi::Runtime &rt, const jsi::Value *args) {
|
|
522
|
+
RsaKeyExportConfig params;
|
|
523
|
+
unsigned int offset = 0;
|
|
524
|
+
|
|
525
|
+
// format
|
|
526
|
+
params.format = static_cast<WebCryptoKeyFormat>((int)args[offset].getNumber());
|
|
527
|
+
offset++;
|
|
528
|
+
|
|
529
|
+
// key
|
|
530
|
+
std::shared_ptr<KeyObjectHandle> handle =
|
|
531
|
+
std::static_pointer_cast<KeyObjectHandle>(
|
|
532
|
+
args[1].asObject(rt).getHostObject(rt));
|
|
533
|
+
params.key_ = handle->Data();
|
|
534
|
+
offset++;
|
|
535
|
+
|
|
536
|
+
// variant
|
|
537
|
+
params.variant = static_cast<KeyVariant>((int)args[offset].getNumber());
|
|
538
|
+
offset++;
|
|
539
|
+
|
|
540
|
+
this->params_ = std::move(params);
|
|
541
|
+
return true;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
WebCryptoKeyExportStatus RsaKeyExport::DoExport(ByteSource* out) {
|
|
545
|
+
auto key_data = this->params_.key_;
|
|
546
|
+
CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret);
|
|
547
|
+
|
|
548
|
+
switch (this->params_.format) {
|
|
549
|
+
case kWebCryptoKeyFormatRaw:
|
|
550
|
+
throw std::runtime_error("Raw format not supported for RSA keys");
|
|
551
|
+
return WebCryptoKeyExportStatus::FAILED;
|
|
552
|
+
case kWebCryptoKeyFormatJWK:
|
|
553
|
+
throw std::runtime_error("JWK format not handled in C++ for RSA keys");
|
|
554
|
+
return WebCryptoKeyExportStatus::FAILED;
|
|
555
|
+
case kWebCryptoKeyFormatPKCS8:
|
|
556
|
+
if (key_data->GetKeyType() != kKeyTypePrivate) {
|
|
557
|
+
throw std::runtime_error("Invalid key type for PKCS8 export");
|
|
558
|
+
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
|
|
559
|
+
}
|
|
560
|
+
return PKEY_PKCS8_Export(key_data.get(), out);
|
|
561
|
+
case kWebCryptoKeyFormatSPKI:
|
|
562
|
+
if (key_data->GetKeyType() != kKeyTypePublic) {
|
|
563
|
+
throw std::runtime_error("Invalid key type for SPKI export");
|
|
564
|
+
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
|
|
565
|
+
}
|
|
566
|
+
return PKEY_SPKI_Export(key_data.get(), out);
|
|
567
|
+
default:
|
|
568
|
+
throw std::runtime_error("Unrecognized format for RSA key export");
|
|
569
|
+
return WebCryptoKeyExportStatus::FAILED;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
397
573
|
} // namespace margelo
|
package/cpp/Cipher/MGLRsa.h
CHANGED
|
@@ -25,6 +25,13 @@ namespace margelo {
|
|
|
25
25
|
|
|
26
26
|
namespace jsi = facebook::jsi;
|
|
27
27
|
|
|
28
|
+
// TODO: keep in in sync with JS side (src/rsa.ts)
|
|
29
|
+
enum RSAKeyVariant {
|
|
30
|
+
kKeyVariantRSA_SSA_PKCS1_v1_5,
|
|
31
|
+
kKeyVariantRSA_PSS,
|
|
32
|
+
kKeyVariantRSA_OAEP
|
|
33
|
+
};
|
|
34
|
+
|
|
28
35
|
// On node there is a complete madness of structs/classes that encapsulate and
|
|
29
36
|
// initialize the data in a generic manner this is to be later be used to
|
|
30
37
|
// generate the keys in a thread-safe manner (I think) I'm however too dumb and
|
|
@@ -64,6 +71,39 @@ std::shared_ptr<KeyObjectData> ImportJWKRsaKey(jsi::Runtime &rt,
|
|
|
64
71
|
jsi::Value GetRsaKeyDetail(jsi::Runtime &rt,
|
|
65
72
|
std::shared_ptr<KeyObjectData> key);
|
|
66
73
|
|
|
74
|
+
struct RsaKeyExportConfig final {
|
|
75
|
+
WebCryptoKeyFormat format;
|
|
76
|
+
std::shared_ptr<KeyObjectData> key_;
|
|
77
|
+
KeyVariant variant;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
class RsaKeyExport {
|
|
81
|
+
public:
|
|
82
|
+
bool GetParamsFromJS(jsi::Runtime &rt, const jsi::Value *args);
|
|
83
|
+
WebCryptoKeyExportStatus DoExport(ByteSource* out);
|
|
84
|
+
private:
|
|
85
|
+
RsaKeyExportConfig params_;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
struct RSACipherConfig final {
|
|
89
|
+
WebCryptoCipherMode mode;
|
|
90
|
+
std::shared_ptr<KeyObjectData> key;
|
|
91
|
+
ByteSource data;
|
|
92
|
+
RSAKeyVariant variant;
|
|
93
|
+
ByteSource label;
|
|
94
|
+
int padding = 0;
|
|
95
|
+
const EVP_MD* digest = nullptr;
|
|
96
|
+
|
|
97
|
+
RSACipherConfig() = default;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
class RSACipher {
|
|
101
|
+
public:
|
|
102
|
+
RSACipher() {}
|
|
103
|
+
RSACipherConfig GetParamsFromJS(jsi::Runtime &rt, const jsi::Value *args);
|
|
104
|
+
WebCryptoCipherStatus DoCipher(const RSACipherConfig ¶ms, ByteSource *out);
|
|
105
|
+
};
|
|
106
|
+
|
|
67
107
|
} // namespace margelo
|
|
68
108
|
|
|
69
109
|
#endif /* MGLRsa_hpp */
|
|
@@ -30,4 +30,12 @@ inline bool CheckIsInt32(const jsi::Value &value) {
|
|
|
30
30
|
return (d >= std::numeric_limits<int32_t>::lowest() && d <= std::numeric_limits<int32_t>::max());
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
inline bool CheckIsUint32(const jsi::Value &value) {
|
|
34
|
+
if (!value.isNumber()) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
double d = value.asNumber();
|
|
38
|
+
return (d >= std::numeric_limits<uint32_t>::lowest() && d <= std::numeric_limits<uint32_t>::max());
|
|
39
|
+
}
|
|
40
|
+
|
|
33
41
|
#endif /* MGLJSIUtils_h */
|
package/cpp/MGLKeys.cpp
CHANGED
|
@@ -562,7 +562,7 @@ jsi::Value ManagedEVPPKey::ToEncodedPublicKey(jsi::Runtime& rt,
|
|
|
562
562
|
// Note that this has the downside of containing sensitive data of the
|
|
563
563
|
// private key.
|
|
564
564
|
auto data = KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key));
|
|
565
|
-
auto handle = KeyObjectHandle::Create(
|
|
565
|
+
auto handle = KeyObjectHandle::Create(data);
|
|
566
566
|
auto out = jsi::Object::createFromHostObject(rt, handle);
|
|
567
567
|
return jsi::Value(std::move(out));
|
|
568
568
|
} else
|
|
@@ -583,7 +583,7 @@ jsi::Value ManagedEVPPKey::ToEncodedPrivateKey(jsi::Runtime& rt,
|
|
|
583
583
|
if (!key) return {};
|
|
584
584
|
if (config.output_key_object_) {
|
|
585
585
|
auto data = KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key));
|
|
586
|
-
auto handle = KeyObjectHandle::Create(
|
|
586
|
+
auto handle = KeyObjectHandle::Create(data);
|
|
587
587
|
auto out = jsi::Object::createFromHostObject(rt, handle);
|
|
588
588
|
return jsi::Value(std::move(out));
|
|
589
589
|
} else
|
|
@@ -696,6 +696,7 @@ ManagedEVPPKey ManagedEVPPKey::GetPublicOrPrivateKeyFromJs(
|
|
|
696
696
|
const jsi::Value* args,
|
|
697
697
|
unsigned int* offset) {
|
|
698
698
|
if (args[*offset].asObject(runtime).isArrayBuffer(runtime)) {
|
|
699
|
+
// data (key) as ArrayBuffer
|
|
699
700
|
auto dataArrayBuffer =
|
|
700
701
|
args[(*offset)++].asObject(runtime).getArrayBuffer(runtime);
|
|
701
702
|
|
|
@@ -703,6 +704,7 @@ ManagedEVPPKey ManagedEVPPKey::GetPublicOrPrivateKeyFromJs(
|
|
|
703
704
|
throw jsi::JSError(runtime, "data is too big");
|
|
704
705
|
}
|
|
705
706
|
|
|
707
|
+
// rest of args for encoding
|
|
706
708
|
NonCopyableMaybe<PrivateKeyEncodingConfig> config_ =
|
|
707
709
|
GetPrivateKeyEncodingFromJs(runtime, args, offset, kKeyContextInput);
|
|
708
710
|
if (config_.IsEmpty()) return ManagedEVPPKey();
|
|
@@ -907,8 +909,7 @@ jsi::Value KeyObjectHandle::get(
|
|
|
907
909
|
// registry->Register(Equals);
|
|
908
910
|
// }
|
|
909
911
|
|
|
910
|
-
std::shared_ptr<KeyObjectHandle> KeyObjectHandle::Create(
|
|
911
|
-
std::shared_ptr<KeyObjectData> data) {
|
|
912
|
+
std::shared_ptr<KeyObjectHandle> KeyObjectHandle::Create(std::shared_ptr<KeyObjectData> data) {
|
|
912
913
|
auto handle = std::make_shared<KeyObjectHandle>();
|
|
913
914
|
handle->data_ = data;
|
|
914
915
|
return handle;
|
|
@@ -932,7 +933,7 @@ const std::shared_ptr<KeyObjectData>& KeyObjectHandle::Data() {
|
|
|
932
933
|
//
|
|
933
934
|
|
|
934
935
|
jsi::Value KeyObjectHandle::Init(jsi::Runtime &rt) {
|
|
935
|
-
return HOSTFN("init",
|
|
936
|
+
return HOSTFN("init", 5) {
|
|
936
937
|
CHECK(args[0].isNumber());
|
|
937
938
|
KeyType type = static_cast<KeyType>((int32_t)args[0].asNumber());
|
|
938
939
|
|
|
@@ -941,15 +942,13 @@ jsi::Value KeyObjectHandle::Init(jsi::Runtime &rt) {
|
|
|
941
942
|
|
|
942
943
|
switch (type) {
|
|
943
944
|
case kKeyTypeSecret: {
|
|
944
|
-
|
|
945
|
-
|
|
945
|
+
CHECK_EQ(count, 2);
|
|
946
946
|
ByteSource key = ByteSource::FromStringOrBuffer(rt, args[1]);
|
|
947
947
|
this->data_ = KeyObjectData::CreateSecret(std::move(key));
|
|
948
948
|
break;
|
|
949
949
|
}
|
|
950
950
|
case kKeyTypePublic: {
|
|
951
|
-
|
|
952
|
-
|
|
951
|
+
CHECK_EQ(count, 5);
|
|
953
952
|
offset = 1;
|
|
954
953
|
pkey = ManagedEVPPKey::GetPublicOrPrivateKeyFromJs(rt, args, &offset);
|
|
955
954
|
if (!pkey)
|
|
@@ -958,8 +957,7 @@ jsi::Value KeyObjectHandle::Init(jsi::Runtime &rt) {
|
|
|
958
957
|
break;
|
|
959
958
|
}
|
|
960
959
|
case kKeyTypePrivate: {
|
|
961
|
-
|
|
962
|
-
|
|
960
|
+
CHECK_EQ(count, 5);
|
|
963
961
|
offset = 1;
|
|
964
962
|
pkey = ManagedEVPPKey::GetPrivateKeyFromJs(rt, args, &offset, false);
|
|
965
963
|
if (!pkey)
|
|
@@ -1167,7 +1165,7 @@ jsi::Value KeyObjectHandle::GetAsymmetricKeyType(jsi::Runtime &rt) const {
|
|
|
1167
1165
|
std::string ret;
|
|
1168
1166
|
switch (EVP_PKEY_id(key.get())) {
|
|
1169
1167
|
case EVP_PKEY_RSA:
|
|
1170
|
-
ret = "
|
|
1168
|
+
ret = "rsa";
|
|
1171
1169
|
break;
|
|
1172
1170
|
case EVP_PKEY_RSA_PSS:
|
|
1173
1171
|
ret = "rsa_pss";
|
|
@@ -1389,37 +1387,37 @@ jsi::Value KeyObjectHandle::ExportJWK(jsi::Runtime &rt) {
|
|
|
1389
1387
|
// return std::make_unique<KeyObjectTransferData>(handle_data_);
|
|
1390
1388
|
//}
|
|
1391
1389
|
//
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
//
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
//
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1390
|
+
WebCryptoKeyExportStatus PKEY_SPKI_Export(KeyObjectData* key_data,
|
|
1391
|
+
ByteSource* out) {
|
|
1392
|
+
CHECK_EQ(key_data->GetKeyType(), kKeyTypePublic);
|
|
1393
|
+
ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey();
|
|
1394
|
+
// Mutex::ScopedLock lock(*m_pkey.mutex());
|
|
1395
|
+
BIOPointer bio(BIO_new(BIO_s_mem()));
|
|
1396
|
+
CHECK(bio);
|
|
1397
|
+
if (!i2d_PUBKEY_bio(bio.get(), m_pkey.get())) {
|
|
1398
|
+
throw std::runtime_error("Failed to export key");
|
|
1399
|
+
return WebCryptoKeyExportStatus::FAILED;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
*out = ByteSource::FromBIO(bio);
|
|
1403
|
+
return WebCryptoKeyExportStatus::OK;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
WebCryptoKeyExportStatus PKEY_PKCS8_Export(
|
|
1407
|
+
KeyObjectData* key_data,
|
|
1408
|
+
ByteSource* out) {
|
|
1409
|
+
CHECK_EQ(key_data->GetKeyType(), kKeyTypePrivate);
|
|
1410
|
+
ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey();
|
|
1411
|
+
// Mutex::ScopedLock lock(*m_pkey.mutex());
|
|
1412
|
+
BIOPointer bio(BIO_new(BIO_s_mem()));
|
|
1413
|
+
CHECK(bio);
|
|
1414
|
+
PKCS8Pointer p8inf(EVP_PKEY2PKCS8(m_pkey.get()));
|
|
1415
|
+
if (!i2d_PKCS8_PRIV_KEY_INFO_bio(bio.get(), p8inf.get()))
|
|
1416
|
+
return WebCryptoKeyExportStatus::FAILED;
|
|
1417
|
+
|
|
1418
|
+
*out = ByteSource::FromBIO(bio);
|
|
1419
|
+
return WebCryptoKeyExportStatus::OK;
|
|
1420
|
+
}
|
|
1423
1421
|
|
|
1424
1422
|
// void RegisterExternalReferences(ExternalReferenceRegistry * registry) {
|
|
1425
1423
|
// KeyObjectHandle::RegisterExternalReferences(registry);
|
package/cpp/MGLKeys.h
CHANGED
|
@@ -168,8 +168,7 @@ class JSI_EXPORT KeyObjectHandle: public jsi::HostObject {
|
|
|
168
168
|
jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propNameID);
|
|
169
169
|
const std::shared_ptr<KeyObjectData>& Data();
|
|
170
170
|
|
|
171
|
-
static std::shared_ptr<KeyObjectHandle> Create(
|
|
172
|
-
std::shared_ptr<KeyObjectData> data);
|
|
171
|
+
static std::shared_ptr<KeyObjectHandle> Create(std::shared_ptr<KeyObjectData> data);
|
|
173
172
|
|
|
174
173
|
protected:
|
|
175
174
|
jsi::Value Export(jsi::Runtime &rt);
|
|
@@ -191,6 +190,14 @@ class JSI_EXPORT KeyObjectHandle: public jsi::HostObject {
|
|
|
191
190
|
std::shared_ptr<KeyObjectData> data_;
|
|
192
191
|
};
|
|
193
192
|
|
|
193
|
+
WebCryptoKeyExportStatus PKEY_SPKI_Export(
|
|
194
|
+
KeyObjectData* key_data,
|
|
195
|
+
ByteSource* out);
|
|
196
|
+
|
|
197
|
+
WebCryptoKeyExportStatus PKEY_PKCS8_Export(
|
|
198
|
+
KeyObjectData* key_data,
|
|
199
|
+
ByteSource* out);
|
|
200
|
+
|
|
194
201
|
} // namespace margelo
|
|
195
202
|
|
|
196
203
|
#endif /* MGLCipherKeys_h */
|
|
@@ -113,12 +113,12 @@ MGLQuickCryptoHostObject::MGLQuickCryptoHostObject(
|
|
|
113
113
|
// createVerify
|
|
114
114
|
this->fields.push_back(getVerifyFieldDefinition(jsCallInvoker, workerQueue));
|
|
115
115
|
|
|
116
|
-
// subtle API
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
116
|
+
// subtle API
|
|
117
|
+
this->fields.push_back(JSI_VALUE("webcrypto", {
|
|
118
|
+
auto hostObject = std::make_shared<MGLWebCryptoHostObject>(
|
|
119
|
+
jsCallInvoker, workerQueue);
|
|
120
|
+
return jsi::Object::createFromHostObject(runtime, hostObject);
|
|
121
|
+
}));
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
} // namespace margelo
|
package/cpp/Utils/MGLUtils.cpp
CHANGED
|
@@ -184,8 +184,29 @@ ByteSource ByteSource::Foreign(const void* data, size_t size) {
|
|
|
184
184
|
return ByteSource(data, nullptr, size);
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
ByteSource ByteSource::FromBN(const BIGNUM* bn, size_t size) {
|
|
188
|
+
std::vector<uint8_t> buf(size);
|
|
189
|
+
CHECK_EQ(BN_bn2binpad(bn, buf.data(), size), size);
|
|
190
|
+
ByteSource::Builder out(size);
|
|
191
|
+
memcpy(out.data<void>(), buf.data(), size);
|
|
192
|
+
return std::move(out).release();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
ByteSource GetByteSourceFromJS(jsi::Runtime &rt,
|
|
196
|
+
const jsi::Value &value,
|
|
197
|
+
std::string name) {
|
|
198
|
+
if (!value.isObject() || !value.asObject(rt).isArrayBuffer(rt)) {
|
|
199
|
+
throw jsi::JSError(rt, "arg is not an array buffer: " + name);
|
|
200
|
+
}
|
|
201
|
+
ByteSource data = ByteSource::FromStringOrBuffer(rt, value);
|
|
202
|
+
if (data.size() > INT_MAX) {
|
|
203
|
+
throw jsi::JSError(rt, "arg is too big (> int32): " + name);
|
|
204
|
+
}
|
|
205
|
+
return data;
|
|
206
|
+
}
|
|
207
|
+
|
|
187
208
|
std::string EncodeBignum(const BIGNUM* bn,
|
|
188
|
-
|
|
209
|
+
size_t size,
|
|
189
210
|
bool url) {
|
|
190
211
|
if (size == 0)
|
|
191
212
|
size = BN_num_bytes(bn);
|
|
@@ -222,4 +243,53 @@ std::string DecodeBase64(const std::string &in, bool remove_linebreaks) {
|
|
|
222
243
|
return base64_decode(in, remove_linebreaks);
|
|
223
244
|
}
|
|
224
245
|
|
|
246
|
+
MUST_USE_RESULT CSPRNGResult CSPRNG(void* buffer, size_t length) {
|
|
247
|
+
unsigned char* buf = static_cast<unsigned char*>(buffer);
|
|
248
|
+
do {
|
|
249
|
+
if (1 == RAND_status()) {
|
|
250
|
+
#if OPENSSL_VERSION_MAJOR >= 3
|
|
251
|
+
if (1 == RAND_bytes_ex(nullptr, buf, length, 0)) return {true};
|
|
252
|
+
#else
|
|
253
|
+
while (length > INT_MAX && 1 == RAND_bytes(buf, INT_MAX)) {
|
|
254
|
+
buf += INT_MAX;
|
|
255
|
+
length -= INT_MAX;
|
|
256
|
+
}
|
|
257
|
+
if (length <= INT_MAX && 1 == RAND_bytes(buf, static_cast<int>(length)))
|
|
258
|
+
return {true};
|
|
259
|
+
#endif
|
|
260
|
+
}
|
|
261
|
+
#if OPENSSL_VERSION_MAJOR >= 3
|
|
262
|
+
const auto code = ERR_peek_last_error();
|
|
263
|
+
// A misconfigured OpenSSL 3 installation may report 1 from RAND_poll()
|
|
264
|
+
// and RAND_status() but fail in RAND_bytes() if it cannot look up
|
|
265
|
+
// a matching algorithm for the CSPRNG.
|
|
266
|
+
if (ERR_GET_LIB(code) == ERR_LIB_RAND) {
|
|
267
|
+
const auto reason = ERR_GET_REASON(code);
|
|
268
|
+
if (reason == RAND_R_ERROR_INSTANTIATING_DRBG ||
|
|
269
|
+
reason == RAND_R_UNABLE_TO_FETCH_DRBG ||
|
|
270
|
+
reason == RAND_R_UNABLE_TO_CREATE_DRBG) {
|
|
271
|
+
return {false};
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
#endif
|
|
275
|
+
} while (1 == RAND_poll());
|
|
276
|
+
|
|
277
|
+
return {false};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
bool SetRsaOaepLabel(const EVPKeyCtxPointer& ctx, const ByteSource& label) {
|
|
281
|
+
if (label.size() != 0) {
|
|
282
|
+
// OpenSSL takes ownership of the label, so we need to create a copy.
|
|
283
|
+
void* label_copy = OPENSSL_memdup(label.data(), label.size());
|
|
284
|
+
CHECK_NOT_NULL(label_copy);
|
|
285
|
+
int ret = EVP_PKEY_CTX_set0_rsa_oaep_label(
|
|
286
|
+
ctx.get(), static_cast<unsigned char*>(label_copy), label.size());
|
|
287
|
+
if (ret <= 0) {
|
|
288
|
+
OPENSSL_free(label_copy);
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
|
|
225
295
|
} // namespace margelo
|
package/cpp/Utils/MGLUtils.h
CHANGED
|
@@ -50,6 +50,27 @@ using EVPMDPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>;
|
|
|
50
50
|
using ECDSASigPointer = DeleteFnPtr<ECDSA_SIG, ECDSA_SIG_free>;
|
|
51
51
|
using ECKeyPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
|
|
52
52
|
using ECPointPointer = DeleteFnPtr<EC_POINT, EC_POINT_free>;
|
|
53
|
+
using CipherCtxPointer = DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>;
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
#ifdef __GNUC__
|
|
57
|
+
#define MUST_USE_RESULT __attribute__((warn_unused_result))
|
|
58
|
+
#else
|
|
59
|
+
#define MUST_USE_RESULT
|
|
60
|
+
#endif
|
|
61
|
+
|
|
62
|
+
struct CSPRNGResult {
|
|
63
|
+
const bool ok;
|
|
64
|
+
MUST_USE_RESULT bool is_ok() const { return ok; }
|
|
65
|
+
MUST_USE_RESULT bool is_err() const { return !ok; }
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Either succeeds with exactly |length| bytes of cryptographically
|
|
69
|
+
// strong pseudo-random data, or fails. This function may block.
|
|
70
|
+
// Don't assume anything about the contents of |buffer| on error.
|
|
71
|
+
// As a special case, |length == 0| can be used to check if the CSPRNG
|
|
72
|
+
// is properly seeded without consuming entropy.
|
|
73
|
+
MUST_USE_RESULT CSPRNGResult CSPRNG(void* buffer, size_t length);
|
|
53
74
|
|
|
54
75
|
template <typename T>
|
|
55
76
|
class NonCopyableMaybe {
|
|
@@ -198,6 +219,8 @@ class ByteSource {
|
|
|
198
219
|
|
|
199
220
|
static ByteSource FromBIO(const BIOPointer& bio);
|
|
200
221
|
|
|
222
|
+
static ByteSource FromBN(const BIGNUM* bn, size_t size);
|
|
223
|
+
|
|
201
224
|
// static ByteSource NullTerminatedCopy(Environment* env,
|
|
202
225
|
// v8::Local<v8::Value> value);
|
|
203
226
|
//
|
|
@@ -281,13 +304,19 @@ inline jsi::Value toJSI(jsi::Runtime& rt, ByteSource value) {
|
|
|
281
304
|
return o;
|
|
282
305
|
}
|
|
283
306
|
|
|
307
|
+
ByteSource GetByteSourceFromJS(jsi::Runtime &rt,
|
|
308
|
+
const jsi::Value &value,
|
|
309
|
+
std::string name);
|
|
310
|
+
|
|
284
311
|
std::string EncodeBignum(const BIGNUM* bn,
|
|
285
|
-
|
|
312
|
+
size_t size,
|
|
286
313
|
bool url = false);
|
|
287
314
|
|
|
288
315
|
std::string EncodeBase64(const std::string data, bool url = false);
|
|
289
316
|
std::string DecodeBase64(const std::string &in, bool remove_linebreaks = false);
|
|
290
317
|
|
|
318
|
+
bool SetRsaOaepLabel(const EVPKeyCtxPointer& ctx, const ByteSource& label);
|
|
319
|
+
|
|
291
320
|
// TODO: until shared, keep in sync with JS side (src/NativeQuickCrypto/Cipher.ts)
|
|
292
321
|
enum KeyVariant {
|
|
293
322
|
kvRSA_SSA_PKCS1_v1_5,
|
|
@@ -299,6 +328,31 @@ enum KeyVariant {
|
|
|
299
328
|
kvDH,
|
|
300
329
|
};
|
|
301
330
|
|
|
331
|
+
enum FnMode {
|
|
332
|
+
kAsync,
|
|
333
|
+
kSync,
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
enum WebCryptoKeyFormat {
|
|
337
|
+
kWebCryptoKeyFormatRaw,
|
|
338
|
+
kWebCryptoKeyFormatPKCS8,
|
|
339
|
+
kWebCryptoKeyFormatSPKI,
|
|
340
|
+
kWebCryptoKeyFormatJWK
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
enum WebCryptoCipherMode {
|
|
344
|
+
kEncrypt,
|
|
345
|
+
kDecrypt,
|
|
346
|
+
// kWrapKey,
|
|
347
|
+
// kUnwrapKey,
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
enum class WebCryptoCipherStatus {
|
|
351
|
+
OK,
|
|
352
|
+
INVALID_KEY_TYPE,
|
|
353
|
+
FAILED
|
|
354
|
+
};
|
|
355
|
+
|
|
302
356
|
} // namespace margelo
|
|
303
357
|
|
|
304
358
|
#endif /* MGLUtils_h */
|