react-native-quick-crypto 0.7.0-rc.9 → 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.
Files changed (155) hide show
  1. package/android/CMakeLists.txt +2 -0
  2. package/cpp/Cipher/MGLGenerateKeyPairInstaller.cpp +51 -14
  3. package/cpp/Cipher/MGLGenerateKeyPairSyncInstaller.cpp +25 -9
  4. package/cpp/Cipher/MGLRsa.cpp +192 -15
  5. package/cpp/Cipher/MGLRsa.h +36 -2
  6. package/cpp/JSIUtils/MGLJSIUtils.h +17 -0
  7. package/cpp/MGLKeys.cpp +210 -187
  8. package/cpp/MGLKeys.h +25 -13
  9. package/cpp/MGLQuickCryptoHostObject.cpp +6 -6
  10. package/cpp/Sig/MGLSignHostObjects.cpp +284 -421
  11. package/cpp/Sig/MGLSignHostObjects.h +40 -0
  12. package/cpp/Utils/MGLUtils.cpp +71 -42
  13. package/cpp/Utils/MGLUtils.h +81 -6
  14. package/cpp/webcrypto/MGLWebCrypto.cpp +97 -35
  15. package/cpp/webcrypto/MGLWebCrypto.h +5 -7
  16. package/cpp/webcrypto/crypto_aes.cpp +516 -0
  17. package/cpp/webcrypto/crypto_aes.h +79 -0
  18. package/cpp/webcrypto/crypto_ec.cpp +110 -20
  19. package/cpp/webcrypto/crypto_ec.h +18 -5
  20. package/cpp/webcrypto/crypto_keygen.cpp +86 -0
  21. package/cpp/webcrypto/crypto_keygen.h +38 -0
  22. package/lib/commonjs/Cipher.js +140 -95
  23. package/lib/commonjs/Cipher.js.map +1 -1
  24. package/lib/commonjs/Hashnames.js +20 -8
  25. package/lib/commonjs/Hashnames.js.map +1 -1
  26. package/lib/commonjs/NativeQuickCrypto/Cipher.js +23 -8
  27. package/lib/commonjs/NativeQuickCrypto/Cipher.js.map +1 -1
  28. package/lib/commonjs/NativeQuickCrypto/NativeQuickCrypto.js.map +1 -1
  29. package/lib/commonjs/NativeQuickCrypto/aes.js +6 -0
  30. package/lib/commonjs/NativeQuickCrypto/aes.js.map +1 -0
  31. package/lib/commonjs/NativeQuickCrypto/keygen.js +6 -0
  32. package/lib/commonjs/NativeQuickCrypto/keygen.js.map +1 -0
  33. package/lib/commonjs/NativeQuickCrypto/rsa.js +6 -0
  34. package/lib/commonjs/NativeQuickCrypto/rsa.js.map +1 -0
  35. package/lib/commonjs/NativeQuickCrypto/sig.js +17 -0
  36. package/lib/commonjs/NativeQuickCrypto/sig.js.map +1 -1
  37. package/lib/commonjs/Utils.js +45 -7
  38. package/lib/commonjs/Utils.js.map +1 -1
  39. package/lib/commonjs/aes.js +184 -227
  40. package/lib/commonjs/aes.js.map +1 -1
  41. package/lib/commonjs/ec.js +79 -91
  42. package/lib/commonjs/ec.js.map +1 -1
  43. package/lib/commonjs/index.js +12 -2
  44. package/lib/commonjs/index.js.map +1 -1
  45. package/lib/commonjs/keygen.js +56 -0
  46. package/lib/commonjs/keygen.js.map +1 -0
  47. package/lib/commonjs/keys.js +84 -29
  48. package/lib/commonjs/keys.js.map +1 -1
  49. package/lib/commonjs/random.js +6 -0
  50. package/lib/commonjs/random.js.map +1 -1
  51. package/lib/commonjs/rsa.js +115 -196
  52. package/lib/commonjs/rsa.js.map +1 -1
  53. package/lib/commonjs/sig.js.map +1 -1
  54. package/lib/commonjs/subtle.js +205 -29
  55. package/lib/commonjs/subtle.js.map +1 -1
  56. package/lib/commonjs/webcrypto.js +14 -0
  57. package/lib/commonjs/webcrypto.js.map +1 -0
  58. package/lib/module/Cipher.js +138 -93
  59. package/lib/module/Cipher.js.map +1 -1
  60. package/lib/module/Hashnames.js +20 -8
  61. package/lib/module/Hashnames.js.map +1 -1
  62. package/lib/module/NativeQuickCrypto/Cipher.js +22 -7
  63. package/lib/module/NativeQuickCrypto/Cipher.js.map +1 -1
  64. package/lib/module/NativeQuickCrypto/NativeQuickCrypto.js.map +1 -1
  65. package/lib/module/NativeQuickCrypto/aes.js +2 -0
  66. package/lib/module/NativeQuickCrypto/aes.js.map +1 -0
  67. package/lib/module/NativeQuickCrypto/keygen.js +2 -0
  68. package/lib/module/NativeQuickCrypto/keygen.js.map +1 -0
  69. package/lib/module/NativeQuickCrypto/rsa.js +2 -0
  70. package/lib/module/NativeQuickCrypto/rsa.js.map +1 -0
  71. package/lib/module/NativeQuickCrypto/sig.js +13 -0
  72. package/lib/module/NativeQuickCrypto/sig.js.map +1 -1
  73. package/lib/module/Utils.js +38 -5
  74. package/lib/module/Utils.js.map +1 -1
  75. package/lib/module/aes.js +183 -228
  76. package/lib/module/aes.js.map +1 -1
  77. package/lib/module/ec.js +76 -93
  78. package/lib/module/ec.js.map +1 -1
  79. package/lib/module/index.js +11 -2
  80. package/lib/module/index.js.map +1 -1
  81. package/lib/module/keygen.js +47 -0
  82. package/lib/module/keygen.js.map +1 -0
  83. package/lib/module/keys.js +76 -28
  84. package/lib/module/keys.js.map +1 -1
  85. package/lib/module/random.js +6 -0
  86. package/lib/module/random.js.map +1 -1
  87. package/lib/module/rsa.js +115 -198
  88. package/lib/module/rsa.js.map +1 -1
  89. package/lib/module/sig.js.map +1 -1
  90. package/lib/module/subtle.js +209 -34
  91. package/lib/module/subtle.js.map +1 -1
  92. package/lib/module/webcrypto.js +8 -0
  93. package/lib/module/webcrypto.js.map +1 -0
  94. package/lib/typescript/Cipher.d.ts +23 -14
  95. package/lib/typescript/Cipher.d.ts.map +1 -1
  96. package/lib/typescript/Hash.d.ts.map +1 -1
  97. package/lib/typescript/Hashnames.d.ts +2 -2
  98. package/lib/typescript/Hashnames.d.ts.map +1 -1
  99. package/lib/typescript/NativeQuickCrypto/Cipher.d.ts +16 -6
  100. package/lib/typescript/NativeQuickCrypto/Cipher.d.ts.map +1 -1
  101. package/lib/typescript/NativeQuickCrypto/NativeQuickCrypto.d.ts +4 -1
  102. package/lib/typescript/NativeQuickCrypto/NativeQuickCrypto.d.ts.map +1 -1
  103. package/lib/typescript/NativeQuickCrypto/aes.d.ts +5 -0
  104. package/lib/typescript/NativeQuickCrypto/aes.d.ts.map +1 -0
  105. package/lib/typescript/NativeQuickCrypto/keygen.d.ts +4 -0
  106. package/lib/typescript/NativeQuickCrypto/keygen.d.ts.map +1 -0
  107. package/lib/typescript/NativeQuickCrypto/rsa.d.ts +5 -0
  108. package/lib/typescript/NativeQuickCrypto/rsa.d.ts.map +1 -0
  109. package/lib/typescript/NativeQuickCrypto/sig.d.ts +10 -0
  110. package/lib/typescript/NativeQuickCrypto/sig.d.ts.map +1 -1
  111. package/lib/typescript/NativeQuickCrypto/webcrypto.d.ts +14 -2
  112. package/lib/typescript/NativeQuickCrypto/webcrypto.d.ts.map +1 -1
  113. package/lib/typescript/Utils.d.ts +5 -4
  114. package/lib/typescript/Utils.d.ts.map +1 -1
  115. package/lib/typescript/aes.d.ts +18 -1
  116. package/lib/typescript/aes.d.ts.map +1 -1
  117. package/lib/typescript/ec.d.ts +3 -1
  118. package/lib/typescript/ec.d.ts.map +1 -1
  119. package/lib/typescript/index.d.ts +30 -24
  120. package/lib/typescript/index.d.ts.map +1 -1
  121. package/lib/typescript/keygen.d.ts +6 -0
  122. package/lib/typescript/keygen.d.ts.map +1 -0
  123. package/lib/typescript/keys.d.ts +67 -18
  124. package/lib/typescript/keys.d.ts.map +1 -1
  125. package/lib/typescript/random.d.ts +2 -1
  126. package/lib/typescript/random.d.ts.map +1 -1
  127. package/lib/typescript/rsa.d.ts +9 -1
  128. package/lib/typescript/rsa.d.ts.map +1 -1
  129. package/lib/typescript/sig.d.ts +3 -17
  130. package/lib/typescript/sig.d.ts.map +1 -1
  131. package/lib/typescript/subtle.d.ts +8 -4
  132. package/lib/typescript/subtle.d.ts.map +1 -1
  133. package/lib/typescript/webcrypto.d.ts +9 -0
  134. package/lib/typescript/webcrypto.d.ts.map +1 -0
  135. package/package.json +2 -2
  136. package/src/Cipher.ts +139 -75
  137. package/src/Hashnames.ts +23 -21
  138. package/src/NativeQuickCrypto/Cipher.ts +46 -14
  139. package/src/NativeQuickCrypto/NativeQuickCrypto.ts +6 -0
  140. package/src/NativeQuickCrypto/aes.ts +14 -0
  141. package/src/NativeQuickCrypto/keygen.ts +7 -0
  142. package/src/NativeQuickCrypto/rsa.ts +12 -0
  143. package/src/NativeQuickCrypto/sig.ts +27 -0
  144. package/src/NativeQuickCrypto/webcrypto.ts +28 -2
  145. package/src/Utils.ts +49 -8
  146. package/src/aes.ts +259 -222
  147. package/src/ec.ts +114 -90
  148. package/src/index.ts +10 -1
  149. package/src/keygen.ts +80 -0
  150. package/src/keys.ts +165 -61
  151. package/src/random.ts +12 -1
  152. package/src/rsa.ts +161 -187
  153. package/src/sig.ts +7 -23
  154. package/src/subtle.ts +309 -35
  155. package/src/webcrypto.ts +8 -0
