react-native-quick-crypto 0.2.0 → 0.3.0
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/README.md +23 -6
- package/cpp/Cipher/MGLCipherHostObject.cpp +64 -48
- package/cpp/Cipher/MGLCipherKeys.cpp +1469 -0
- package/cpp/Cipher/MGLCipherKeys.h +124 -0
- package/cpp/Cipher/MGLCreateCipherInstaller.cpp +56 -53
- package/cpp/Cipher/MGLCreateCipherInstaller.h +5 -0
- package/cpp/Cipher/MGLCreateDecipherInstaller.cpp +56 -53
- package/cpp/Cipher/MGLGenerateKeyPairInstaller.cpp +107 -0
- package/cpp/Cipher/MGLGenerateKeyPairInstaller.h +32 -0
- package/cpp/Cipher/MGLGenerateKeyPairSyncInstaller.cpp +60 -0
- package/cpp/Cipher/MGLGenerateKeyPairSyncInstaller.h +35 -0
- package/cpp/Cipher/MGLPublicCipher.h +120 -0
- package/cpp/Cipher/MGLPublicCipherInstaller.h +113 -0
- package/cpp/Cipher/MGLRsa.cpp +188 -0
- package/cpp/Cipher/MGLRsa.h +61 -0
- package/cpp/JSIUtils/MGLJSIUtils.h +24 -0
- package/cpp/JSIUtils/MGLThreadAwareHostObject.h +1 -1
- package/cpp/MGLQuickCryptoHostObject.cpp +42 -3
- package/cpp/Utils/MGLUtils.cpp +156 -0
- package/cpp/Utils/MGLUtils.h +254 -0
- package/lib/commonjs/Cipher.js +307 -0
- package/lib/commonjs/Cipher.js.map +1 -1
- package/lib/commonjs/NativeQuickCrypto/Cipher.js +11 -0
- package/lib/commonjs/NativeQuickCrypto/Cipher.js.map +1 -1
- package/lib/commonjs/NativeQuickCrypto/NativeQuickCrypto.js.map +1 -1
- package/lib/commonjs/QuickCrypto.js +8 -0
- package/lib/commonjs/QuickCrypto.js.map +1 -1
- package/lib/commonjs/Utils.js +82 -1
- package/lib/commonjs/Utils.js.map +1 -1
- package/lib/commonjs/constants.js +86 -0
- package/lib/commonjs/constants.js.map +1 -0
- package/lib/commonjs/index.js +5 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/keys.js +207 -0
- package/lib/commonjs/keys.js.map +1 -0
- package/lib/module/Cipher.js +296 -3
- package/lib/module/Cipher.js.map +1 -1
- package/lib/module/NativeQuickCrypto/Cipher.js +9 -1
- package/lib/module/NativeQuickCrypto/Cipher.js.map +1 -1
- package/lib/module/NativeQuickCrypto/NativeQuickCrypto.js.map +1 -1
- package/lib/module/QuickCrypto.js +8 -1
- package/lib/module/QuickCrypto.js.map +1 -1
- package/lib/module/Utils.js +67 -1
- package/lib/module/Utils.js.map +1 -1
- package/lib/module/constants.js +79 -0
- package/lib/module/constants.js.map +1 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/keys.js +193 -0
- package/lib/module/keys.js.map +1 -0
- package/lib/typescript/Cipher.d.ts +58 -1
- package/lib/typescript/NativeQuickCrypto/Cipher.d.ts +10 -0
- package/lib/typescript/NativeQuickCrypto/NativeQuickCrypto.d.ts +6 -1
- package/lib/typescript/QuickCrypto.d.ts +105 -1
- package/lib/typescript/Utils.d.ts +11 -0
- package/lib/typescript/constants.d.ts +75 -0
- package/lib/typescript/index.d.ts +2 -0
- package/lib/typescript/keys.d.ts +60 -0
- package/package.json +5 -5
- package/react-native-quick-crypto.podspec +1 -1
- package/src/.DS_Store +0 -0
- package/src/Cipher.ts +444 -3
- package/src/NativeQuickCrypto/Cipher.ts +44 -0
- package/src/NativeQuickCrypto/NativeQuickCrypto.ts +13 -1
- package/src/QuickCrypto.ts +12 -0
- package/src/Utils.ts +91 -0
- package/src/constants.ts +79 -0
- package/src/index.ts +4 -0
- package/src/keys.ts +297 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
//
|
|
2
|
+
// MGLPublicCipher.h
|
|
3
|
+
// react-native-fast-crypto
|
|
4
|
+
//
|
|
5
|
+
// Created by Oscar on 17.06.22.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#ifndef MGLPublicCipher_h
|
|
9
|
+
#define MGLPublicCipher_h
|
|
10
|
+
|
|
11
|
+
#include <jsi/jsi.h>
|
|
12
|
+
#include <openssl/evp.h>
|
|
13
|
+
|
|
14
|
+
#include <optional>
|
|
15
|
+
#include <vector>
|
|
16
|
+
|
|
17
|
+
#include "MGLCipherKeys.h"
|
|
18
|
+
#ifdef ANDROID
|
|
19
|
+
#include "JSIUtils/MGLJSIUtils.h"
|
|
20
|
+
#include "JSIUtils/MGLTypedArray.h"
|
|
21
|
+
#else
|
|
22
|
+
#include "MGLJSIUtils.h"
|
|
23
|
+
#include "MGLTypedArray.h"
|
|
24
|
+
#include "logs.h"
|
|
25
|
+
#endif
|
|
26
|
+
|
|
27
|
+
namespace margelo {
|
|
28
|
+
|
|
29
|
+
namespace jsi = facebook::jsi;
|
|
30
|
+
|
|
31
|
+
class MGLPublicCipher {
|
|
32
|
+
public:
|
|
33
|
+
typedef int (*EVP_PKEY_cipher_init_t)(EVP_PKEY_CTX* ctx);
|
|
34
|
+
typedef int (*EVP_PKEY_cipher_t)(EVP_PKEY_CTX* ctx, unsigned char* out,
|
|
35
|
+
size_t* outlen, const unsigned char* in,
|
|
36
|
+
size_t inlen);
|
|
37
|
+
|
|
38
|
+
enum Operation { kPublic, kPrivate };
|
|
39
|
+
|
|
40
|
+
template <Operation operation, EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
|
|
41
|
+
EVP_PKEY_cipher_t EVP_PKEY_cipher>
|
|
42
|
+
static std::optional<jsi::Value> Cipher(jsi::Runtime& runtime,
|
|
43
|
+
const ManagedEVPPKey& pkey,
|
|
44
|
+
int padding, const EVP_MD* digest,
|
|
45
|
+
const jsi::Value& oaep_label,
|
|
46
|
+
jsi::ArrayBuffer& data);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
template <MGLPublicCipher::Operation operation,
|
|
50
|
+
MGLPublicCipher::EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
|
|
51
|
+
MGLPublicCipher::EVP_PKEY_cipher_t EVP_PKEY_cipher>
|
|
52
|
+
std::optional<jsi::Value> MGLPublicCipher::Cipher(jsi::Runtime& runtime,
|
|
53
|
+
const ManagedEVPPKey& pkey,
|
|
54
|
+
int padding,
|
|
55
|
+
const EVP_MD* digest,
|
|
56
|
+
const jsi::Value& oaep_label,
|
|
57
|
+
jsi::ArrayBuffer& data) {
|
|
58
|
+
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
|
|
59
|
+
|
|
60
|
+
if (!ctx) {
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (EVP_PKEY_cipher_init(ctx.get()) <= 0) {
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), padding) <= 0) {
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (digest != nullptr) {
|
|
73
|
+
if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), digest) <= 0) {
|
|
74
|
+
return {};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!oaep_label.isUndefined()) {
|
|
79
|
+
auto oaep_label_buffer =
|
|
80
|
+
oaep_label.asObject(runtime).getArrayBuffer(runtime);
|
|
81
|
+
// OpenSSL takes ownership of the label, so we need to create a copy.
|
|
82
|
+
void* label = OPENSSL_memdup(oaep_label_buffer.data(runtime),
|
|
83
|
+
oaep_label_buffer.size(runtime));
|
|
84
|
+
if (label == nullptr) {
|
|
85
|
+
throw new jsi::JSError(runtime, "Error openSSL memdump oaep label");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (0 >= EVP_PKEY_CTX_set0_rsa_oaep_label(
|
|
89
|
+
ctx.get(), static_cast<unsigned char*>(label),
|
|
90
|
+
static_cast<int>(oaep_label_buffer.size(runtime)))) {
|
|
91
|
+
OPENSSL_free(label);
|
|
92
|
+
return {};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// First pass without storing to get the out_len
|
|
97
|
+
size_t out_len = 0;
|
|
98
|
+
if (EVP_PKEY_cipher(ctx.get(), nullptr, &out_len, data.data(runtime),
|
|
99
|
+
data.size(runtime)) <= 0) {
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
std::vector<unsigned char> out_vec(out_len);
|
|
104
|
+
|
|
105
|
+
if (EVP_PKEY_cipher(ctx.get(), out_vec.data(), &out_len, data.data(runtime),
|
|
106
|
+
data.size(runtime)) <= 0) {
|
|
107
|
+
return {};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// trim unnecessary data
|
|
111
|
+
std::vector<unsigned char> helper_vec(out_vec.data(),
|
|
112
|
+
out_vec.data() + out_len);
|
|
113
|
+
MGLTypedArray<MGLTypedArrayKind::Uint8Array> outBuffer(runtime, out_len);
|
|
114
|
+
outBuffer.update(runtime, helper_vec);
|
|
115
|
+
|
|
116
|
+
return outBuffer;
|
|
117
|
+
}
|
|
118
|
+
} // namespace margelo
|
|
119
|
+
|
|
120
|
+
#endif /* MGLPublicCipher_h */
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
//
|
|
2
|
+
// MGLPrivateDecryptInstaller.h
|
|
3
|
+
// react-native-quick-crypto
|
|
4
|
+
//
|
|
5
|
+
// Created by Oscar on 28.06.22.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#ifndef MGLPublicCipherInstaller_h
|
|
9
|
+
#define MGLPublicCipherInstaller_h
|
|
10
|
+
|
|
11
|
+
#include <jsi/jsi.h>
|
|
12
|
+
#include <openssl/evp.h>
|
|
13
|
+
|
|
14
|
+
#include <iostream>
|
|
15
|
+
#include <memory>
|
|
16
|
+
#include <optional>
|
|
17
|
+
#include <string>
|
|
18
|
+
#include <utility>
|
|
19
|
+
#include <vector>
|
|
20
|
+
|
|
21
|
+
#include "MGLCipherKeys.h"
|
|
22
|
+
#include "MGLPublicCipher.h"
|
|
23
|
+
|
|
24
|
+
#ifdef ANDROID
|
|
25
|
+
#include "JSIUtils/MGLJSIUtils.h"
|
|
26
|
+
#include "JSIUtils/MGLSmartHostObject.h"
|
|
27
|
+
#include "JSIUtils/MGLTypedArray.h"
|
|
28
|
+
#else
|
|
29
|
+
#include "MGLJSIUtils.h"
|
|
30
|
+
#include "MGLSmartHostObject.h"
|
|
31
|
+
#include "MGLTypedArray.h"
|
|
32
|
+
#endif
|
|
33
|
+
|
|
34
|
+
namespace margelo {
|
|
35
|
+
namespace jsi = facebook::jsi;
|
|
36
|
+
|
|
37
|
+
// "publicEncrypt", "publicDecrypt", "privateEncrypt", "privateDecrypt" all use
|
|
38
|
+
// the same key extraction logic, only vary in the final openSSL call, so this
|
|
39
|
+
// is a template that accepts and incoming template function, think of it as a
|
|
40
|
+
// weird lambda before real lambdas Because this is a template, the
|
|
41
|
+
// implementation needs to be in this header to prevent linker failure
|
|
42
|
+
template <MGLPublicCipher::Operation operation,
|
|
43
|
+
MGLPublicCipher::EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
|
|
44
|
+
MGLPublicCipher::EVP_PKEY_cipher_t EVP_PKEY_cipher>
|
|
45
|
+
FieldDefinition getPublicCipherFieldDefinition(
|
|
46
|
+
std::string name, std::shared_ptr<react::CallInvoker> jsCallInvoker,
|
|
47
|
+
std::shared_ptr<DispatchQueue::dispatch_queue> workerQueue) {
|
|
48
|
+
return buildPair(
|
|
49
|
+
name, JSIF([=]) {
|
|
50
|
+
// there is a variable amount of parameters passed depending on the
|
|
51
|
+
// scheme therefore making param validation on this level makes little
|
|
52
|
+
// sense everything should be done on JS, which makes this a bit unsafe
|
|
53
|
+
// but it's acceptable
|
|
54
|
+
unsigned int offset = 0;
|
|
55
|
+
|
|
56
|
+
ManagedEVPPKey pkey = ManagedEVPPKey::GetPublicOrPrivateKeyFromJs(
|
|
57
|
+
runtime, arguments, &offset);
|
|
58
|
+
|
|
59
|
+
if (!pkey) {
|
|
60
|
+
jsi::detail::throwJSError(runtime, "Could not generate key");
|
|
61
|
+
throw new jsi::JSError(runtime, "Could not generate key");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
auto buf = arguments[offset].asObject(runtime).getArrayBuffer(runtime);
|
|
65
|
+
if (!CheckSizeInt32(runtime, buf)) {
|
|
66
|
+
jsi::detail::throwJSError(runtime, "Data buffer is too long");
|
|
67
|
+
throw new jsi::JSError(runtime, "Data buffer is too long");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
uint32_t padding =
|
|
71
|
+
static_cast<uint32_t>(arguments[offset + 1].getNumber());
|
|
72
|
+
if (!padding) {
|
|
73
|
+
jsi::detail::throwJSError(runtime, "Invalid padding");
|
|
74
|
+
throw new jsi::JSError(runtime, "Invalid padding");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const EVP_MD* digest = nullptr;
|
|
78
|
+
if (arguments[offset + 2].isString()) {
|
|
79
|
+
auto oaep_str =
|
|
80
|
+
arguments[offset + 2].getString(runtime).utf8(runtime);
|
|
81
|
+
|
|
82
|
+
digest = EVP_get_digestbyname(oaep_str.c_str());
|
|
83
|
+
if (digest == nullptr) {
|
|
84
|
+
jsi::detail::throwJSError(runtime, "Invalid digest (oaep_str)");
|
|
85
|
+
throw new jsi::JSError(runtime, "Invalid digest (oaep_str)");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!arguments[offset + 3].isUndefined()) {
|
|
90
|
+
auto oaep_label_buffer =
|
|
91
|
+
arguments[offset + 3].getObject(runtime).getArrayBuffer(runtime);
|
|
92
|
+
if (!CheckSizeInt32(runtime, oaep_label_buffer)) {
|
|
93
|
+
jsi::detail::throwJSError(runtime, "oaep_label buffer is too long");
|
|
94
|
+
throw new jsi::JSError(runtime, "oaep_label buffer is too long");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
std::optional<jsi::Value> out =
|
|
99
|
+
MGLPublicCipher::Cipher<operation, EVP_PKEY_cipher_init,
|
|
100
|
+
EVP_PKEY_cipher>(
|
|
101
|
+
runtime, pkey, padding, digest, arguments[offset + 3], buf);
|
|
102
|
+
|
|
103
|
+
if (!out.has_value()) {
|
|
104
|
+
jsi::detail::throwJSError(runtime, "Failed to decrypt");
|
|
105
|
+
throw new jsi::JSError(runtime, "Failed to decrypt");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return out.value().getObject(runtime);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
} // namespace margelo
|
|
112
|
+
|
|
113
|
+
#endif /* MGLPublicCipherInstaller_h */
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
//
|
|
2
|
+
// MGLRsa.cpp
|
|
3
|
+
// react-native-quick-crypto
|
|
4
|
+
//
|
|
5
|
+
// Created by Oscar on 22.06.22.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#include "MGLRsa.h"
|
|
9
|
+
|
|
10
|
+
#include <utility>
|
|
11
|
+
|
|
12
|
+
namespace margelo {
|
|
13
|
+
|
|
14
|
+
namespace jsi = facebook::jsi;
|
|
15
|
+
|
|
16
|
+
EVPKeyCtxPointer setup(std::shared_ptr<RsaKeyPairGenConfig> config) {
|
|
17
|
+
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new_id(
|
|
18
|
+
config->variant == kKeyVariantRSA_PSS ? EVP_PKEY_RSA_PSS : EVP_PKEY_RSA,
|
|
19
|
+
nullptr));
|
|
20
|
+
|
|
21
|
+
if (EVP_PKEY_keygen_init(ctx.get()) <= 0) return EVPKeyCtxPointer();
|
|
22
|
+
|
|
23
|
+
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), config->modulus_bits) <= 0) {
|
|
24
|
+
return EVPKeyCtxPointer();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 0x10001 is the default RSA exponent.
|
|
28
|
+
if (config->exponent != 0x10001) {
|
|
29
|
+
BignumPointer bn(BN_new());
|
|
30
|
+
// CHECK_NOT_NULL(bn.get());
|
|
31
|
+
BN_set_word(bn.get(), config->exponent);
|
|
32
|
+
// EVP_CTX accepts ownership of bn on success.
|
|
33
|
+
if (EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx.get(), bn.get()) <= 0) {
|
|
34
|
+
return EVPKeyCtxPointer();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
bn.release();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (config->variant == kKeyVariantRSA_PSS) {
|
|
41
|
+
if (config->md != nullptr &&
|
|
42
|
+
EVP_PKEY_CTX_set_rsa_pss_keygen_md(ctx.get(), config->md) <= 0) {
|
|
43
|
+
return EVPKeyCtxPointer();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// TODO(tniessen): This appears to only be necessary in OpenSSL 3, while
|
|
47
|
+
// OpenSSL 1.1.1 behaves as recommended by RFC 8017 and defaults the MGF1
|
|
48
|
+
// hash algorithm to the RSA-PSS hashAlgorithm. Remove this code if the
|
|
49
|
+
// behavior of OpenSSL 3 changes.
|
|
50
|
+
const EVP_MD* mgf1_md = config->mgf1_md;
|
|
51
|
+
if (mgf1_md == nullptr && config->md != nullptr) {
|
|
52
|
+
mgf1_md = config->md;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (mgf1_md != nullptr &&
|
|
56
|
+
EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md(ctx.get(), mgf1_md) <= 0) {
|
|
57
|
+
return EVPKeyCtxPointer();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
int saltlen = config->saltlen;
|
|
61
|
+
if (saltlen < 0 && config->md != nullptr) {
|
|
62
|
+
saltlen = EVP_MD_size(config->md);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (saltlen >= 0 &&
|
|
66
|
+
EVP_PKEY_CTX_set_rsa_pss_keygen_saltlen(ctx.get(), saltlen) <= 0) {
|
|
67
|
+
return EVPKeyCtxPointer();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return ctx;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
RsaKeyPairGenConfig prepareRsaKeyGenConfig(jsi::Runtime& runtime,
|
|
75
|
+
const jsi::Value* arguments) {
|
|
76
|
+
RsaKeyPairGenConfig config = RsaKeyPairGenConfig();
|
|
77
|
+
|
|
78
|
+
// This is a funky one: depending on which encryption scheme you are
|
|
79
|
+
// using, there is a variable number of arguments that will need to be
|
|
80
|
+
// parsed, therefore this pointer will be used by the internal functions
|
|
81
|
+
// as they go reading the arguments based on the selected scheme. I
|
|
82
|
+
// tried to keep as close to the node implementation to make future
|
|
83
|
+
// debugging easier
|
|
84
|
+
unsigned int offset = 0;
|
|
85
|
+
|
|
86
|
+
// TODO(osp)
|
|
87
|
+
// CHECK(args[*offset]->IsUint32()); // Variant
|
|
88
|
+
// CHECK(args[*offset + 1]->IsUint32()); // Modulus bits
|
|
89
|
+
// CHECK(args[*offset + 2]->IsUint32()); // Exponent
|
|
90
|
+
config.variant =
|
|
91
|
+
static_cast<RSAKeyVariant>((int)arguments[offset].asNumber());
|
|
92
|
+
|
|
93
|
+
// TODO(osp)
|
|
94
|
+
// CHECK_IMPLIES(params->params.variant != kKeyVariantRSA_PSS,
|
|
95
|
+
// args.Length() == 10);
|
|
96
|
+
// CHECK_IMPLIES(params->params.variant == kKeyVariantRSA_PSS,
|
|
97
|
+
// args.Length() == 13);
|
|
98
|
+
config.modulus_bits =
|
|
99
|
+
static_cast<unsigned int>(arguments[offset + 1].asNumber());
|
|
100
|
+
config.exponent = static_cast<unsigned int>(arguments[offset + 2].asNumber());
|
|
101
|
+
|
|
102
|
+
offset += 3;
|
|
103
|
+
|
|
104
|
+
if (config.variant == kKeyVariantRSA_PSS) {
|
|
105
|
+
if (!arguments[offset].isUndefined()) {
|
|
106
|
+
// TODO(osp) CHECK(string)
|
|
107
|
+
config.md = EVP_get_digestbyname(
|
|
108
|
+
arguments[offset].asString(runtime).utf8(runtime).c_str());
|
|
109
|
+
|
|
110
|
+
if (config.md == nullptr) {
|
|
111
|
+
jsi::detail::throwJSError(runtime, "invalid digest");
|
|
112
|
+
throw new jsi::JSError(runtime, "invalid digest");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!arguments[offset + 1].isUndefined()) {
|
|
117
|
+
// TODO(osp) CHECK(string)
|
|
118
|
+
config.mgf1_md = EVP_get_digestbyname(
|
|
119
|
+
arguments[offset + 1].asString(runtime).utf8(runtime).c_str());
|
|
120
|
+
|
|
121
|
+
if (config.mgf1_md == nullptr) {
|
|
122
|
+
jsi::detail::throwJSError(runtime, "invalid digest");
|
|
123
|
+
throw new jsi::JSError(runtime, "invalid digest");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!arguments[offset + 2].isUndefined()) {
|
|
128
|
+
// CHECK(args[*offset + 2]->IsInt32());
|
|
129
|
+
config.saltlen = static_cast<int>(arguments[offset + 2].asNumber());
|
|
130
|
+
|
|
131
|
+
if (config.saltlen < 0) {
|
|
132
|
+
jsi::detail::throwJSError(runtime, "salt length is out of range");
|
|
133
|
+
throw new jsi::JSError(runtime, "salt length is out of range");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
offset += 3;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
config.public_key_encoding = ManagedEVPPKey::GetPublicKeyEncodingFromJs(
|
|
141
|
+
runtime, arguments, &offset, kKeyContextGenerate);
|
|
142
|
+
|
|
143
|
+
auto private_key_encoding = ManagedEVPPKey::GetPrivateKeyEncodingFromJs(
|
|
144
|
+
runtime, arguments, &offset, kKeyContextGenerate);
|
|
145
|
+
|
|
146
|
+
if (!private_key_encoding.IsEmpty()) {
|
|
147
|
+
config.private_key_encoding = private_key_encoding.Release();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return config;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
std::pair<StringOrBuffer, StringOrBuffer> generateRSAKeyPair(
|
|
154
|
+
jsi::Runtime& runtime, std::shared_ptr<RsaKeyPairGenConfig> config) {
|
|
155
|
+
CheckEntropy();
|
|
156
|
+
|
|
157
|
+
EVPKeyCtxPointer ctx = setup(config);
|
|
158
|
+
|
|
159
|
+
if (!ctx) {
|
|
160
|
+
jsi::detail::throwJSError(runtime, "Error on key generation job");
|
|
161
|
+
throw new jsi::JSError(runtime, "Error on key generation job");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Generate the key
|
|
165
|
+
EVP_PKEY* pkey = nullptr;
|
|
166
|
+
if (!EVP_PKEY_keygen(ctx.get(), &pkey)) {
|
|
167
|
+
jsi::detail::throwJSError(runtime, "Error generating key");
|
|
168
|
+
throw new jsi::JSError(runtime, "Error generating key");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
config->key = ManagedEVPPKey(EVPKeyPointer(pkey));
|
|
172
|
+
|
|
173
|
+
std::optional<StringOrBuffer> publicBuffer =
|
|
174
|
+
ManagedEVPPKey::ToEncodedPublicKey(runtime, std::move(config->key),
|
|
175
|
+
config->public_key_encoding);
|
|
176
|
+
std::optional<StringOrBuffer> privateBuffer =
|
|
177
|
+
ManagedEVPPKey::ToEncodedPrivateKey(runtime, std::move(config->key),
|
|
178
|
+
config->private_key_encoding);
|
|
179
|
+
|
|
180
|
+
if (!publicBuffer.has_value() || !privateBuffer.has_value()) {
|
|
181
|
+
jsi::detail::throwJSError(runtime,
|
|
182
|
+
"Failed to encode public and/or private key");
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return std::make_pair(publicBuffer.value(), privateBuffer.value());
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
} // namespace margelo
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
//
|
|
2
|
+
// MGLRsa.hpp
|
|
3
|
+
// react-native-quick-crypto
|
|
4
|
+
//
|
|
5
|
+
// Created by Oscar on 22.06.22.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#ifndef MGLRsa_hpp
|
|
9
|
+
#define MGLRsa_hpp
|
|
10
|
+
|
|
11
|
+
#include <jsi/jsi.h>
|
|
12
|
+
|
|
13
|
+
#include <memory>
|
|
14
|
+
#include <optional>
|
|
15
|
+
#include <utility>
|
|
16
|
+
|
|
17
|
+
#include "MGLCipherKeys.h"
|
|
18
|
+
#include "MGLUtils.h"
|
|
19
|
+
|
|
20
|
+
namespace margelo {
|
|
21
|
+
|
|
22
|
+
namespace jsi = facebook::jsi;
|
|
23
|
+
|
|
24
|
+
enum RSAKeyVariant {
|
|
25
|
+
kKeyVariantRSA_SSA_PKCS1_v1_5,
|
|
26
|
+
kKeyVariantRSA_PSS,
|
|
27
|
+
kKeyVariantRSA_OAEP
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// On node there is a complete madness of structs/classes that encapsulate and
|
|
31
|
+
// initialize the data in a generic manner this is to be later be used to
|
|
32
|
+
// generate the keys in a thread-safe manner (I think) I'm however too dumb and
|
|
33
|
+
// after ~4hrs I have given up on trying to replicate/extract the important
|
|
34
|
+
// parts For now I'm storing a single config param, a generic abstractino is
|
|
35
|
+
// necessary for more schemes. this struct is just a very simplified version
|
|
36
|
+
// meant to carry information around
|
|
37
|
+
struct RsaKeyPairGenConfig {
|
|
38
|
+
PublicKeyEncodingConfig public_key_encoding;
|
|
39
|
+
PrivateKeyEncodingConfig private_key_encoding;
|
|
40
|
+
ManagedEVPPKey key;
|
|
41
|
+
|
|
42
|
+
RSAKeyVariant variant;
|
|
43
|
+
unsigned int modulus_bits;
|
|
44
|
+
unsigned int exponent;
|
|
45
|
+
|
|
46
|
+
// The following options are used for RSA-PSS. If any of them are set, a
|
|
47
|
+
// RSASSA-PSS-params sequence will be added to the key.
|
|
48
|
+
const EVP_MD* md = nullptr;
|
|
49
|
+
const EVP_MD* mgf1_md = nullptr;
|
|
50
|
+
int saltlen = -1;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
RsaKeyPairGenConfig prepareRsaKeyGenConfig(jsi::Runtime& runtime,
|
|
54
|
+
const jsi::Value* arguments);
|
|
55
|
+
|
|
56
|
+
std::pair<StringOrBuffer, StringOrBuffer> generateRSAKeyPair(
|
|
57
|
+
jsi::Runtime& runtime, std::shared_ptr<RsaKeyPairGenConfig> config);
|
|
58
|
+
|
|
59
|
+
} // namespace margelo
|
|
60
|
+
|
|
61
|
+
#endif /* MGLRsa_hpp */
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//
|
|
2
|
+
// MGLJSIUtils.h
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Oscar on 20.06.22.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#ifndef MGLJSIUtils_h
|
|
9
|
+
#define MGLJSIUtils_h
|
|
10
|
+
|
|
11
|
+
#include <jsi/jsi.h>
|
|
12
|
+
|
|
13
|
+
namespace jsi = facebook::jsi;
|
|
14
|
+
|
|
15
|
+
inline bool CheckIsArrayBuffer(jsi::Runtime &runtime, const jsi::Value &value) {
|
|
16
|
+
return !value.isNull() && !value.isUndefined() && value.isObject() &&
|
|
17
|
+
value.asObject(runtime).isArrayBuffer(runtime);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
inline bool CheckSizeInt32(jsi::Runtime &runtime, jsi::ArrayBuffer &buffer) {
|
|
21
|
+
return buffer.size(runtime) <= INT_MAX;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
#endif /* MGLJSIUtils_h */
|
|
@@ -5,11 +5,14 @@
|
|
|
5
5
|
#include <jsi/jsi.h>
|
|
6
6
|
|
|
7
7
|
#include <memory>
|
|
8
|
+
#include <string>
|
|
8
9
|
#include <vector>
|
|
9
10
|
|
|
10
11
|
#ifdef ANDROID
|
|
11
12
|
#include "Cipher/MGLCreateCipherInstaller.h"
|
|
12
13
|
#include "Cipher/MGLCreateDecipherInstaller.h"
|
|
14
|
+
#include "Cipher/MGLPublicCipher.h"
|
|
15
|
+
#include "Cipher/MGLPublicCipherInstaller.h"
|
|
13
16
|
#include "HMAC/MGLHmacInstaller.h"
|
|
14
17
|
#include "Hash/MGLHashInstaller.h"
|
|
15
18
|
#include "Random/MGLRandomHostObject.h"
|
|
@@ -17,11 +20,14 @@
|
|
|
17
20
|
#else
|
|
18
21
|
#include "MGLCreateCipherInstaller.h"
|
|
19
22
|
#include "MGLCreateDecipherInstaller.h"
|
|
23
|
+
#include "MGLGenerateKeyPairInstaller.h"
|
|
24
|
+
#include "MGLGenerateKeyPairSyncInstaller.h"
|
|
20
25
|
#include "MGLHashInstaller.h"
|
|
21
26
|
#include "MGLHmacInstaller.h"
|
|
22
27
|
#include "MGLPbkdf2HostObject.h"
|
|
28
|
+
#include "MGLPublicCipher.h"
|
|
29
|
+
#include "MGLPublicCipherInstaller.h"
|
|
23
30
|
#include "MGLRandomHostObject.h"
|
|
24
|
-
|
|
25
31
|
#endif
|
|
26
32
|
|
|
27
33
|
namespace margelo {
|
|
@@ -38,14 +44,47 @@ MGLQuickCryptoHostObject::MGLQuickCryptoHostObject(
|
|
|
38
44
|
// HashInstaller
|
|
39
45
|
this->fields.push_back(getHashFieldDefinition(jsCallInvoker, workerQueue));
|
|
40
46
|
|
|
41
|
-
//
|
|
47
|
+
// createCipher
|
|
42
48
|
this->fields.push_back(
|
|
43
49
|
getCreateCipherFieldDefinition(jsCallInvoker, workerQueue));
|
|
44
50
|
|
|
45
|
-
//
|
|
51
|
+
// createDecipher
|
|
46
52
|
this->fields.push_back(
|
|
47
53
|
getCreateDecipherFieldDefinition(jsCallInvoker, workerQueue));
|
|
48
54
|
|
|
55
|
+
// publicEncrypt
|
|
56
|
+
this->fields.push_back(
|
|
57
|
+
getPublicCipherFieldDefinition<MGLPublicCipher::kPublic,
|
|
58
|
+
EVP_PKEY_encrypt_init, EVP_PKEY_encrypt>(
|
|
59
|
+
"publicEncrypt", jsCallInvoker, workerQueue));
|
|
60
|
+
|
|
61
|
+
// privateDecrypt
|
|
62
|
+
this->fields.push_back(
|
|
63
|
+
getPublicCipherFieldDefinition<MGLPublicCipher::kPrivate,
|
|
64
|
+
EVP_PKEY_decrypt_init, EVP_PKEY_decrypt>(
|
|
65
|
+
"privateDecrypt", jsCallInvoker, workerQueue));
|
|
66
|
+
|
|
67
|
+
// privateEncrypt
|
|
68
|
+
this->fields.push_back(
|
|
69
|
+
getPublicCipherFieldDefinition<MGLPublicCipher::kPrivate,
|
|
70
|
+
EVP_PKEY_sign_init, EVP_PKEY_sign>(
|
|
71
|
+
"privateEncrypt", jsCallInvoker, workerQueue));
|
|
72
|
+
|
|
73
|
+
// publicDecrypt
|
|
74
|
+
this->fields.push_back(
|
|
75
|
+
getPublicCipherFieldDefinition<MGLPublicCipher::kPublic,
|
|
76
|
+
EVP_PKEY_verify_recover_init,
|
|
77
|
+
EVP_PKEY_verify_recover>(
|
|
78
|
+
"publicDecrypt", jsCallInvoker, workerQueue));
|
|
79
|
+
|
|
80
|
+
// generateKeyPair
|
|
81
|
+
this->fields.push_back(
|
|
82
|
+
getGenerateKeyPairFieldDefinition(jsCallInvoker, workerQueue));
|
|
83
|
+
|
|
84
|
+
// generateKeyPairSync
|
|
85
|
+
this->fields.push_back(
|
|
86
|
+
getGenerateKeyPairSyncFieldDefinition(jsCallInvoker, workerQueue));
|
|
87
|
+
|
|
49
88
|
// Pbkdf2HostObject
|
|
50
89
|
this->fields.push_back(JSI_VALUE("pbkdf2", {
|
|
51
90
|
auto hostObject =
|