@onekeyfe/react-native-aes-crypto 3.0.7 → 3.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/android/build.gradle
CHANGED
|
@@ -74,4 +74,7 @@ def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
|
74
74
|
dependencies {
|
|
75
75
|
implementation "com.facebook.react:react-android"
|
|
76
76
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
77
|
+
implementation "com.madgag.spongycastle:core:1.58.0.0"
|
|
78
|
+
implementation "com.madgag.spongycastle:prov:1.54.0.0"
|
|
79
|
+
implementation "com.madgag.spongycastle:pg:1.54.0.0"
|
|
77
80
|
}
|
|
@@ -9,194 +9,192 @@ import java.security.SecureRandom
|
|
|
9
9
|
import java.util.UUID
|
|
10
10
|
import javax.crypto.Cipher
|
|
11
11
|
import javax.crypto.Mac
|
|
12
|
-
import javax.crypto.SecretKeyFactory
|
|
13
12
|
import javax.crypto.spec.IvParameterSpec
|
|
14
|
-
import javax.crypto.spec.PBEKeySpec
|
|
15
13
|
import javax.crypto.spec.SecretKeySpec
|
|
16
|
-
|
|
14
|
+
import org.spongycastle.crypto.Digest
|
|
15
|
+
import org.spongycastle.crypto.digests.SHA1Digest
|
|
16
|
+
import org.spongycastle.crypto.digests.SHA256Digest
|
|
17
|
+
import org.spongycastle.crypto.digests.SHA512Digest
|
|
18
|
+
import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator
|
|
19
|
+
import org.spongycastle.crypto.params.KeyParameter
|
|
20
|
+
import org.spongycastle.util.encoders.Hex
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Ported from upstream react-native-aes-crypto Aes.java.
|
|
24
|
+
* Adapted to extend NativeAesCryptoSpec (TurboModule).
|
|
25
|
+
*/
|
|
17
26
|
@ReactModule(name = AesCryptoModule.NAME)
|
|
18
27
|
class AesCryptoModule(reactContext: ReactApplicationContext) :
|
|
19
28
|
NativeAesCryptoSpec(reactContext) {
|
|
20
29
|
|
|
21
30
|
companion object {
|
|
22
31
|
const val NAME = "AesCrypto"
|
|
32
|
+
private const val CIPHER_CBC_ALGORITHM = "AES/CBC/PKCS7Padding"
|
|
33
|
+
private const val CIPHER_CTR_ALGORITHM = "AES/CTR/PKCS5Padding"
|
|
34
|
+
private const val HMAC_SHA_256 = "HmacSHA256"
|
|
35
|
+
private const val HMAC_SHA_512 = "HmacSHA512"
|
|
36
|
+
private const val KEY_ALGORITHM = "AES"
|
|
37
|
+
|
|
38
|
+
private val emptyIvSpec = IvParameterSpec(ByteArray(16) { 0x00 })
|
|
39
|
+
|
|
40
|
+
@JvmStatic
|
|
41
|
+
fun bytesToHex(bytes: ByteArray): String {
|
|
42
|
+
val hexArray = "0123456789abcdef".toCharArray()
|
|
43
|
+
val hexChars = CharArray(bytes.size * 2)
|
|
44
|
+
for (j in bytes.indices) {
|
|
45
|
+
val v = bytes[j].toInt() and 0xFF
|
|
46
|
+
hexChars[j * 2] = hexArray[v ushr 4]
|
|
47
|
+
hexChars[j * 2 + 1] = hexArray[v and 0x0F]
|
|
48
|
+
}
|
|
49
|
+
return String(hexChars)
|
|
50
|
+
}
|
|
23
51
|
}
|
|
24
52
|
|
|
25
53
|
override fun getName(): String = NAME
|
|
26
54
|
|
|
27
|
-
private fun cipherTransformation(algorithm: String): String {
|
|
28
|
-
return when (algorithm.lowercase()) {
|
|
29
|
-
"aes-128-cbc", "aes-192-cbc", "aes-256-cbc" -> "AES/CBC/PKCS5Padding"
|
|
30
|
-
"aes-128-ecb", "aes-192-ecb", "aes-256-ecb" -> "AES/ECB/PKCS5Padding"
|
|
31
|
-
else -> "AES/CBC/PKCS5Padding"
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
55
|
override fun encrypt(data: String, key: String, iv: String, algorithm: String, promise: Promise) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (transformation.contains("ECB")) {
|
|
44
|
-
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
|
|
45
|
-
} else {
|
|
46
|
-
cipher.init(Cipher.ENCRYPT_MODE, secretKey, IvParameterSpec(ivBytes))
|
|
47
|
-
}
|
|
48
|
-
val encrypted = cipher.doFinal(data.toByteArray(Charsets.UTF_8))
|
|
49
|
-
promise.resolve(Base64.encodeToString(encrypted, Base64.NO_WRAP))
|
|
50
|
-
} catch (e: Exception) {
|
|
51
|
-
promise.reject("AES_CRYPTO_ERROR", e.message, e)
|
|
52
|
-
}
|
|
53
|
-
}.start()
|
|
56
|
+
try {
|
|
57
|
+
val cipherAlgorithm = if (algorithm.lowercase().contains("cbc")) CIPHER_CBC_ALGORITHM else CIPHER_CTR_ALGORITHM
|
|
58
|
+
val result = encryptImpl(data, key, iv, cipherAlgorithm)
|
|
59
|
+
promise.resolve(result)
|
|
60
|
+
} catch (e: Exception) {
|
|
61
|
+
promise.reject("-1", e.message)
|
|
62
|
+
}
|
|
54
63
|
}
|
|
55
64
|
|
|
56
65
|
override fun decrypt(base64: String, key: String, iv: String, algorithm: String, promise: Promise) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (transformation.contains("ECB")) {
|
|
65
|
-
cipher.init(Cipher.DECRYPT_MODE, secretKey)
|
|
66
|
-
} else {
|
|
67
|
-
cipher.init(Cipher.DECRYPT_MODE, secretKey, IvParameterSpec(ivBytes))
|
|
68
|
-
}
|
|
69
|
-
val decrypted = cipher.doFinal(Base64.decode(base64, Base64.NO_WRAP))
|
|
70
|
-
promise.resolve(String(decrypted, Charsets.UTF_8))
|
|
71
|
-
} catch (e: Exception) {
|
|
72
|
-
promise.reject("AES_CRYPTO_ERROR", e.message, e)
|
|
73
|
-
}
|
|
74
|
-
}.start()
|
|
66
|
+
try {
|
|
67
|
+
val cipherAlgorithm = if (algorithm.lowercase().contains("cbc")) CIPHER_CBC_ALGORITHM else CIPHER_CTR_ALGORITHM
|
|
68
|
+
val result = decryptImpl(base64, key, iv, cipherAlgorithm)
|
|
69
|
+
promise.resolve(result)
|
|
70
|
+
} catch (e: Exception) {
|
|
71
|
+
promise.reject("-1", e.message)
|
|
72
|
+
}
|
|
75
73
|
}
|
|
76
74
|
|
|
77
75
|
override fun pbkdf2(password: String, salt: String, cost: Double, length: Double, algorithm: String, promise: Promise) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
val secretKey = SecretKeySpec(hexToBytes(key), "HmacSHA256")
|
|
103
|
-
mac.init(secretKey)
|
|
104
|
-
val result = mac.doFinal(Base64.decode(base64, Base64.NO_WRAP))
|
|
105
|
-
promise.resolve(bytesToHex(result))
|
|
106
|
-
} catch (e: Exception) {
|
|
107
|
-
promise.reject("AES_CRYPTO_ERROR", e.message, e)
|
|
108
|
-
}
|
|
109
|
-
}.start()
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
override fun hmac512(base64: String, key: String, promise: Promise) {
|
|
113
|
-
Thread {
|
|
114
|
-
try {
|
|
115
|
-
val mac = Mac.getInstance("HmacSHA512")
|
|
116
|
-
val secretKey = SecretKeySpec(hexToBytes(key), "HmacSHA512")
|
|
117
|
-
mac.init(secretKey)
|
|
118
|
-
val result = mac.doFinal(Base64.decode(base64, Base64.NO_WRAP))
|
|
119
|
-
promise.resolve(bytesToHex(result))
|
|
120
|
-
} catch (e: Exception) {
|
|
121
|
-
promise.reject("AES_CRYPTO_ERROR", e.message, e)
|
|
122
|
-
}
|
|
123
|
-
}.start()
|
|
76
|
+
try {
|
|
77
|
+
val result = pbkdf2Impl(password, salt, cost.toInt(), length.toInt(), algorithm)
|
|
78
|
+
promise.resolve(result)
|
|
79
|
+
} catch (e: Exception) {
|
|
80
|
+
promise.reject("-1", e.message)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
override fun hmac256(data: String, key: String, promise: Promise) {
|
|
85
|
+
try {
|
|
86
|
+
val result = hmacX(data, key, HMAC_SHA_256)
|
|
87
|
+
promise.resolve(result)
|
|
88
|
+
} catch (e: Exception) {
|
|
89
|
+
promise.reject("-1", e.message)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
override fun hmac512(data: String, key: String, promise: Promise) {
|
|
94
|
+
try {
|
|
95
|
+
val result = hmacX(data, key, HMAC_SHA_512)
|
|
96
|
+
promise.resolve(result)
|
|
97
|
+
} catch (e: Exception) {
|
|
98
|
+
promise.reject("-1", e.message)
|
|
99
|
+
}
|
|
124
100
|
}
|
|
125
101
|
|
|
126
102
|
override fun sha1(text: String, promise: Promise) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
promise.reject("AES_CRYPTO_ERROR", e.message, e)
|
|
134
|
-
}
|
|
135
|
-
}.start()
|
|
103
|
+
try {
|
|
104
|
+
val result = shaX(text, "SHA-1")
|
|
105
|
+
promise.resolve(result)
|
|
106
|
+
} catch (e: Exception) {
|
|
107
|
+
promise.reject("-1", e.message)
|
|
108
|
+
}
|
|
136
109
|
}
|
|
137
110
|
|
|
138
111
|
override fun sha256(text: String, promise: Promise) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
promise.reject("AES_CRYPTO_ERROR", e.message, e)
|
|
146
|
-
}
|
|
147
|
-
}.start()
|
|
112
|
+
try {
|
|
113
|
+
val result = shaX(text, "SHA-256")
|
|
114
|
+
promise.resolve(result)
|
|
115
|
+
} catch (e: Exception) {
|
|
116
|
+
promise.reject("-1", e.message)
|
|
117
|
+
}
|
|
148
118
|
}
|
|
149
119
|
|
|
150
120
|
override fun sha512(text: String, promise: Promise) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
promise.reject("AES_CRYPTO_ERROR", e.message, e)
|
|
158
|
-
}
|
|
159
|
-
}.start()
|
|
121
|
+
try {
|
|
122
|
+
val result = shaX(text, "SHA-512")
|
|
123
|
+
promise.resolve(result)
|
|
124
|
+
} catch (e: Exception) {
|
|
125
|
+
promise.reject("-1", e.message)
|
|
126
|
+
}
|
|
160
127
|
}
|
|
161
128
|
|
|
162
129
|
override fun randomUuid(promise: Promise) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
}.start()
|
|
130
|
+
try {
|
|
131
|
+
promise.resolve(UUID.randomUUID().toString())
|
|
132
|
+
} catch (e: Exception) {
|
|
133
|
+
promise.reject("-1", e.message)
|
|
134
|
+
}
|
|
170
135
|
}
|
|
171
136
|
|
|
172
137
|
override fun randomKey(length: Double, promise: Promise) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
}.start()
|
|
138
|
+
try {
|
|
139
|
+
val key = ByteArray(length.toInt())
|
|
140
|
+
SecureRandom().nextBytes(key)
|
|
141
|
+
promise.resolve(bytesToHex(key))
|
|
142
|
+
} catch (e: Exception) {
|
|
143
|
+
promise.reject("-1", e.message)
|
|
144
|
+
}
|
|
182
145
|
}
|
|
183
146
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
i += 2
|
|
191
|
-
}
|
|
192
|
-
return data
|
|
147
|
+
// --- Private helpers (ported from upstream Aes.java) ---
|
|
148
|
+
|
|
149
|
+
private fun shaX(data: String, algorithm: String): String {
|
|
150
|
+
val md = MessageDigest.getInstance(algorithm)
|
|
151
|
+
md.update(Hex.decode(data))
|
|
152
|
+
return bytesToHex(md.digest())
|
|
193
153
|
}
|
|
194
154
|
|
|
195
|
-
private fun
|
|
196
|
-
val
|
|
197
|
-
|
|
198
|
-
|
|
155
|
+
private fun pbkdf2Impl(pwd: String, salt: String, cost: Int, length: Int, algorithm: String): String {
|
|
156
|
+
val algorithmDigest: Digest = when {
|
|
157
|
+
algorithm.equals("sha1", ignoreCase = true) -> SHA1Digest()
|
|
158
|
+
algorithm.equals("sha256", ignoreCase = true) -> SHA256Digest()
|
|
159
|
+
algorithm.equals("sha512", ignoreCase = true) -> SHA512Digest()
|
|
160
|
+
else -> SHA512Digest()
|
|
199
161
|
}
|
|
200
|
-
|
|
162
|
+
val gen = PKCS5S2ParametersGenerator(algorithmDigest)
|
|
163
|
+
gen.init(Hex.decode(pwd), Hex.decode(salt), cost)
|
|
164
|
+
val key = (gen.generateDerivedParameters(length) as KeyParameter).key
|
|
165
|
+
return bytesToHex(key)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private fun hmacX(text: String, key: String, algorithm: String): String {
|
|
169
|
+
val contentData = Hex.decode(text)
|
|
170
|
+
val akHexData = Hex.decode(key)
|
|
171
|
+
val mac = Mac.getInstance(algorithm)
|
|
172
|
+
val secretKey = SecretKeySpec(akHexData, algorithm)
|
|
173
|
+
mac.init(secretKey)
|
|
174
|
+
return bytesToHex(mac.doFinal(contentData))
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private fun encryptImpl(text: String, hexKey: String, hexIv: String?, algorithm: String): String? {
|
|
178
|
+
if (text.isEmpty()) return null
|
|
179
|
+
|
|
180
|
+
val key = Hex.decode(hexKey)
|
|
181
|
+
val secretKey = SecretKeySpec(key, KEY_ALGORITHM)
|
|
182
|
+
val cipher = Cipher.getInstance(algorithm)
|
|
183
|
+
val ivSpec = if (hexIv == null || hexIv.isEmpty()) emptyIvSpec else IvParameterSpec(Hex.decode(hexIv))
|
|
184
|
+
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec)
|
|
185
|
+
val encrypted = cipher.doFinal(Hex.decode(text))
|
|
186
|
+
return bytesToHex(encrypted)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private fun decryptImpl(ciphertext: String, hexKey: String, hexIv: String?, algorithm: String): String? {
|
|
190
|
+
if (ciphertext.isEmpty()) return null
|
|
191
|
+
|
|
192
|
+
val key = Hex.decode(hexKey)
|
|
193
|
+
val secretKey = SecretKeySpec(key, KEY_ALGORITHM)
|
|
194
|
+
val cipher = Cipher.getInstance(algorithm)
|
|
195
|
+
val ivSpec = if (hexIv == null || hexIv.isEmpty()) emptyIvSpec else IvParameterSpec(Hex.decode(hexIv))
|
|
196
|
+
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec)
|
|
197
|
+
val decrypted = cipher.doFinal(Hex.decode(ciphertext))
|
|
198
|
+
return bytesToHex(decrypted)
|
|
201
199
|
}
|
|
202
200
|
}
|