@@ -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(
@@ -10,6 +10,7 @@
10
10
  #include <iostream>
11
11
  #include <memory>
12
12
  #include <mutex>
13
+ #include <string>
13
14
  #include <thread>
14
15
  #include <utility>
15
16
 
@@ -18,9 +19,11 @@
18
19
  #ifdef ANDROID
19
20
  #include "JSIUtils/MGLJSIMacros.h"
20
21
  #include "JSIUtils/MGLTypedArray.h"
22
+ #include "webcrypto/crypto_ec.h"
21
23
  #else
22
24
  #include "MGLJSIMacros.h"
23
25
  #include "MGLTypedArray.h"
26
+ #include "crypto_ec.h"
24
27
  #endif
25
28
 
26
29
  using namespace facebook;
@@ -29,24 +32,44 @@ namespace margelo {
29
32
 
30
33
  std::mutex m;
31
34
 
32
- // Current implementation only supports RSA schemes (check line config.variant =
33
- // ) As more encryption schemes are added this will require an abstraction that
34
- // supports more schemes
35
35
  FieldDefinition getGenerateKeyPairFieldDefinition(
36
36
  std::shared_ptr<react::CallInvoker> jsCallInvoker,
37
37
  std::shared_ptr<DispatchQueue::dispatch_queue> workerQueue) {
38
38
  return buildPair(
39
39
  "generateKeyPair", JSIF([=]) {
40
- auto config = std::make_shared<RsaKeyPairGenConfig>(
40
+
41
+ KeyVariant variant =
42
+ static_cast<KeyVariant>((int)arguments[0].asNumber());
43
+ std::shared_ptr<RsaKeyPairGenConfig> rsaConfig;
44
+ std::shared_ptr<EcKeyPairGenConfig> ecConfig;
45
+
46
+ // switch on variant to get proper config from arguments
47
+ // outside of lambda 🤮
48
+ if (variant == kvRSA_SSA_PKCS1_v1_5 ||
49
+ variant == kvRSA_PSS ||
50
+ variant == kvRSA_OAEP
51
+ ) {
52
+ rsaConfig = std::make_shared<RsaKeyPairGenConfig>(
41
53
  prepareRsaKeyGenConfig(runtime, arguments));
54
+ } else
55
+ if (variant == kvEC) {
56
+ ecConfig = std::make_shared<EcKeyPairGenConfig>(
57
+ prepareEcKeyGenConfig(runtime, arguments));
58
+ } else {
59
+ throw std::runtime_error("KeyVariant not implemented"
60
+ + std::to_string((int)variant));
61
+ }
62
+
42
63
  auto promiseConstructor =
43
64
  runtime.global().getPropertyAsFunction(runtime, "Promise");
44
65
 
45
66
  auto promise = promiseConstructor.callAsConstructor(
46
67
  runtime,
47
68
  jsi::Function::createFromHostFunction(
48
- runtime, jsi::PropNameID::forAscii(runtime, "executor"), 2,
49
- [&jsCallInvoker, config](
69
+ runtime,
70
+ jsi::PropNameID::forAscii(runtime, "executor"),
71
+ 4,
72
+ [&jsCallInvoker, variant, rsaConfig, ecConfig](
50
73
  jsi::Runtime &runtime, const jsi::Value &,
51
74
  const jsi::Value *promiseArgs, size_t) -> jsi::Value {
52
75
  auto resolve =
@@ -54,19 +77,33 @@ FieldDefinition getGenerateKeyPairFieldDefinition(
54
77
  auto reject =
55
78
  std::make_shared<jsi::Value>(runtime, promiseArgs[1]);
56
79
 
57
- std::thread t([&runtime, resolve, reject,
58
- jsCallInvoker, config]() {
80
+ std::thread t([&runtime, resolve, reject, jsCallInvoker,
81
+ variant, rsaConfig, ecConfig]() {
59
82
  m.lock();
60
83
  try {
61
- jsCallInvoker->invokeAsync([&runtime, config, resolve]() {
62
- auto keys = generateRSAKeyPair(runtime, config);
63
- auto publicKey = toJSI(runtime, keys.first);
64
- auto privateKey = toJSI(runtime, keys.second);
84
+ jsCallInvoker->invokeAsync([&runtime, resolve,
85
+ variant, rsaConfig, ecConfig]() {
86
+ std::pair<jsi::Value, jsi::Value> keys;
87
+
88
+ // switch on variant to get proper generateKeyPair
89
+ if (variant == kvRSA_SSA_PKCS1_v1_5 ||
90
+ variant == kvRSA_PSS ||
91
+ variant == kvRSA_OAEP
92
+ ) {
93
+ keys = generateRsaKeyPair(runtime, rsaConfig);
94
+ } else
95
+ if (variant == kvEC) {
96
+ keys = generateEcKeyPair(runtime, ecConfig);
97
+ } else {
98
+ throw std::runtime_error("KeyVariant not implemented"
99
+ + std::to_string((int)variant));
100
+ }
101
+
65
102
  auto res = jsi::Array::createWithElements(
66
103
  runtime,
67
104
  jsi::Value::undefined(),
68
- publicKey,
69
- privateKey);
105
+ keys.first,
106
+ keys.second);
70
107
  resolve->asObject(runtime).asFunction(runtime).call(
71
108
  runtime, std::move(res));
72
109
  });
@@ -17,31 +17,47 @@
17
17
  #include "JSIUtils/MGLJSIMacros.h"
18
18
  #include "JSIUtils/MGLJSIUtils.h"
19
19
  #include "JSIUtils/MGLTypedArray.h"
20
+ #include "webcrypto/crypto_ec.h"
20
21
  #else
21
22
  #include "MGLJSIMacros.h"
22
23
  #include "MGLJSIUtils.h"
23
24
  #include "MGLTypedArray.h"
25
+ #include "crypto_ec.h"
24
26
  #endif
25
27
 
26
28
  using namespace facebook;
27
29
 
28
30
  namespace margelo {
29
31
 
30
- // Current implementation only supports RSA schemes (check line config.variant =
31
- // ) As more encryption schemes are added this will require an abstraction that
32
- // supports more schemes
33
32
  FieldDefinition getGenerateKeyPairSyncFieldDefinition(
34
33
  std::shared_ptr<react::CallInvoker> jsCallInvoker,
35
34
  std::shared_ptr<DispatchQueue::dispatch_queue> workerQueue) {
36
35
  return buildPair(
37
36
  "generateKeyPairSync", JSIF([=]) {
38
- auto config = std::make_shared<RsaKeyPairGenConfig>(
39
- prepareRsaKeyGenConfig(runtime, arguments));
40
- auto keys = generateRSAKeyPair(runtime, std::move(config));
41
- auto publicKey = toJSI(runtime, keys.first);
42
- auto privateKey = toJSI(runtime, keys.second);
37
+ std::pair<jsi::Value, jsi::Value> keys;
38
+ KeyVariant variant =
39
+ static_cast<KeyVariant>((int)arguments[0].asNumber());
40
+
41
+ // switch on variant to get proper config/genKeyPair
42
+ if (variant == kvRSA_SSA_PKCS1_v1_5 ||
43
+ variant == kvRSA_PSS ||
44
+ variant == kvRSA_OAEP
45
+ ) {
46
+ auto config = std::make_shared<RsaKeyPairGenConfig>(
47
+ prepareRsaKeyGenConfig(runtime, arguments));
48
+ keys = generateRsaKeyPair(runtime, config);
49
+ } else
50
+ if (variant == kvEC) {
51
+ auto config = std::make_shared<EcKeyPairGenConfig>(
52
+ prepareEcKeyGenConfig(runtime, arguments));
53
+ keys = generateEcKeyPair(runtime, config);
54
+ } else {
55
+ throw std::runtime_error("KeyVariant not implemented: " +
56
+ std::to_string((int)variant));
57
+ }
58
+ // keys.first = publicKey keys.second = privateKey
43
59
  return jsi::Array::createWithElements(
44
- runtime, jsi::Value::undefined(), publicKey, privateKey);
60
+ runtime, jsi::Value::undefined(), keys.first, keys.second);
45
61
  });
46
62
  }
47
63
  } // namespace margelo
@@ -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>
@@ -21,7 +27,7 @@ namespace jsi = facebook::jsi;
21
27
 
22
28
  EVPKeyCtxPointer setup(std::shared_ptr<RsaKeyPairGenConfig> config) {
23
29
  EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new_id(
24
- config->variant == kKeyVariantRSA_PSS ? EVP_PKEY_RSA_PSS : EVP_PKEY_RSA,
30
+ config->variant == kvRSA_PSS ? EVP_PKEY_RSA_PSS : EVP_PKEY_RSA,
25
31
  nullptr));
26
32
 
27
33
  if (EVP_PKEY_keygen_init(ctx.get()) <= 0) return EVPKeyCtxPointer();
@@ -43,7 +49,7 @@ EVPKeyCtxPointer setup(std::shared_ptr<RsaKeyPairGenConfig> config) {
43
49
  bn.release();
44
50
  }
45
51
 
46
- if (config->variant == kKeyVariantRSA_PSS) {
52
+ if (config->variant == kvRSA_PSS) {
47
53
  if (config->md != nullptr &&
48
54
  EVP_PKEY_CTX_set_rsa_pss_keygen_md(ctx.get(), config->md) <= 0) {
49
55
  return EVPKeyCtxPointer();
@@ -94,12 +100,12 @@ RsaKeyPairGenConfig prepareRsaKeyGenConfig(jsi::Runtime& runtime,
94
100
  // CHECK(args[*offset + 1]->IsUint32()); // Modulus bits
95
101
  // CHECK(args[*offset + 2]->IsUint32()); // Exponent
96
102
  config.variant =
97
- static_cast<RSAKeyVariant>((int)arguments[offset].asNumber());
103
+ static_cast<KeyVariant>((int)arguments[offset].asNumber());
98
104
 
99
105
  // TODO(osp)
100
- // CHECK_IMPLIES(params->params.variant != kKeyVariantRSA_PSS,
106
+ // CHECK_IMPLIES(params->params.variant != kvRSA_PSS,
101
107
  // args.Length() == 10);
102
- // CHECK_IMPLIES(params->params.variant == kKeyVariantRSA_PSS,
108
+ // CHECK_IMPLIES(params->params.variant == kvRSA_PSS,
103
109
  // args.Length() == 13);
104
110
  config.modulus_bits =
105
111
  static_cast<unsigned int>(arguments[offset + 1].asNumber());
@@ -107,7 +113,7 @@ RsaKeyPairGenConfig prepareRsaKeyGenConfig(jsi::Runtime& runtime,
107
113
 
108
114
  offset += 3;
109
115
 
110
- if (config.variant == kKeyVariantRSA_PSS) {
116
+ if (config.variant == kvRSA_PSS) {
111
117
  if (!arguments[offset].isUndefined()) {
112
118
  // TODO(osp) CHECK(string)
113
119
  config.md = EVP_get_digestbyname(
@@ -153,8 +159,9 @@ RsaKeyPairGenConfig prepareRsaKeyGenConfig(jsi::Runtime& runtime,
153
159
  return config;
154
160
  }
155
161
 
156
- std::pair<JSVariant, JSVariant> generateRSAKeyPair(
162
+ std::pair<jsi::Value, jsi::Value> generateRsaKeyPair(
157
163
  jsi::Runtime& runtime, std::shared_ptr<RsaKeyPairGenConfig> config) {
164
+ // TODO: this is all copied into crypto_ec.cpp - template it up like Node?
158
165
  CheckEntropy();
159
166
 
160
167
  EVPKeyCtxPointer ctx = setup(config);
@@ -171,18 +178,137 @@ std::pair<JSVariant, JSVariant> generateRSAKeyPair(
171
178
 
172
179
  config->key = ManagedEVPPKey(EVPKeyPointer(pkey));
173
180
 
174
- OptionJSVariant publicBuffer =
181
+ jsi::Value publicBuffer =
175
182
  ManagedEVPPKey::ToEncodedPublicKey(runtime, std::move(config->key),
176
183
  config->public_key_encoding);
177
- OptionJSVariant privateBuffer =
184
+ jsi::Value privateBuffer =
178
185
  ManagedEVPPKey::ToEncodedPrivateKey(runtime, std::move(config->key),
179
186
  config->private_key_encoding);
180
187
 
181
- if (!publicBuffer.has_value() || !privateBuffer.has_value()) {
182
- throw jsi::JSError(runtime, "Failed to encode public and/or private key");
188
+ if (publicBuffer.isUndefined() || privateBuffer.isUndefined()) {
189
+ throw jsi::JSError(runtime, "Failed to encode public and/or private key (RSA)");
183
190
  }
184
191
 
185
- return {std::move(publicBuffer.value()), std::move(privateBuffer.value())};
192
+ return {std::move(publicBuffer), std::move(privateBuffer)};
193
+ }
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 &params,
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
+ }
186
312
  }
187
313
 
188
314
  jsi::Value ExportJWKRsaKey(jsi::Runtime &rt,
@@ -329,12 +455,11 @@ jsi::Value GetRsaKeyDetail(jsi::Runtime &rt,
329
455
  RSA_get0_key(rsa, &n, &e, nullptr);
330
456
 
331
457
  size_t modulus_length = BN_num_bits(n);
332
- // TODO: should this be modulusLength or n?
333
458
  target.setProperty(rt, "modulusLength", static_cast<double>(modulus_length));
334
459
 
335
460
  size_t exp_size = BN_num_bytes(e);
336
- // TODO: should this be publicExponent or e?
337
- target.setProperty(rt, "publicExponent", EncodeBignum(e, exp_size, true));
461
+ ByteSource public_exponent = ByteSource::FromBN(e, exp_size);
462
+ target.setProperty(rt, "publicExponent", toJSI(rt, std::move(public_exponent)));
338
463
 
339
464
  if (type == EVP_PKEY_RSA_PSS) {
340
465
  // Due to the way ASN.1 encoding works, default values are omitted when
@@ -393,4 +518,56 @@ jsi::Value GetRsaKeyDetail(jsi::Runtime &rt,
393
518
  return target;
394
519
  }
395
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
+
396
573
  } // namespace margelo
@@ -25,6 +25,7 @@ namespace margelo {
25
25
 
26
26
  namespace jsi = facebook::jsi;
27
27
 
28
+ // TODO: keep in in sync with JS side (src/rsa.ts)
28
29
  enum RSAKeyVariant {
29
30
  kKeyVariantRSA_SSA_PKCS1_v1_5,
30
31
  kKeyVariantRSA_PSS,
@@ -43,7 +44,7 @@ struct RsaKeyPairGenConfig {
43
44
  PrivateKeyEncodingConfig private_key_encoding;
44
45
  ManagedEVPPKey key;
45
46
 
46
- RSAKeyVariant variant;
47
+ KeyVariant variant;
47
48
  unsigned int modulus_bits;
48
49
  unsigned int exponent;
49
50
 
@@ -57,7 +58,7 @@ struct RsaKeyPairGenConfig {
57
58
  RsaKeyPairGenConfig prepareRsaKeyGenConfig(jsi::Runtime& runtime,
58
59
  const jsi::Value* arguments);
59
60
 
60
- std::pair<JSVariant, JSVariant> generateRSAKeyPair(
61
+ std::pair<jsi::Value, jsi::Value> generateRsaKeyPair(
61
62
  jsi::Runtime& runtime, std::shared_ptr<RsaKeyPairGenConfig> config);
62
63
 
63
64
  jsi::Value ExportJWKRsaKey(jsi::Runtime &rt,
@@ -70,6 +71,39 @@ std::shared_ptr<KeyObjectData> ImportJWKRsaKey(jsi::Runtime &rt,
70
71
  jsi::Value GetRsaKeyDetail(jsi::Runtime &rt,
71
72
  std::shared_ptr<KeyObjectData> key);
72
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 &params, ByteSource *out);
105
+ };
106
+
73
107
  } // namespace margelo
74
108
 
75
109
  #endif /* MGLRsa_hpp */
@@ -9,6 +9,7 @@
9
9
  #define MGLJSIUtils_h
10
10
 
11
11
  #include <jsi/jsi.h>
12
+ #include <limits>
12
13
 
13
14
  namespace jsi = facebook::jsi;
14
15
 
@@ -21,4 +22,20 @@ inline bool CheckSizeInt32(jsi::Runtime &runtime, jsi::ArrayBuffer &buffer) {
21
22
  return buffer.size(runtime) <= INT_MAX;
22
23
  }
23
24
 
25
+ inline bool CheckIsInt32(const jsi::Value &value) {
26
+ if (!value.isNumber()) {
27
+ return false;
28
+ }
29
+ double d = value.asNumber();
30
+ return (d >= std::numeric_limits<int32_t>::lowest() && d <= std::numeric_limits<int32_t>::max());
31
+ }
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
+
24
41
  #endif /* MGLJSIUtils_h */