Skip to content

Commit c22cbd7

Browse files
committed
new feature added
1 parent ac0101e commit c22cbd7

File tree

15 files changed

+1251
-189
lines changed

15 files changed

+1251
-189
lines changed

README.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ import {
8686
encryptAsyncAES,
8787
decryptAsyncAES,
8888
encryptAsyncRSA,
89-
decryptAsyncRSA
89+
decryptAsyncRSA,
90+
encryptFile,
91+
decryptFile,
9092
} from 'rn-encryption';;
9193
```
9294

@@ -291,8 +293,12 @@ const decryptedPath = `${RNFS.DocumentDirectoryPath}/data-decrypted.txt`;
291293
const hmac = () => {
292294
try {
293295
console.log('--- HMAC ---');
294-
const hmachash = hmacSHA256('Hello HMAC', 'MyHMACKey');
295-
console.log('HMAC-SHA256:', hmachash);
296+
const hmackey = generateHMACKey(256);
297+
const hmachash = hmacSHA256('Hello HMAC', hmackey);
298+
299+
const hmackey512 = generateHMACKey(512);
300+
const hmachash512 = hmacSHA256('Hello HMAC', hmackey512);
301+
console.log('HMAC-SHA256:', hmachash, hmachash512);
296302
} catch (err) {
297303
console.log('error is', err);
298304
}
@@ -431,6 +437,9 @@ const styles = StyleSheet.create({
431437

432438
```
433439

440+
# ** Keychain Integration for keys**
441+
- It is recommended to save keys in Keychain only. You can refer example in this repo. This is anb sample and can be modified according to the requirements.
442+
434443
---
435444

436445
## 🐞 **7. Troubleshooting**

android/src/main/java/com/encryption/EncryptionModule.kt

Lines changed: 101 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ import javax.crypto.spec.IvParameterSpec
99
import java.security.*
1010
import java.security.spec.PKCS8EncodedKeySpec
1111
import java.security.spec.X509EncodedKeySpec
12+
import java.security.spec.RSAPublicKeySpec
13+
1214
import android.util.Base64
1315
import javax.crypto.Cipher
16+
import java.math.BigInteger
1417

1518
import java.security.KeyFactory
1619
import kotlinx.coroutines.*
@@ -211,7 +214,7 @@ override fun decryptFile(inputPath: String, key: String, promise: Promise) {
211214
}
212215

213216
// -----------------------------------------
214-
// 🔑 AES Key Generation
217+
// 🔑 RSA Key Generation
215218
// -----------------------------------------
216219

