react-native-quick-crypto 0.7.0 → 0.7.2
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 +11 -63
- 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/Sig/MGLSignHostObjects.cpp +22 -15
- 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 +58 -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 +12 -12
- 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 +143 -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/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<a href="https://margelo.io">
|
|
2
|
-
<img src="./img/banner.svg" width="100%" />
|
|
2
|
+
<img src="./docs/img/banner.svg" width="100%" />
|
|
3
3
|
</a>
|
|
4
4
|
|
|
5
5
|
# ⚡️ react-native-quick-crypto
|
|
@@ -42,7 +42,7 @@ Creating a Wallet took 289 ms
|
|
|
42
42
|
## Installation
|
|
43
43
|
|
|
44
44
|
<h3>
|
|
45
|
-
React Native <a href="#"><img src="./img/react-native.png" height="15" /></a>
|
|
45
|
+
React Native <a href="#"><img src="./docs/img/react-native.png" height="15" /></a>
|
|
46
46
|
</h3>
|
|
47
47
|
|
|
48
48
|
```sh
|
|
@@ -51,7 +51,7 @@ cd ios && pod install
|
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
<h3>
|
|
54
|
-
Expo <a href="#"><img src="./img/expo.png" height="12" /></a>
|
|
54
|
+
Expo <a href="#"><img src="./docs/img/expo.png" height="12" /></a>
|
|
55
55
|
</h3>
|
|
56
56
|
|
|
57
57
|
```sh
|
|
@@ -75,7 +75,7 @@ If you are using a library that depends on `crypto`, instead of polyfilling it w
|
|
|
75
75
|
|
|
76
76
|
Use the [`resolveRequest`](https://facebook.github.io/metro/docs/resolution#resolverequest-customresolver) configuration option in your `metro.config.js`
|
|
77
77
|
|
|
78
|
-
```
|
|
78
|
+
```js
|
|
79
79
|
config.resolver.resolveRequest = (context, moduleName, platform) => {
|
|
80
80
|
if (moduleName === 'crypto') {
|
|
81
81
|
// when importing crypto, resolve to react-native-quick-crypto
|
|
@@ -133,67 +133,13 @@ const hashed = QuickCrypto.createHash('sha256')
|
|
|
133
133
|
.digest('hex');
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
-
## Android build errors
|
|
137
|
-
|
|
138
|
-
If you get an error similar to this:
|
|
139
|
-
|
|
140
|
-
```
|
|
141
|
-
Execution failed for task ':app:mergeDebugNativeLibs'.
|
|
142
|
-
> A failure occurred while executing com.android.build.gradle.internal.tasks.MergeNativeLibsTask$MergeNativeLibsTaskWorkAction
|
|
143
|
-
> 2 files found with path 'lib/arm64-v8a/libcrypto.so' from inputs:
|
|
144
|
-
- /Users/osp/Developer/mac_test/node_modules/react-native-quick-crypto/android/build/intermediates/library_jni/debug/jni/arm64-v8a/libcrypto.so
|
|
145
|
-
- /Users/osp/.gradle/caches/transforms-3/e13f88164840fe641a466d05cd8edac7/transformed/jetified-flipper-0.182.0/jni/arm64-v8a/libcrypto.so
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
It means you have a transitive dependency where two libraries depend on OpenSSL and are generating a `libcrypto.so` file. You can get around this issue by adding the following in your `app/build.gradle`:
|
|
149
|
-
|
|
150
|
-
<h4>
|
|
151
|
-
React Native <a href="#"><img src="./img/react-native.png" height="15" /></a>
|
|
152
|
-
</h4>
|
|
153
|
-
|
|
154
|
-
`android/app/build.gradle` file
|
|
155
|
-
|
|
156
|
-
```groovy
|
|
157
|
-
packagingOptions {
|
|
158
|
-
// Should prevent clashes with other libraries that use OpenSSL
|
|
159
|
-
pickFirst '**/libcrypto.so'
|
|
160
|
-
}
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
<h4>
|
|
164
|
-
Expo <a href="#"><img src="./img/expo.png" height="12" /></a>
|
|
165
|
-
</h4>
|
|
166
|
-
|
|
167
|
-
`app.json` file
|
|
168
|
-
|
|
169
|
-
```diff
|
|
170
|
-
...
|
|
171
|
-
plugins: [
|
|
172
|
-
...
|
|
173
|
-
+ [
|
|
174
|
-
+ 'expo-build-properties',
|
|
175
|
-
+ {
|
|
176
|
-
+ android: {
|
|
177
|
-
+ packagingOptions: {
|
|
178
|
-
+ pickFirst: ['**/libcrypto.so'],
|
|
179
|
-
+ },
|
|
180
|
-
+ },
|
|
181
|
-
+ },
|
|
182
|
-
+ ],
|
|
183
|
-
],
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
> This caused by flipper which also depends on OpenSSL
|
|
187
|
-
|
|
188
|
-
This just tells Gradle to grab whatever OpenSSL version it finds first and link against that, but as you can imagine this is not correct if the packages depend on different OpenSSL versions (quick-crypto depends on `com.android.ndk.thirdparty:openssl:1.1.1q-beta-1`). You should make sure all the OpenSSL versions match and you have no conflicts or errors.
|
|
189
|
-
|
|
190
136
|
---
|
|
191
137
|
|
|
192
138
|
## Sponsors
|
|
193
139
|
|
|
194
140
|
<!-- Onin -->
|
|
195
141
|
<div align="center">
|
|
196
|
-
<img height="50" src="./img/sponsors/onin.svg" align="center"><br/>
|
|
142
|
+
<img height="50" src="./docs/img/sponsors/onin.svg" align="center"><br/>
|
|
197
143
|
<a href="https://onin.co"><b>Onin</b></a> - This library is supported by Onin. Plan events without leaving the chat: <a href="https://onin.co">onin.co</a>
|
|
198
144
|
</div>
|
|
199
145
|
<br/>
|
|
@@ -201,7 +147,7 @@ This just tells Gradle to grab whatever OpenSSL version it finds first and link
|
|
|
201
147
|
|
|
202
148
|
<!-- Steakwallet -->
|
|
203
149
|
<div align="center">
|
|
204
|
-
<img height="37" src="./img/sponsors/omni.png" align="center"><br/>
|
|
150
|
+
<img height="37" src="./docs/img/sponsors/omni.png" align="center"><br/>
|
|
205
151
|
<a href="https://steakwallet.fi"><b>Omni</b></a> - Web3 for all. Access all of Web3 in one easy to use wallet. Omni supports more blockchains so you get more tokens, more yields, more NFTs, and more fun!
|
|
206
152
|
</div>
|
|
207
153
|
<br/>
|
|
@@ -209,7 +155,7 @@ This just tells Gradle to grab whatever OpenSSL version it finds first and link
|
|
|
209
155
|
|
|
210
156
|
<!-- Litentry -->
|
|
211
157
|
<div align="center">
|
|
212
|
-
<img height="70" src="./img/sponsors/litentry.png" align="center"><br/>
|
|
158
|
+
<img height="70" src="./docs/img/sponsors/litentry.png" align="center"><br/>
|
|
213
159
|
<a href="https://litentry.com"><b>Litentry</b></a> - A decentralized identity aggregator, providing the structure and tools to empower you and your identity.
|
|
214
160
|
</div>
|
|
215
161
|
<br/>
|
|
@@ -217,7 +163,7 @@ This just tells Gradle to grab whatever OpenSSL version it finds first and link
|
|
|
217
163
|
|
|
218
164
|
<!-- WalletConnect -->
|
|
219
165
|
<div align="center">
|
|
220
|
-
<img height="35" src="./img/sponsors/walletconnect.png" align="center"><br/>
|
|
166
|
+
<img height="35" src="./docs/img/sponsors/walletconnect.png" align="center"><br/>
|
|
221
167
|
<a href="https://walletconnect.com"><b>WalletConnect</b></a> - The communications protocol for web3, WalletConnect brings the ecosystem together by enabling wallets and apps to securely connect and interact.
|
|
222
168
|
</div>
|
|
223
169
|
<br/>
|
|
@@ -227,7 +173,7 @@ This just tells Gradle to grab whatever OpenSSL version it finds first and link
|
|
|
227
173
|
|
|
228
174
|
<!-- THORSwap -->
|
|
229
175
|
<div align="center">
|
|
230
|
-
<img height="40" src="./img/sponsors/thorswap.png" align="center"><br/>
|
|
176
|
+
<img height="40" src="./docs/img/sponsors/thorswap.png" align="center"><br/>
|
|
231
177
|
<a href="https://thorswap.finance"><b>THORSwap</b></a> - THORSwap is a cross-chain DEX aggregator that enables users to swap native assets across chains, provide liquidity to earn yield, and more. THORSwap is fully permissionless and non-custodial. No account signup, your wallet, your keys, your coins.
|
|
232
178
|
</div>
|
|
233
179
|
<br/>
|
|
@@ -237,6 +183,8 @@ This just tells Gradle to grab whatever OpenSSL version it finds first and link
|
|
|
237
183
|
|
|
238
184
|
As the library uses JSI for synchronous native methods access, remote debugging (e.g. with Chrome) is no longer possible. Instead, you should use [Flipper](https://fbflipper.com).
|
|
239
185
|
|
|
186
|
+
Not all cryptographic algorithms are supported yet. See the [implementation coverage](./docs/implementation-coverage.md) document for more details. If you need a specific algorithm, please open a `feature request` issue and we'll see what we can do.
|
|
187
|
+
|
|
240
188
|
## Community Discord
|
|
241
189
|
|
|
242
190
|
[Join the Margelo Community Discord](https://discord.gg/6CSHz2qAvA) to chat about react-native-quick-crypto or other Margelo libraries.
|
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
|