@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.
@@ -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
- Thread {
37
- try {
38
- val keyBytes = hexToBytes(key)
39
- val ivBytes = hexToBytes(iv)
40
- val transformation = cipherTransformation(algorithm)
41
- val cipher = Cipher.getInstance(transformation)
42
- val secretKey = SecretKeySpec(keyBytes, "AES")
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
- Thread {
58
- try {
59
- val keyBytes = hexToBytes(key)
60
- val ivBytes = hexToBytes(iv)
61
- val transformation = cipherTransformation(algorithm)
62
- val cipher = Cipher.getInstance(transformation)
63
- val secretKey = SecretKeySpec(keyBytes, "AES")
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
- Thread {
79
- try {
80
- val saltBytes = salt.toByteArray(Charsets.UTF_8)
81
- val iterationCount = cost.toInt()
82
- val keyLength = length.toInt() * 8
83
- val hmacAlgorithm = when (algorithm.uppercase()) {
84
- "SHA256", "SHA-256" -> "PBKDF2WithHmacSHA256"
85
- "SHA512", "SHA-512" -> "PBKDF2WithHmacSHA512"
86
- else -> "PBKDF2WithHmacSHA1"
87
- }
88
- val spec = PBEKeySpec(password.toCharArray(), saltBytes, iterationCount, keyLength)
89
- val factory = SecretKeyFactory.getInstance(hmacAlgorithm)
90
- val keyBytes = factory.generateSecret(spec).encoded
91
- promise.resolve(bytesToHex(keyBytes))
92
- } catch (e: Exception) {
93
- promise.reject("AES_CRYPTO_ERROR", e.message, e)
94
- }
95
- }.start()
96
- }
97
-
98
- override fun hmac256(base64: String, key: String, promise: Promise) {
99
- Thread {
100
- try {
101
- val mac = Mac.getInstance("HmacSHA256")
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
- Thread {
128
- try {
129
- val digest = MessageDigest.getInstance("SHA-1")
130
- val result = digest.digest(text.toByteArray(Charsets.UTF_8))
131
- promise.resolve(bytesToHex(result))
132
- } catch (e: Exception) {
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
- Thread {
140
- try {
141
- val digest = MessageDigest.getInstance("SHA-256")
142
- val result = digest.digest(text.toByteArray(Charsets.UTF_8))
143
- promise.resolve(bytesToHex(result))
144
- } catch (e: Exception) {
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
- Thread {
152
- try {
153
- val digest = MessageDigest.getInstance("SHA-512")
154
- val result = digest.digest(text.toByteArray(Charsets.UTF_8))
155
- promise.resolve(bytesToHex(result))
156
- } catch (e: Exception) {
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
- Thread {
164
- try {
165
- promise.resolve(UUID.randomUUID().toString())
166
- } catch (e: Exception) {
167
- promise.reject("AES_CRYPTO_ERROR", e.message, e)
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
- Thread {
174
- try {
175
- val bytes = ByteArray(length.toInt())
176
- SecureRandom().nextBytes(bytes)
177
- promise.resolve(bytesToHex(bytes))
178
- } catch (e: Exception) {
179
- promise.reject("AES_CRYPTO_ERROR", e.message, e)
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
- private fun hexToBytes(hex: String): ByteArray {
185
- val len = hex.length
186
- val data = ByteArray(len / 2)
187
- var i = 0
188
- while (i < len) {
189
- data[i / 2] = ((Character.digit(hex[i], 16) shl 4) + Character.digit(hex[i + 1], 16)).toByte()
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 bytesToHex(bytes: ByteArray): String {
196
- val sb = StringBuilder()
197
- for (b in bytes) {
198
- sb.append(String.format("%02x", b))
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
- return sb.toString()
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-aes-crypto",
3
- "version": "3.0.7",
3
+ "version": "3.0.9",
4
4
  "description": "react-native-aes-crypto",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",