217220
/**
@@ -221,33 +224,73 @@ override fun decryptFile(inputPath: String, key: String, promise: Promise) {
221224
* @throws Exception if key generation fails.
222225
*/
223226
@Throws(Exception::class)
224-
override fun generateRSAKeyPair(): WritableMap {
225-
return try {
226-
// Generate RSA Key Pair
227-
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
228-
keyPairGenerator.initialize(2048)
229-
val keyPair = keyPairGenerator.genKeyPair()
230-
231-
// Get keys and encode them as Base64
232-
val publicKey = keyPair.public.encoded
233-
val privateKey = keyPair.private.encoded
234-
235-
val publicKeyBase64 = Base64.encodeToString(publicKey, Base64.DEFAULT)
236-
val privateKeyBase64 = Base64.encodeToString(privateKey, Base64.DEFAULT)
237-
238-
// Create WritableMap
239-
val result: WritableMap = Arguments.createMap()
240-
result.putString("publicKey", publicKeyBase64)
241-
result.putString("privateKey", privateKeyBase64)
227+
override fun generateRSAKeyPair(): WritableMap {
228+
try {
229+
// Generate RSA Key Pair
230+
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
231+
keyPairGenerator.initialize(2048)
232+
val keyPair: KeyPair = keyPairGenerator.genKeyPair()
233+
234+
// Extract Public and Private Key
235+
val publicKey = keyPair.public
236+
val privateKey = keyPair.private
237+
238+
// Encode Keys to Base64
239+
val publicKeyBytes = publicKey.encoded
240+
val privateKeyBytes = privateKey.encoded
241+
242+
val publicKeyBase64 = Base64.encodeToString(publicKeyBytes, Base64.DEFAULT)
243+
val privateKeyBase64 = Base64.encodeToString(privateKeyBytes, Base64.DEFAULT)
244+
245+
// Return as WritableMap
246+
val result: WritableMap = Arguments.createMap()
247+
result.putString("publicKey", publicKeyBase64)
248+
result.putString("privateKey", privateKeyBase64)
249+
250+
return result
251+
} catch (e: Exception) {
252+
e.printStackTrace()
253+
throw Exception("Failed to generate RSA key pair: ${e.localizedMessage}")
254+
}
255+
}
242256

243-
result
244-
} catch (e: Exception) {
245-
e.printStackTrace()
246-
val errorMap: WritableMap = Arguments.createMap()
247-
errorMap.putString("error", "Failed to generate RSA key pair: ${e.localizedMessage}")
248-
errorMap
249-
}
250-
}
257+
/**
258+
* Retrieve the Public Key from a given Private Key (Base64 Encoded)
259+
* @param privateKeyBase64 Base64-encoded RSA private key.
260+
* @return Base64-encoded RSA public key or null on failure.
261+
* @throws IllegalArgumentException if the key is invalid.
262+
* @throws Exception for general key-related errors.
263+
*/
264+
@Throws(IllegalArgumentException::class, Exception::class)
265+
override fun getPublicRSAkey(privateKeyBase64: String): String {
266+
try {
267+
// Decode the Base64-encoded private key
268+
val privateKeyBytes = Base64.decode(privateKeyBase64, Base64.DEFAULT)
269+
val keySpec = PKCS8EncodedKeySpec(privateKeyBytes)
270+
val keyFactory = KeyFactory.getInstance("RSA")
271+
272+
// Generate PrivateKey object
273+
val privateKey: PrivateKey = keyFactory.generatePrivate(keySpec)
274+
val rsaPrivateKey = privateKey as java.security.interfaces.RSAPrivateKey
275+
276+
// Extract Modulus and Public Exponent
277+
val modulus: BigInteger = rsaPrivateKey.modulus
278+
val publicExponent: BigInteger = BigInteger.valueOf(65537) // Common RSA exponent
279+
280+
// Generate PublicKey from Modulus and Public Exponent
281+
val publicKeySpec = RSAPublicKeySpec(modulus, publicExponent)
282+
val publicKey: PublicKey = keyFactory.generatePublic(publicKeySpec)
283+
284+
// Encode PublicKey to Base64
285+
val publicKeyBase64 = Base64.encodeToString(publicKey.encoded, Base64.DEFAULT)
286+
return publicKeyBase64
287+
288+
} catch (e: IllegalArgumentException) {
289+
throw IllegalArgumentException("Invalid private key format: ${e.localizedMessage}")
290+
} catch (e: Exception) {
291+
throw Exception("Failed to extract public key: ${e.localizedMessage}")
292+
}
293+
}
251294

252295
// -----------------------------------------
253296
// 🔒 RSA Encryption
@@ -394,9 +437,19 @@ override fun decryptFile(inputPath: String, key: String, promise: Promise) {
394437
}
395438

396439
// -----------------------------------------
397-
// 📝 HMAC-SHA256
440+
// 📝 HMAC-SHA256/512
398441
// -----------------------------------------
399442

