react-native-security-suite 0.9.22 → 1.0.0-rc.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/README.md +235 -69
- package/android/build.gradle +11 -0
- package/android/gradle.properties +1 -1
- package/android/src/main/java/com/securitysuite/CryptoConfig.java +158 -0
- package/android/src/main/java/com/securitysuite/CryptoUtils.java +152 -0
- package/android/src/main/java/com/securitysuite/EcdhKeyStore.java +60 -0
- package/android/src/main/java/com/securitysuite/HeaderSanitizer.java +75 -0
- package/android/src/main/java/com/securitysuite/JWSGenerator.java +237 -32
- package/android/src/main/java/com/securitysuite/JwsFetchPayload.java +81 -0
- package/android/src/main/java/com/securitysuite/Obfuscation.java +57 -0
- package/android/src/main/java/com/securitysuite/SecureStorageNative.java +211 -0
- package/android/src/main/java/com/securitysuite/SecureView.java +2 -10
- package/android/src/main/java/com/securitysuite/SecureWindowHelper.java +30 -0
- package/android/src/main/java/com/securitysuite/SecuritySuiteModule.java +310 -102
- package/android/src/main/java/com/securitysuite/Sslpinning.java +219 -106
- package/android/src/main/java/com/securitysuite/security/AppIntegrityChecker.java +133 -0
- package/android/src/main/java/com/securitysuite/security/EmulatorDetector.java +145 -0
- package/android/src/main/java/com/securitysuite/security/RuntimeDetector.java +234 -0
- package/android/src/test/java/com/securitysuite/JWSGeneratorTest.java +153 -0
- package/android/src/test/java/com/securitysuite/SecureStorageNativeTest.java +37 -0
- package/ios/CryptoConfig.swift +124 -0
- package/ios/JWSGenerator.swift +288 -0
- package/ios/JWSGeneratorTests.swift +168 -0
- package/ios/KeychainHelper.swift +104 -0
- package/ios/Obfuscation.swift +42 -0
- package/ios/SecureStorageNative.swift +84 -0
- package/ios/Security/AppIntegrityChecker.swift +85 -0
- package/ios/Security/EmulatorDetector.swift +45 -0
- package/ios/Security/RuntimeDetector.swift +107 -0
- package/ios/SecuritySuite.mm +28 -4
- package/ios/SecuritySuite.swift +407 -131
- package/ios/SslPinning.swift +242 -263
- package/lib/commonjs/clipboard/index.js +3 -0
- package/lib/commonjs/clipboard/index.js.map +1 -0
- package/lib/commonjs/crypto/index.js +39 -0
- package/lib/commonjs/crypto/index.js.map +1 -0
- package/lib/commonjs/device/index.js +40 -0
- package/lib/commonjs/device/index.js.map +1 -0
- package/lib/commonjs/errors.js +62 -0
- package/lib/commonjs/errors.js.map +1 -0
- package/lib/commonjs/index.js +220 -151
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/integrity/index.js +40 -0
- package/lib/commonjs/integrity/index.js.map +1 -0
- package/lib/commonjs/jws.js +141 -0
- package/lib/commonjs/jws.js.map +1 -0
- package/lib/commonjs/legacy/cryptoOptions.js +20 -0
- package/lib/commonjs/legacy/cryptoOptions.js.map +1 -0
- package/lib/commonjs/native/bridge.js +23 -0
- package/lib/commonjs/native/bridge.js.map +1 -0
- package/lib/commonjs/network/index.js +3 -0
- package/lib/commonjs/network/index.js.map +1 -0
- package/lib/commonjs/risk/score.js +36 -0
- package/lib/commonjs/risk/score.js.map +1 -0
- package/lib/commonjs/runtime/index.js +31 -0
- package/lib/commonjs/runtime/index.js.map +1 -0
- package/lib/commonjs/screen/index.js +13 -0
- package/lib/commonjs/screen/index.js.map +1 -0
- package/lib/commonjs/securitySuite/index.js +42 -0
- package/lib/commonjs/securitySuite/index.js.map +1 -0
- package/lib/commonjs/storage/index.js +3 -0
- package/lib/commonjs/storage/index.js.map +1 -0
- package/lib/commonjs/types/detection.js +2 -0
- package/lib/commonjs/types/detection.js.map +1 -0
- package/lib/module/clipboard/index.js +3 -0
- package/lib/module/clipboard/index.js.map +1 -0
- package/lib/module/crypto/index.js +35 -0
- package/lib/module/crypto/index.js.map +1 -0
- package/lib/module/device/index.js +36 -0
- package/lib/module/device/index.js.map +1 -0
- package/lib/module/errors.js +55 -0
- package/lib/module/errors.js.map +1 -0
- package/lib/module/index.js +147 -148
- package/lib/module/index.js.map +1 -1
- package/lib/module/integrity/index.js +36 -0
- package/lib/module/integrity/index.js.map +1 -0
- package/lib/module/jws.js +127 -0
- package/lib/module/jws.js.map +1 -0
- package/lib/module/legacy/cryptoOptions.js +16 -0
- package/lib/module/legacy/cryptoOptions.js.map +1 -0
- package/lib/module/native/bridge.js +19 -0
- package/lib/module/native/bridge.js.map +1 -0
- package/lib/module/network/index.js +3 -0
- package/lib/module/network/index.js.map +1 -0
- package/lib/module/risk/score.js +32 -0
- package/lib/module/risk/score.js.map +1 -0
- package/lib/module/runtime/index.js +27 -0
- package/lib/module/runtime/index.js.map +1 -0
- package/lib/module/screen/index.js +5 -0
- package/lib/module/screen/index.js.map +1 -0
- package/lib/module/securitySuite/index.js +38 -0
- package/lib/module/securitySuite/index.js.map +1 -0
- package/lib/module/storage/index.js +3 -0
- package/lib/module/storage/index.js.map +1 -0
- package/lib/module/types/detection.js +2 -0
- package/lib/module/types/detection.js.map +1 -0
- package/lib/typescript/commonjs/docs/api-v1-proposal.d.ts +215 -0
- package/lib/typescript/commonjs/docs/api-v1-proposal.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/SecureView.d.ts +1 -1
- package/lib/typescript/commonjs/src/SecureView.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/clipboard/index.d.ts +2 -0
- package/lib/typescript/commonjs/src/clipboard/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/crypto/index.d.ts +15 -0
- package/lib/typescript/commonjs/src/crypto/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/device/index.d.ts +11 -0
- package/lib/typescript/commonjs/src/device/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/errors.d.ts +17 -0
- package/lib/typescript/commonjs/src/errors.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/helpers.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +77 -24
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/integrity/index.d.ts +6 -0
- package/lib/typescript/commonjs/src/integrity/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/jws.d.ts +44 -0
- package/lib/typescript/commonjs/src/jws.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/legacy/cryptoOptions.d.ts +35 -0
- package/lib/typescript/commonjs/src/legacy/cryptoOptions.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/native/bridge.d.ts +12 -0
- package/lib/typescript/commonjs/src/native/bridge.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/network/index.d.ts +2 -0
- package/lib/typescript/commonjs/src/network/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/risk/score.d.ts +12 -0
- package/lib/typescript/commonjs/src/risk/score.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/runtime/index.d.ts +6 -0
- package/lib/typescript/commonjs/src/runtime/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/screen/index.d.ts +3 -0
- package/lib/typescript/commonjs/src/screen/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/securitySuite/index.d.ts +6 -0
- package/lib/typescript/commonjs/src/securitySuite/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/storage/index.d.ts +2 -0
- package/lib/typescript/commonjs/src/storage/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/types/detection.d.ts +41 -0
- package/lib/typescript/commonjs/src/types/detection.d.ts.map +1 -0
- package/lib/typescript/module/docs/api-v1-proposal.d.ts +215 -0
- package/lib/typescript/module/docs/api-v1-proposal.d.ts.map +1 -0
- package/lib/typescript/module/src/SecureView.d.ts +1 -1
- package/lib/typescript/module/src/SecureView.d.ts.map +1 -1
- package/lib/typescript/module/src/clipboard/index.d.ts +2 -0
- package/lib/typescript/module/src/clipboard/index.d.ts.map +1 -0
- package/lib/typescript/module/src/crypto/index.d.ts +15 -0
- package/lib/typescript/module/src/crypto/index.d.ts.map +1 -0
- package/lib/typescript/module/src/device/index.d.ts +11 -0
- package/lib/typescript/module/src/device/index.d.ts.map +1 -0
- package/lib/typescript/module/src/errors.d.ts +17 -0
- package/lib/typescript/module/src/errors.d.ts.map +1 -0
- package/lib/typescript/module/src/helpers.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +77 -24
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/integrity/index.d.ts +6 -0
- package/lib/typescript/module/src/integrity/index.d.ts.map +1 -0
- package/lib/typescript/module/src/jws.d.ts +44 -0
- package/lib/typescript/module/src/jws.d.ts.map +1 -0
- package/lib/typescript/module/src/legacy/cryptoOptions.d.ts +35 -0
- package/lib/typescript/module/src/legacy/cryptoOptions.d.ts.map +1 -0
- package/lib/typescript/module/src/native/bridge.d.ts +12 -0
- package/lib/typescript/module/src/native/bridge.d.ts.map +1 -0
- package/lib/typescript/module/src/network/index.d.ts +2 -0
- package/lib/typescript/module/src/network/index.d.ts.map +1 -0
- package/lib/typescript/module/src/risk/score.d.ts +12 -0
- package/lib/typescript/module/src/risk/score.d.ts.map +1 -0
- package/lib/typescript/module/src/runtime/index.d.ts +6 -0
- package/lib/typescript/module/src/runtime/index.d.ts.map +1 -0
- package/lib/typescript/module/src/screen/index.d.ts +3 -0
- package/lib/typescript/module/src/screen/index.d.ts.map +1 -0
- package/lib/typescript/module/src/securitySuite/index.d.ts +6 -0
- package/lib/typescript/module/src/securitySuite/index.d.ts.map +1 -0
- package/lib/typescript/module/src/storage/index.d.ts +2 -0
- package/lib/typescript/module/src/storage/index.d.ts.map +1 -0
- package/lib/typescript/module/src/types/detection.d.ts +41 -0
- package/lib/typescript/module/src/types/detection.d.ts.map +1 -0
- package/package.json +2 -10
- package/src/clipboard/index.ts +1 -0
- package/src/crypto/index.ts +49 -0
- package/src/device/index.ts +47 -0
- package/src/errors.ts +84 -0
- package/src/index.tsx +293 -195
- package/src/integrity/index.ts +46 -0
- package/src/jws.ts +213 -0
- package/src/legacy/cryptoOptions.ts +49 -0
- package/src/native/bridge.ts +37 -0
- package/src/network/index.ts +1 -0
- package/src/risk/score.ts +49 -0
- package/src/runtime/index.ts +43 -0
- package/src/screen/index.ts +2 -0
- package/src/securitySuite/index.ts +45 -0
- package/src/storage/index.ts +1 -0
- package/src/types/detection.ts +46 -0
- package/android/src/main/java/com/securitysuite/StorageEncryption.java +0 -52
- package/ios/StorageEncryption.swift +0 -89
|
@@ -1,203 +1,411 @@
|
|
|
1
1
|
package com.securitysuite;
|
|
2
2
|
|
|
3
|
+
import com.facebook.react.bridge.Arguments;
|
|
3
4
|
import com.facebook.react.bridge.Callback;
|
|
4
5
|
import com.facebook.react.bridge.Promise;
|
|
5
6
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
6
7
|
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
7
8
|
import com.facebook.react.bridge.ReactMethod;
|
|
9
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
8
10
|
import com.facebook.react.bridge.ReadableMap;
|
|
11
|
+
import com.facebook.react.bridge.WritableArray;
|
|
9
12
|
import com.facebook.react.module.annotations.ReactModule;
|
|
10
13
|
|
|
11
14
|
import androidx.annotation.NonNull;
|
|
12
15
|
|
|
13
|
-
import android.annotation.SuppressLint;
|
|
14
|
-
import android.provider.Settings;
|
|
15
16
|
import android.util.Base64;
|
|
16
17
|
import android.util.Log;
|
|
17
18
|
|
|
18
19
|
import java.nio.charset.Charset;
|
|
19
|
-
import java.
|
|
20
|
-
import java.security.InvalidKeyException;
|
|
20
|
+
import java.nio.charset.StandardCharsets;
|
|
21
21
|
import java.security.KeyFactory;
|
|
22
|
-
import java.security.KeyPair;
|
|
23
|
-
import java.security.KeyPairGenerator;
|
|
24
|
-
import java.security.NoSuchAlgorithmException;
|
|
25
22
|
import java.security.PrivateKey;
|
|
26
23
|
import java.security.PublicKey;
|
|
27
|
-
import java.security.spec.ECGenParameterSpec;
|
|
28
24
|
import java.security.spec.X509EncodedKeySpec;
|
|
29
25
|
|
|
30
|
-
import javax.crypto.BadPaddingException;
|
|
31
26
|
import javax.crypto.Cipher;
|
|
32
|
-
import javax.crypto.IllegalBlockSizeException;
|
|
33
27
|
import javax.crypto.KeyAgreement;
|
|
34
|
-
import javax.crypto.NoSuchPaddingException;
|
|
35
28
|
import javax.crypto.SecretKey;
|
|
36
29
|
import javax.crypto.spec.GCMParameterSpec;
|
|
37
30
|
import javax.crypto.spec.SecretKeySpec;
|
|
38
31
|
|
|
39
32
|
import com.scottyab.rootbeer.RootBeer;
|
|
40
33
|
|
|
34
|
+
import com.securitysuite.security.AppIntegrityChecker;
|
|
35
|
+
import com.securitysuite.security.EmulatorDetector;
|
|
36
|
+
import com.securitysuite.security.RuntimeDetector;
|
|
37
|
+
|
|
41
38
|
@ReactModule(name = SecuritySuiteModule.NAME)
|
|
42
39
|
public class SecuritySuiteModule extends ReactContextBaseJavaModule {
|
|
43
40
|
public static final String NAME = "SecuritySuite";
|
|
44
|
-
private ReactApplicationContext context;
|
|
41
|
+
private final ReactApplicationContext context;
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
PublicKey serverPublicKey;
|
|
50
|
-
PrivateKey privateKey;
|
|
51
|
-
String sharedKey;
|
|
52
|
-
SecretKey secretKey;
|
|
43
|
+
private SecretKey encryptionKey;
|
|
44
|
+
private SecretKey hmacKey;
|
|
45
|
+
private CryptoConfig cryptoConfig = CryptoConfig.defaults();
|
|
53
46
|
|
|
54
47
|
public SecuritySuiteModule(ReactApplicationContext reactContext) {
|
|
55
48
|
super(reactContext);
|
|
56
49
|
context = reactContext;
|
|
57
|
-
generateKeyPair();
|
|
58
50
|
}
|
|
59
51
|
|
|
60
|
-
|
|
52
|
+
@ReactMethod
|
|
53
|
+
public void getPublicKey(Promise promise) {
|
|
61
54
|
try {
|
|
62
|
-
|
|
63
|
-
ECGenParameterSpec prime256v1ParamSpec = new ECGenParameterSpec("secp256r1");
|
|
64
|
-
keyPairGenerator.initialize(prime256v1ParamSpec);
|
|
65
|
-
keyPair = keyPairGenerator.genKeyPair();
|
|
66
|
-
publicKey = keyPair.getPublic();
|
|
67
|
-
privateKey = keyPair.getPrivate();
|
|
55
|
+
promise.resolve(EcdhKeyStore.getPublicKeyBase64(context));
|
|
68
56
|
} catch (Exception e) {
|
|
69
|
-
|
|
57
|
+
promise.reject("GET_PUBLIC_KEY_ERROR", e.getMessage(), e);
|
|
70
58
|
}
|
|
71
59
|
}
|
|
72
60
|
|
|
73
61
|
@ReactMethod
|
|
74
|
-
public void
|
|
75
|
-
String base64DEREncoded = Base64.encodeToString(publicKey.getEncoded(), Base64.NO_WRAP);
|
|
76
|
-
promise.resolve(base64DEREncoded);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
private static SecretKey agreeSecretKey(PrivateKey prk_self, PublicKey pbk_peer, boolean lastPhase) throws Exception {
|
|
80
|
-
SecretKey desSpec;
|
|
62
|
+
public void establishSharedKey(String serverPK, ReadableMap options, Promise promise) {
|
|
81
63
|
try {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
64
|
+
if (serverPK == null || serverPK.trim().isEmpty()) {
|
|
65
|
+
promise.reject("GET_SHARED_KEY_ERROR", "Server public key is required");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
cryptoConfig = CryptoConfig.fromReadableMap(options);
|
|
70
|
+
|
|
71
|
+
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(
|
|
72
|
+
Base64.decode(serverPK.trim(), Base64.NO_WRAP)
|
|
73
|
+
);
|
|
74
|
+
KeyFactory keyFactory = KeyFactory.getInstance(cryptoConfig.keyFactoryAlgorithm);
|
|
75
|
+
PublicKey serverPublicKey = keyFactory.generatePublic(keySpec);
|
|
76
|
+
PrivateKey privateKey = EcdhKeyStore.getPrivateKey(context);
|
|
77
|
+
|
|
78
|
+
KeyAgreement keyAgree = KeyAgreement.getInstance(cryptoConfig.keyAgreementAlgorithm);
|
|
79
|
+
keyAgree.init(privateKey);
|
|
80
|
+
keyAgree.doPhase(serverPublicKey, true);
|
|
81
|
+
byte[] sharedSecret = keyAgree.generateSecret();
|
|
82
|
+
|
|
83
|
+
byte[] encKeyBytes = CryptoUtils.deriveEncryptionKey(sharedSecret);
|
|
84
|
+
byte[] macKeyBytes = CryptoUtils.deriveHmacKey(sharedSecret);
|
|
85
|
+
encryptionKey = new SecretKeySpec(encKeyBytes, cryptoConfig.encryptionKeyAlgorithm);
|
|
86
|
+
hmacKey = new SecretKeySpec(macKeyBytes, cryptoConfig.hmacKeyAlgorithm);
|
|
87
|
+
|
|
88
|
+
promise.resolve(null);
|
|
89
|
+
} catch (Exception e) {
|
|
90
|
+
Log.e("establishSharedKey Error: ", String.valueOf(e));
|
|
91
|
+
promise.reject("GET_SHARED_KEY_ERROR", e.getMessage(), e);
|
|
91
92
|
}
|
|
92
|
-
return desSpec;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
@ReactMethod
|
|
96
|
-
public void getSharedKey(String serverPK, Promise promise) {
|
|
96
|
+
public void getSharedKey(String serverPK, ReadableMap options, Promise promise) {
|
|
97
97
|
try {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
if (serverPK == null || serverPK.trim().isEmpty()) {
|
|
99
|
+
promise.reject("GET_SHARED_KEY_ERROR", "Server public key is required");
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
cryptoConfig = CryptoConfig.fromReadableMap(options);
|
|
104
|
+
|
|
105
|
+
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(
|
|
106
|
+
Base64.decode(serverPK.trim(), Base64.NO_WRAP)
|
|
107
|
+
);
|
|
108
|
+
KeyFactory keyFactory = KeyFactory.getInstance(cryptoConfig.keyFactoryAlgorithm);
|
|
109
|
+
PublicKey serverPublicKey = keyFactory.generatePublic(keySpec);
|
|
110
|
+
PrivateKey privateKey = EcdhKeyStore.getPrivateKey(context);
|
|
111
|
+
|
|
112
|
+
KeyAgreement keyAgree = KeyAgreement.getInstance(cryptoConfig.keyAgreementAlgorithm);
|
|
113
|
+
keyAgree.init(privateKey);
|
|
114
|
+
keyAgree.doPhase(serverPublicKey, true);
|
|
115
|
+
byte[] sharedSecret = keyAgree.generateSecret();
|
|
116
|
+
|
|
117
|
+
byte[] encKeyBytes = CryptoUtils.deriveEncryptionKey(sharedSecret);
|
|
118
|
+
byte[] macKeyBytes = CryptoUtils.deriveHmacKey(sharedSecret);
|
|
119
|
+
encryptionKey = new SecretKeySpec(encKeyBytes, cryptoConfig.encryptionKeyAlgorithm);
|
|
120
|
+
hmacKey = new SecretKeySpec(macKeyBytes, cryptoConfig.hmacKeyAlgorithm);
|
|
121
|
+
|
|
122
|
+
promise.resolve(Base64.encodeToString(encKeyBytes, Base64.NO_WRAP));
|
|
104
123
|
} catch (Exception e) {
|
|
105
124
|
Log.e("getSharedKey Error: ", String.valueOf(e));
|
|
106
|
-
promise.reject(
|
|
125
|
+
promise.reject("GET_SHARED_KEY_ERROR", e.getMessage(), e);
|
|
107
126
|
}
|
|
108
127
|
}
|
|
109
128
|
|
|
110
129
|
@ReactMethod
|
|
111
|
-
public void encrypt(String input, Promise promise) {
|
|
130
|
+
public void encrypt(String input, ReadableMap options, Promise promise) {
|
|
112
131
|
try {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
132
|
+
if (encryptionKey == null) {
|
|
133
|
+
promise.reject("ENCRYPT_ERROR", "Encryption key not established. Call getSharedKey first.");
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
CryptoConfig config = cryptoConfig.merge(options);
|
|
137
|
+
byte[] inputByte = input.getBytes(StandardCharsets.UTF_8);
|
|
138
|
+
Cipher cipher = Cipher.getInstance(config.cipherTransformation);
|
|
139
|
+
cipher.init(Cipher.ENCRYPT_MODE, encryptionKey);
|
|
118
140
|
byte[] iv = cipher.getIV();
|
|
119
|
-
assert iv.length == 12;
|
|
120
141
|
byte[] cipherText = cipher.doFinal(inputByte);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
System.arraycopy(iv, 0, output, 0, 12);
|
|
125
|
-
System.arraycopy(cipherText, 0, output, 12, cipherText.length);
|
|
142
|
+
byte[] output = new byte[iv.length + cipherText.length];
|
|
143
|
+
System.arraycopy(iv, 0, output, 0, iv.length);
|
|
144
|
+
System.arraycopy(cipherText, 0, output, iv.length, cipherText.length);
|
|
126
145
|
promise.resolve(Base64.encodeToString(output, Base64.NO_WRAP));
|
|
127
146
|
} catch (Exception e) {
|
|
128
|
-
|
|
129
|
-
promise.reject(String.valueOf(e));
|
|
147
|
+
promise.reject("ENCRYPT_ERROR", e.getMessage(), e);
|
|
130
148
|
}
|
|
131
149
|
}
|
|
132
150
|
|
|
133
151
|
@ReactMethod
|
|
134
|
-
public void decrypt(String input, Promise promise) {
|
|
152
|
+
public void decrypt(String input, ReadableMap options, Promise promise) {
|
|
135
153
|
try {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
byte[]
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
154
|
+
if (encryptionKey == null) {
|
|
155
|
+
promise.reject("DECRYPT_ERROR", "Encryption key not established. Call getSharedKey first.");
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
CryptoConfig config = cryptoConfig.merge(options);
|
|
159
|
+
byte[] inputBytes = Base64.decode(input.getBytes(StandardCharsets.UTF_8), Base64.NO_WRAP);
|
|
160
|
+
int minLength = config.gcmIvLength + (config.gcmTagLength / 8);
|
|
161
|
+
if (inputBytes.length < minLength) {
|
|
162
|
+
promise.reject("DECRYPT_ERROR", "Invalid ciphertext");
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
Cipher cipher = Cipher.getInstance(config.cipherTransformation);
|
|
166
|
+
GCMParameterSpec params = new GCMParameterSpec(
|
|
167
|
+
config.gcmTagLength,
|
|
168
|
+
inputBytes,
|
|
169
|
+
0,
|
|
170
|
+
config.gcmIvLength
|
|
171
|
+
);
|
|
172
|
+
cipher.init(Cipher.DECRYPT_MODE, encryptionKey, params);
|
|
173
|
+
byte[] plaintext = cipher.doFinal(
|
|
174
|
+
inputBytes,
|
|
175
|
+
config.gcmIvLength,
|
|
176
|
+
inputBytes.length - config.gcmIvLength
|
|
177
|
+
);
|
|
178
|
+
promise.resolve(new String(plaintext, Charset.forName("UTF-8")));
|
|
179
|
+
} catch (Exception e) {
|
|
180
|
+
promise.reject("DECRYPT_ERROR", e.getMessage(), e);
|
|
150
181
|
}
|
|
151
182
|
}
|
|
152
183
|
|
|
153
184
|
@ReactMethod
|
|
154
|
-
public void
|
|
185
|
+
public void generateJWS(ReadableMap options, Promise promise) {
|
|
155
186
|
try {
|
|
156
|
-
|
|
157
|
-
|
|
187
|
+
if (options == null || !options.hasKey("secret")) {
|
|
188
|
+
promise.reject("JWS_ERROR", "JWS secret is required and must be a non-empty string");
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
String secret = options.getString("secret");
|
|
193
|
+
if (secret == null || secret.trim().isEmpty()) {
|
|
194
|
+
promise.reject("JWS_ERROR", "JWS secret is required and must be a non-empty string");
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
String payload = "";
|
|
199
|
+
if (options.hasKey("payload") && !options.isNull("payload")) {
|
|
200
|
+
payload = options.getString("payload");
|
|
201
|
+
if (payload == null) {
|
|
202
|
+
payload = "";
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
String algorithm = options.hasKey("algorithm") ? options.getString("algorithm") : null;
|
|
207
|
+
ReadableMap headers = options.hasKey("headers") ? options.getMap("headers") : null;
|
|
208
|
+
boolean detached = options.hasKey("detached") && options.getBoolean("detached");
|
|
209
|
+
|
|
210
|
+
JWSGenerator generator = new JWSGenerator();
|
|
211
|
+
String jws = generator.generate(payload, secret, algorithm, headers, detached);
|
|
212
|
+
promise.resolve(jws);
|
|
158
213
|
} catch (Exception e) {
|
|
159
|
-
|
|
214
|
+
promise.reject("JWS_ERROR", e.getMessage(), e);
|
|
160
215
|
}
|
|
161
216
|
}
|
|
162
217
|
|
|
218
|
+
@ReactMethod
|
|
219
|
+
public void obfuscate(String input, String secret, Promise promise) {
|
|
220
|
+
try {
|
|
221
|
+
promise.resolve(Obfuscation.obfuscate(input, secret));
|
|
222
|
+
} catch (Exception e) {
|
|
223
|
+
promise.reject("OBFUSCATE_ERROR", e.getMessage(), e);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
@ReactMethod
|
|
228
|
+
public void deobfuscate(String input, String secret, Promise promise) {
|
|
229
|
+
try {
|
|
230
|
+
promise.resolve(Obfuscation.deobfuscate(input, secret));
|
|
231
|
+
} catch (Exception e) {
|
|
232
|
+
promise.reject("DEOBFUSCATE_ERROR", e.getMessage(), e);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** @deprecated Use obfuscate() or SecureStorage instead. */
|
|
163
237
|
@ReactMethod
|
|
164
238
|
public void storageEncrypt(String input, String secretKey, Boolean hardEncryption, Callback callback) {
|
|
165
239
|
try {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
240
|
+
if (secretKey == null || secretKey.trim().isEmpty()) {
|
|
241
|
+
callback.invoke(null, "secretKey is required. Device identifiers are not accepted as encryption keys.");
|
|
242
|
+
return;
|
|
169
243
|
}
|
|
170
|
-
|
|
171
|
-
|
|
244
|
+
if (Boolean.TRUE.equals(hardEncryption)) {
|
|
245
|
+
callback.invoke(
|
|
246
|
+
null,
|
|
247
|
+
"hardEncryption is deprecated. Use SecureStorage for encrypted-at-rest data."
|
|
248
|
+
);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
callback.invoke(Obfuscation.obfuscate(input, secretKey), null);
|
|
172
252
|
} catch (Exception e) {
|
|
173
|
-
callback.invoke(null, e);
|
|
253
|
+
callback.invoke(null, e.getMessage());
|
|
174
254
|
}
|
|
175
255
|
}
|
|
176
256
|
|
|
257
|
+
/** @deprecated Use deobfuscate() or SecureStorage APIs instead. */
|
|
177
258
|
@ReactMethod
|
|
178
259
|
public void storageDecrypt(String input, String secretKey, Boolean hardEncryption, Callback callback) {
|
|
179
260
|
try {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
261
|
+
if (secretKey == null || secretKey.trim().isEmpty()) {
|
|
262
|
+
callback.invoke(null, "secretKey is required. Device identifiers are not accepted as encryption keys.");
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (Boolean.TRUE.equals(hardEncryption)) {
|
|
266
|
+
callback.invoke(
|
|
267
|
+
null,
|
|
268
|
+
"hardEncryption is deprecated. Use SecureStorage for encrypted-at-rest data."
|
|
269
|
+
);
|
|
270
|
+
return;
|
|
183
271
|
}
|
|
184
|
-
|
|
185
|
-
callback.invoke(decryptedMessage, null);
|
|
272
|
+
callback.invoke(Obfuscation.deobfuscate(input, secretKey), null);
|
|
186
273
|
} catch (Exception e) {
|
|
187
274
|
callback.invoke(null, e.getMessage());
|
|
188
275
|
}
|
|
189
276
|
}
|
|
190
277
|
|
|
191
|
-
@
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
278
|
+
@ReactMethod
|
|
279
|
+
public void secureStorageSetItem(String key, String value, Promise promise) {
|
|
280
|
+
try {
|
|
281
|
+
SecureStorageNative.setItem(context, key, value);
|
|
282
|
+
promise.resolve(null);
|
|
283
|
+
} catch (Exception e) {
|
|
284
|
+
promise.reject("SECURE_STORAGE_ERROR", secureStorageMessage(e), e);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
@ReactMethod
|
|
289
|
+
public void secureStorageGetItem(String key, Promise promise) {
|
|
290
|
+
try {
|
|
291
|
+
promise.resolve(SecureStorageNative.getItem(context, key));
|
|
292
|
+
} catch (Exception e) {
|
|
293
|
+
promise.reject("SECURE_STORAGE_ERROR", secureStorageMessage(e), e);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
@ReactMethod
|
|
298
|
+
public void secureStorageRemoveItem(String key, Promise promise) {
|
|
299
|
+
try {
|
|
300
|
+
SecureStorageNative.removeItem(context, key);
|
|
301
|
+
promise.resolve(null);
|
|
302
|
+
} catch (Exception e) {
|
|
303
|
+
promise.reject("SECURE_STORAGE_ERROR", secureStorageMessage(e), e);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
@ReactMethod
|
|
308
|
+
public void secureStorageClear(Promise promise) {
|
|
309
|
+
try {
|
|
310
|
+
SecureStorageNative.clear(context);
|
|
311
|
+
promise.resolve(null);
|
|
312
|
+
} catch (Exception e) {
|
|
313
|
+
promise.reject("SECURE_STORAGE_ERROR", secureStorageMessage(e), e);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
@ReactMethod
|
|
318
|
+
public void secureStorageGetAllKeys(Promise promise) {
|
|
319
|
+
try {
|
|
320
|
+
promise.resolve(SecureStorageNative.getAllKeys(context));
|
|
321
|
+
} catch (Exception e) {
|
|
322
|
+
promise.reject("SECURE_STORAGE_ERROR", secureStorageMessage(e), e);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
@ReactMethod
|
|
327
|
+
public void secureStorageMultiSet(ReadableArray pairs, Promise promise) {
|
|
328
|
+
try {
|
|
329
|
+
SecureStorageNative.multiSet(context, pairs);
|
|
330
|
+
promise.resolve(null);
|
|
331
|
+
} catch (Exception e) {
|
|
332
|
+
promise.reject("SECURE_STORAGE_ERROR", secureStorageMessage(e), e);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
@ReactMethod
|
|
337
|
+
public void secureStorageMultiGet(ReadableArray keys, Promise promise) {
|
|
338
|
+
try {
|
|
339
|
+
promise.resolve(SecureStorageNative.multiGet(context, keys));
|
|
340
|
+
} catch (Exception e) {
|
|
341
|
+
promise.reject("SECURE_STORAGE_ERROR", secureStorageMessage(e), e);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
@ReactMethod
|
|
346
|
+
public void secureStorageMultiRemove(ReadableArray keys, Promise promise) {
|
|
347
|
+
try {
|
|
348
|
+
SecureStorageNative.multiRemove(context, keys);
|
|
349
|
+
promise.resolve(null);
|
|
350
|
+
} catch (Exception e) {
|
|
351
|
+
promise.reject("SECURE_STORAGE_ERROR", secureStorageMessage(e), e);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
private static String secureStorageMessage(Exception error) {
|
|
356
|
+
String message = error.getMessage();
|
|
357
|
+
if (message != null && !message.isEmpty()) {
|
|
358
|
+
return message;
|
|
359
|
+
}
|
|
360
|
+
return "Secure storage operation failed";
|
|
195
361
|
}
|
|
196
362
|
|
|
197
363
|
@ReactMethod
|
|
198
364
|
public void fetch(String url, final ReadableMap options, Callback callback) {
|
|
199
365
|
Sslpinning sslpinning = new Sslpinning(context);
|
|
200
|
-
sslpinning.fetch(url, options,
|
|
366
|
+
sslpinning.fetch(url, options, callback);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
@ReactMethod
|
|
370
|
+
public void getDeviceId(Callback callback) {
|
|
371
|
+
try {
|
|
372
|
+
callback.invoke(
|
|
373
|
+
android.provider.Settings.Secure.getString(
|
|
374
|
+
context.getContentResolver(),
|
|
375
|
+
android.provider.Settings.Secure.ANDROID_ID
|
|
376
|
+
),
|
|
377
|
+
null
|
|
378
|
+
);
|
|
379
|
+
} catch (Exception e) {
|
|
380
|
+
callback.invoke(null, e.getMessage());
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
@ReactMethod
|
|
385
|
+
public void runtimeDetect(Promise promise) {
|
|
386
|
+
try {
|
|
387
|
+
promise.resolve(RuntimeDetector.detect());
|
|
388
|
+
} catch (Exception e) {
|
|
389
|
+
promise.reject("RUNTIME_DETECT_ERROR", e.getMessage(), e);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
@ReactMethod
|
|
394
|
+
public void appIntegrityVerify(Promise promise) {
|
|
395
|
+
try {
|
|
396
|
+
promise.resolve(AppIntegrityChecker.verify(context));
|
|
397
|
+
} catch (Exception e) {
|
|
398
|
+
promise.reject("APP_INTEGRITY_ERROR", e.getMessage(), e);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
@ReactMethod
|
|
403
|
+
public void deviceGetEnvironment(Promise promise) {
|
|
404
|
+
try {
|
|
405
|
+
promise.resolve(EmulatorDetector.detect(context));
|
|
406
|
+
} catch (Exception e) {
|
|
407
|
+
promise.reject("DEVICE_ENVIRONMENT_ERROR", e.getMessage(), e);
|
|
408
|
+
}
|
|
201
409
|
}
|
|
202
410
|
|
|
203
411
|
@ReactMethod
|