443+
/**
444+
* Generate HMAC Key for SHA-256 or SHA-512.
445+
* @param keySize Size of the key in bits (256 or 512).
446+
* @return Base64-encoded HMAC key.
447+
* @throws IllegalArgumentException If the key size is invalid.
448+
*/
449+
@Throws(IllegalArgumentException::class)
450+
override fun generateHMACKey(keySize: Double): String {
451+
return HashingUtils.generateHMACKey(keySize)
452+
}
400453
/**
401454
* Hashes data using hmac SHA-256.
402455
*
@@ -410,6 +463,20 @@ override fun decryptFile(inputPath: String, key: String, promise: Promise) {
410463
return HashingUtils.hmacSHA256(data, key)
411464
}
412465

466+
/**
467+
* Hashes data using hmac SHA-512.
468+
*
469+
* @param data The input string to hash.
470+
* @param key The input key to be used for hash.
471+
* @return A hex-encoded hmac SHA-256 hash.
472+
* @throws Exception if hashing fails.
473+
*/
474+
@Throws(Exception::class)
475+
override fun hmacSHA512(data: String, key: String): String {
476+
return HashingUtils.hmacSHA512(data, key)
477+
}
478+
479+
413480
// -----------------------------------------
414481
// 🎲 Random String Generation
415482
// -----------------------------------------
@@ -465,6 +532,12 @@ override fun decryptFile(inputPath: String, key: String, promise: Promise) {
465532
return SignatureUtils.generateECDSAKeyPair()
466533
}
467534

535+
@Throws(Exception::class)
536+
override fun getPublicECDSAKey(privateKeyBase64: String): String {
537+
return SignatureUtils.getPublicECDSAKey(privateKeyBase64)
538+
}
539+
540+
468541
/**
469542
* Signs a given string using ECDSA (Elliptic Curve Digital Signature Algorithm).
470543
*

android/src/main/java/com/encryption/HashingUtils.kt

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import android.util.Base64
33
import kotlin.math.roundToInt
44
import java.security.*
55
import javax.crypto.spec.SecretKeySpec
6+
import javax.crypto.KeyGenerator
7+
import javax.crypto.SecretKey
68

79

810
object HashingUtils {
@@ -51,9 +53,33 @@ object HashingUtils {
5153
}
5254

5355
// -----------------------------------------
54-
// 📝 HMAC-SHA256
56+
// 📝 HMAC-SHA256/512
5557
// -----------------------------------------
5658

59+
/**
60+
* Generate HMAC Key for SHA-256 or SHA-512.
61+
* @param keySize Size of the key in bits (256 or 512).
62+
* @return Base64-encoded HMAC key.
63+
* @throws IllegalArgumentException If the key size is invalid.
64+
*/
65+
@Throws(IllegalArgumentException::class)
66+
fun generateHMACKey(keySize: Double): String {
67+
// Validate key size
68+
// val validSizes = listOf(256, 512)
69+
// if (keySize !in validSizes) {
70+
// throw IllegalArgumentException("Invalid key size. Supported sizes: 256.0, 512.0 bits")
71+
// }
72+
73+
// Convert Double to Int for byte array size
74+
val keyBytes = ByteArray((keySize / 8).toInt()) // Convert bits to bytes
75+
76+
// Generate random key bytes
77+
SecureRandom().nextBytes(keyBytes)
78+
79+
// Encode the key as Base64 for storage/transfer
80+
return Base64.encodeToString(keyBytes, Base64.DEFAULT)
81+
}
82+
5783
/**
5884
* Hashes data using hmac SHA-256.
5985
*
@@ -73,6 +99,25 @@ object HashingUtils {
7399
}
74100
}
75101

102+
/**
103+
* Hashes data using hmac SHA-256.
104+
*
105+
* @param data The input string to hash.
106+
* @param key The input key to be used for hash.
107+
* @return A hex-encoded hmac SHA-256 hash.
108+
* @throws Exception if hashing fails.
109+
*/
110+
@Throws(Exception::class)
111+
fun hmacSHA512(data: String, key: String): String {
112+
val secretKey = SecretKeySpec(key.toByteArray(), "HmacSHA512")
113+
val mac = Mac.getInstance("HmacSHA512")
114+
mac.init(secretKey)
115+
val hash = mac.doFinal(data.toByteArray())
116+
return hash.joinToString("") {
117+
"%02x".format(it)
118+
}
119+
}
120+
76121
// -----------------------------------------
77122
// 🎲 Random String Generation
78123
// -----------------------------------------

0 commit comments

Comments
 (0)