From 5ac64a7f03f7743c7efbaaa504cd0aad28354388 Mon Sep 17 00:00:00 2001 From: Anushka Verma Date: Sat, 12 Oct 2024 10:51:04 +0530 Subject: [PATCH 1/3] implemented_encryption_with_hash_digest --- .idea/codeStyles/Project.xml | 123 ++++++++++++++++++ .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/deploymentTargetSelector.xml | 10 ++ .idea/gradle.xml | 6 +- .idea/kotlinc.xml | 2 +- .idea/migrations.xml | 10 ++ .idea/runConfigurations.xml | 13 ++ .../data/chat/BluetoothDataTransferService.kt | 95 +++++++++++--- 8 files changed, 240 insertions(+), 24 deletions(-) create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/deploymentTargetSelector.xml create mode 100644 .idea/migrations.xml create mode 100644 .idea/runConfigurations.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..7643783 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,123 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index ae388c2..7b3006b 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -4,16 +4,16 @@ diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 4515aa3..4251b72 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..931b96c --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/invincible/jedishare/data/chat/BluetoothDataTransferService.kt b/app/src/main/java/com/invincible/jedishare/data/chat/BluetoothDataTransferService.kt index 94dd59e..472da8d 100644 --- a/app/src/main/java/com/invincible/jedishare/data/chat/BluetoothDataTransferService.kt +++ b/app/src/main/java/com/invincible/jedishare/data/chat/BluetoothDataTransferService.kt @@ -14,6 +14,12 @@ import kotlinx.coroutines.withContext import java.io.ByteArrayOutputStream import java.io.IOException import java.nio.ByteBuffer +import javax.crypto.Cipher +import javax.crypto.spec.IvParameterSpec +import javax.crypto.spec.SecretKeySpec +import java.security.MessageDigest +import javax.crypto.KeyGenerator +import java.security.SecureRandom const val BUFFER_SIZE = 990 // Adjust the buffer size as needed const val FILE_DELIMITER = "----FILE_DELIMITER----" @@ -25,6 +31,24 @@ class BluetoothDataTransferService( private val incomingDataStream = ByteArrayOutputStream() + // Generate AES key and IV + private val secretKey: ByteArray = generateKey() + private val iv: ByteArray = generateIv() + + // Function to generate an AES key + private fun generateKey(): ByteArray { + val keyGen = KeyGenerator.getInstance("AES") + keyGen.init(256) + return keyGen.generateKey().encoded + } + + // Function to generate an IV + private fun generateIv(): ByteArray { + val iv = ByteArray(16) // AES block size is 16 bytes + SecureRandom().nextBytes(iv) + return iv + } + fun listenForIncomingMessages(viewModel: BluetoothViewModel): Flow { return flow { if (!socket.isConnected) { @@ -37,24 +61,19 @@ class BluetoothDataTransferService( } catch (e: IOException) { throw TransferFailedException() } - var bufferRed = buffer.copyOfRange(0, byteCount) + val bufferRed = buffer.copyOfRange(0, byteCount) Log.e("HELLOME", "Received: " + bufferRed.size.toString()) // processIncomingData(bufferRed) // checkForFiles(viewModel)?.let { fileBytes -> // emit(fileBytes) // } - Log.e("MYTAG", "Bytes Read : " + bufferRed.size) + // Decrypt the received data + val decryptedData = decryptData(bufferRed) + Log.e("MYTAG", "Bytes Read (Decrypted): " + decryptedData.size) - if(bufferRed.size == 880){ - viewModel?.isFirst = true - }else{ - emit(bufferRed) - } - -// emit( -// bufferRed -// ) + // Emit the decrypted data + emit(decryptedData) } }.flowOn(Dispatchers.IO) } @@ -65,7 +84,8 @@ class BluetoothDataTransferService( private fun checkForFiles(viewModel: BluetoothViewModel?): ByteArray? { val data = incomingDataStream.toByteArray() - val delimiterIndex = findIndexOfSubArray(incomingDataStream.toByteArray(), repeatedString.toByteArray()) + val delimiterIndex = + findIndexOfSubArray(incomingDataStream.toByteArray(), repeatedString.toByteArray()) // Log.e("MYTAG","delimiter size" + FILE_DELIMITER.toByteArray().size.toString()) @@ -94,7 +114,7 @@ class BluetoothDataTransferService( } fun findIndexOfSubArray(mainArray: ByteArray, subArray: ByteArray): Int { - if(mainArray.size == repeatedString.toByteArray().size) + if (mainArray.size == repeatedString.toByteArray().size) return 0 // for (i in 0 until mainArray.size - subArray.size + 1) { // if (mainArray.copyOfRange(i, i + subArray.size).contentEquals(subArray)) { @@ -106,15 +126,50 @@ class BluetoothDataTransferService( suspend fun sendMessage(bytes: ByteArray): Boolean { return withContext(Dispatchers.IO) { - try { - socket.outputStream.write(bytes) - Log.e("HELLOME", "Sent: " + bytes.size.toString()) + try { + val encryptedData = encryptData(bytes) + socket.outputStream.write(encryptedData) + Log.e("HELLOME", "Sent: " + bytes.size.toString()) - } catch (e: IOException) { + } catch (e: IOException) { return@withContext false - } + } - true + true } } -} + + // encrypts the provided data + private fun encryptData(data: ByteArray): ByteArray { + val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") + val secretKeySpec = SecretKeySpec(secretKey, "AES") + val iv = ByteArray(16) + SecureRandom().nextBytes(iv) + val ivParameterSpec = IvParameterSpec(iv) + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec) + return iv + cipher.doFinal(data) + } + + // decrypts the provided data + private fun decryptData(data: ByteArray): ByteArray { + val iv = data.copyOfRange(0, 16) + val actualData = data.copyOfRange(16, data.size) + val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") + val secretKeySpec = SecretKeySpec(secretKey, "AES") + val ivParameterSpec = IvParameterSpec(iv) + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec) + return cipher.doFinal(actualData) + } + + // generates a SHA-256 hash of the provided data + private fun generateHash(data: ByteArray): ByteArray { + val digest = MessageDigest.getInstance("SHA-256") + return digest.digest(data) + } + + // verifying hash of the provided data matches the expectedHash + private fun verifyHash(data: ByteArray, expectedHash: ByteArray): Boolean { + val hash = generateHash(data) + return hash.contentEquals(expectedHash) + } +} \ No newline at end of file From ba4938c529ba9bd4214f8c31b55a29ba69131119 Mon Sep 17 00:00:00 2001 From: Anushka Verma Date: Fri, 18 Oct 2024 06:20:13 +0530 Subject: [PATCH 2/3] modified-encrypt-hashDigest --- .../data/chat/BluetoothDataTransferService.kt | 144 +++++++++--------- .../invincible/jedishare/utils/CryptoUtils.kt | 36 +++++ .../invincible/jedishare/utils/KeyUtils.kt | 44 ++++++ 3 files changed, 151 insertions(+), 73 deletions(-) create mode 100644 app/src/main/java/com/invincible/jedishare/utils/CryptoUtils.kt create mode 100644 app/src/main/java/com/invincible/jedishare/utils/KeyUtils.kt diff --git a/app/src/main/java/com/invincible/jedishare/data/chat/BluetoothDataTransferService.kt b/app/src/main/java/com/invincible/jedishare/data/chat/BluetoothDataTransferService.kt index 472da8d..5a19acf 100644 --- a/app/src/main/java/com/invincible/jedishare/data/chat/BluetoothDataTransferService.kt +++ b/app/src/main/java/com/invincible/jedishare/data/chat/BluetoothDataTransferService.kt @@ -6,6 +6,8 @@ import com.invincible.jedishare.domain.chat.BluetoothMessage import com.invincible.jedishare.domain.chat.TransferFailedException import com.invincible.jedishare.presentation.BluetoothViewModel import com.invincible.jedishare.presentation.components.CustomProgressIndicator +import com.invincible.jedishare.utils.CryptoUtils +import com.invincible.jedishare.utils.KeyUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow @@ -14,39 +16,41 @@ import kotlinx.coroutines.withContext import java.io.ByteArrayOutputStream import java.io.IOException import java.nio.ByteBuffer -import javax.crypto.Cipher -import javax.crypto.spec.IvParameterSpec -import javax.crypto.spec.SecretKeySpec -import java.security.MessageDigest -import javax.crypto.KeyGenerator -import java.security.SecureRandom +import javax.crypto.SecretKey +import java.security.KeyPair +import java.security.PublicKey const val BUFFER_SIZE = 990 // Adjust the buffer size as needed const val FILE_DELIMITER = "----FILE_DELIMITER----" val repeatedString = FILE_DELIMITER.repeat(40) class BluetoothDataTransferService( - private val socket: BluetoothSocket + private val socket: BluetoothSocket, + private var aesKey: SecretKey? = null ) { private val incomingDataStream = ByteArrayOutputStream() - // Generate AES key and IV - private val secretKey: ByteArray = generateKey() - private val iv: ByteArray = generateIv() - - // Function to generate an AES key - private fun generateKey(): ByteArray { - val keyGen = KeyGenerator.getInstance("AES") - keyGen.init(256) - return keyGen.generateKey().encoded + // Start the Diffie-Hellman Key Exchange + fun startKeyExchange(): ByteArray { + val keyPair: KeyPair = KeyUtils.generateDHKeyPair() + val publicKeyBytes = KeyUtils.serializePublicKey(keyPair.public) + // Send the public key bytes to the other device + // Store the private key for computing the shared secret later + dhPrivateKey = keyPair.private + return publicKeyBytes } - // Function to generate an IV - private fun generateIv(): ByteArray { - val iv = ByteArray(16) // AES block size is 16 bytes - SecureRandom().nextBytes(iv) - return iv + // Complete the Key Exchange and generate the AES key + fun completeKeyExchange(otherPublicKeyBytes: ByteArray) { + if (dhPrivateKey == null) { + Log.e("BluetoothDataTransfer", "Private key is null. Key exchange failed!") + throw IllegalStateException("Key exchange must be completed before data transfer.") + } + + val otherPublicKey: PublicKey = KeyUtils.deserializePublicKey(otherPublicKeyBytes) + val sharedSecret: ByteArray = KeyUtils.generateSharedSecret(dhPrivateKey!!, otherPublicKey) + aesKey = KeyUtils.generateAESKeyFromSharedSecret(sharedSecret) } fun listenForIncomingMessages(viewModel: BluetoothViewModel): Flow { @@ -61,19 +65,36 @@ class BluetoothDataTransferService( } catch (e: IOException) { throw TransferFailedException() } - val bufferRed = buffer.copyOfRange(0, byteCount) - Log.e("HELLOME", "Received: " + bufferRed.size.toString()) - -// processIncomingData(bufferRed) -// checkForFiles(viewModel)?.let { fileBytes -> -// emit(fileBytes) -// } - // Decrypt the received data - val decryptedData = decryptData(bufferRed) - Log.e("MYTAG", "Bytes Read (Decrypted): " + decryptedData.size) - - // Emit the decrypted data - emit(decryptedData) + val encryptedChunk = buffer.copyOfRange(0, byteCount) + + // Read the hash digest (for integrity check) + val hashBuffer = ByteArray(32) // SHA-256 produces a 32-byte hash + socket.inputStream.read(hashBuffer) + val receivedHash = hashBuffer.copyOfRange(0, hashBuffer.size) + + // Verify the hash to ensure data integrity + val computedHash = CryptoUtils.generateSHA256Hash(encryptedChunk) + if (!computedHash.contentEquals(receivedHash)) { + throw TransferFailedException() + } + + // Ensure AES key is ready before decrypting + if (aesKey == null) { + throw TransferFailedException() + } + + // Decrypt the chunk using AES + val decryptedData = CryptoUtils.decrypt(encryptedChunk, aesKey!!) + + Log.e("BluetoothDataTransfer", "Received and decrypted: ${decryptedData.size} bytes") + + processIncomingData(decryptedData) + + if (decryptedData.size == 880) { + viewModel?.isFirst = true + } else { + emit(decryptedData) + } } }.flowOn(Dispatchers.IO) } @@ -84,8 +105,7 @@ class BluetoothDataTransferService( private fun checkForFiles(viewModel: BluetoothViewModel?): ByteArray? { val data = incomingDataStream.toByteArray() - val delimiterIndex = - findIndexOfSubArray(incomingDataStream.toByteArray(), repeatedString.toByteArray()) + val delimiterIndex = findIndexOfSubArray(incomingDataStream.toByteArray(), repeatedString.toByteArray()) // Log.e("MYTAG","delimiter size" + FILE_DELIMITER.toByteArray().size.toString()) @@ -114,7 +134,7 @@ class BluetoothDataTransferService( } fun findIndexOfSubArray(mainArray: ByteArray, subArray: ByteArray): Int { - if (mainArray.size == repeatedString.toByteArray().size) + if(mainArray.size == repeatedString.toByteArray().size) return 0 // for (i in 0 until mainArray.size - subArray.size + 1) { // if (mainArray.copyOfRange(i, i + subArray.size).contentEquals(subArray)) { @@ -127,9 +147,20 @@ class BluetoothDataTransferService( suspend fun sendMessage(bytes: ByteArray): Boolean { return withContext(Dispatchers.IO) { try { - val encryptedData = encryptData(bytes) + // Encrypt the data chunk using AES + val encryptedData = CryptoUtils.encrypt(bytes, aesKey!!) + + // Generate SHA-256 hash for integrity check + val hashDigest = CryptoUtils.generateSHA256Hash(encryptedData) + + // Send the encrypted chunk socket.outputStream.write(encryptedData) - Log.e("HELLOME", "Sent: " + bytes.size.toString()) + + // Send the hash digest for integrity verification + socket.outputStream.write(hashDigest) + + Log.e("HELLOME", "Sent encrypted data: ${encryptedData.size} bytes") + Log.e("HELLOME", "Sent hash digest: ${hashDigest.size} bytes") } catch (e: IOException) { return@withContext false @@ -138,38 +169,5 @@ class BluetoothDataTransferService( true } } - - // encrypts the provided data - private fun encryptData(data: ByteArray): ByteArray { - val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") - val secretKeySpec = SecretKeySpec(secretKey, "AES") - val iv = ByteArray(16) - SecureRandom().nextBytes(iv) - val ivParameterSpec = IvParameterSpec(iv) - cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec) - return iv + cipher.doFinal(data) - } - - // decrypts the provided data - private fun decryptData(data: ByteArray): ByteArray { - val iv = data.copyOfRange(0, 16) - val actualData = data.copyOfRange(16, data.size) - val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") - val secretKeySpec = SecretKeySpec(secretKey, "AES") - val ivParameterSpec = IvParameterSpec(iv) - cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec) - return cipher.doFinal(actualData) - } - - // generates a SHA-256 hash of the provided data - private fun generateHash(data: ByteArray): ByteArray { - val digest = MessageDigest.getInstance("SHA-256") - return digest.digest(data) - } - - // verifying hash of the provided data matches the expectedHash - private fun verifyHash(data: ByteArray, expectedHash: ByteArray): Boolean { - val hash = generateHash(data) - return hash.contentEquals(expectedHash) - } + private var dhPrivateKey: java.security.PrivateKey? = null } \ No newline at end of file diff --git a/app/src/main/java/com/invincible/jedishare/utils/CryptoUtils.kt b/app/src/main/java/com/invincible/jedishare/utils/CryptoUtils.kt new file mode 100644 index 0000000..674f870 --- /dev/null +++ b/app/src/main/java/com/invincible/jedishare/utils/CryptoUtils.kt @@ -0,0 +1,36 @@ +package com.invincible.jedishare.utils + +import javax.crypto.Cipher +import javax.crypto.SecretKey +import javax.crypto.spec.SecretKeySpec +import java.security.MessageDigest + +object CryptoUtils { + private const val AES_TRANSFORMATION = "AES/ECB/PKCS5Padding" + private const val AES_ALGORITHM = "AES" + + // Encrypt data using AES + fun encrypt(data: ByteArray, key: SecretKey): ByteArray { + val cipher = Cipher.getInstance(AES_TRANSFORMATION) + cipher.init(Cipher.ENCRYPT_MODE, key) + return cipher.doFinal(data) + } + + // Decrypt data using AES + fun decrypt(data: ByteArray, key: SecretKey): ByteArray { + val cipher = Cipher.getInstance(AES_TRANSFORMATION) + cipher.init(Cipher.DECRYPT_MODE, key) + return cipher.doFinal(data) + } + + // Generate SHA-256 hash for integrity check + fun generateSHA256Hash(data: ByteArray): ByteArray { + val digest = MessageDigest.getInstance("SHA-256") + return digest.digest(data) + } + + // Generate a SecretKey from a byte array (used for generating AES key) + fun generateSecretKey(keyBytes: ByteArray): SecretKey { + return SecretKeySpec(keyBytes, AES_ALGORITHM) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/invincible/jedishare/utils/KeyUtils.kt b/app/src/main/java/com/invincible/jedishare/utils/KeyUtils.kt new file mode 100644 index 0000000..80125b9 --- /dev/null +++ b/app/src/main/java/com/invincible/jedishare/utils/KeyUtils.kt @@ -0,0 +1,44 @@ +package com.invincible.jedishare.utils + +import java.security.KeyPair +import java.security.KeyPairGenerator +import java.security.PublicKey +import java.security.spec.X509EncodedKeySpec +import javax.crypto.KeyAgreement +import javax.crypto.SecretKey +import javax.crypto.spec.SecretKeySpec + +object KeyUtils { + // Generate Diffie-Hellman Key Pair + fun generateDHKeyPair(): KeyPair { + val keyPairGenerator = KeyPairGenerator.getInstance("DH") + keyPairGenerator.initialize(2048) // Strong 2048-bit key + return keyPairGenerator.generateKeyPair() + } + + // Serialize public key to send over the network + fun serializePublicKey(publicKey: PublicKey): ByteArray { + return publicKey.encoded + } + + // Deserialize public key received from the other device + fun deserializePublicKey(publicKeyBytes: ByteArray): PublicKey { + val keyFactory = java.security.KeyFactory.getInstance("DH") + val spec = X509EncodedKeySpec(publicKeyBytes) + return keyFactory.generatePublic(spec) + } + + // Generate shared secret using Diffie-Hellman + fun generateSharedSecret(ownPrivateKey: java.security.PrivateKey, otherPublicKey: PublicKey): ByteArray { + val keyAgreement = KeyAgreement.getInstance("DH") + keyAgreement.init(ownPrivateKey) + keyAgreement.doPhase(otherPublicKey, true) + return keyAgreement.generateSecret() + } + + // Generate AES key from shared secret + fun generateAESKeyFromSharedSecret(sharedSecret: ByteArray): SecretKey { + // Use the first 16 bytes of the shared secret for AES-128 + return SecretKeySpec(sharedSecret.copyOf(16), "AES") + } +} \ No newline at end of file From d13ddf0e79bbfd7b204aad1e21a09c725505320a Mon Sep 17 00:00:00 2001 From: Anushka Verma Date: Thu, 24 Oct 2024 19:36:06 +0530 Subject: [PATCH 3/3] Added encryption and integrity check feature --- .../data/chat/BluetoothDataTransferService.kt | 63 +++++++++---------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/invincible/jedishare/data/chat/BluetoothDataTransferService.kt b/app/src/main/java/com/invincible/jedishare/data/chat/BluetoothDataTransferService.kt index 5a19acf..d070e40 100644 --- a/app/src/main/java/com/invincible/jedishare/data/chat/BluetoothDataTransferService.kt +++ b/app/src/main/java/com/invincible/jedishare/data/chat/BluetoothDataTransferService.kt @@ -68,7 +68,7 @@ class BluetoothDataTransferService( val encryptedChunk = buffer.copyOfRange(0, byteCount) // Read the hash digest (for integrity check) - val hashBuffer = ByteArray(32) // SHA-256 produces a 32-byte hash + val hashBuffer = ByteArray(32) socket.inputStream.read(hashBuffer) val receivedHash = hashBuffer.copyOfRange(0, hashBuffer.size) @@ -103,50 +103,49 @@ class BluetoothDataTransferService( incomingDataStream.write(data) } + private fun checkForFiles(viewModel: BluetoothViewModel?): ByteArray? { val data = incomingDataStream.toByteArray() - val delimiterIndex = findIndexOfSubArray(incomingDataStream.toByteArray(), repeatedString.toByteArray()) - - -// Log.e("MYTAG","delimiter size" + FILE_DELIMITER.toByteArray().size.toString()) -// Log.e("MYTAG","byte array size" + data.size) - -// val delimiterIndex = data.indexOf(FILE_DELIMITER.toByteArray()) - if (delimiterIndex == 0) { -// val fileBytes = data.copyOfRange(0, delimiterIndex) -// incomingDataStream.reset() -// Log.e("MYTAG","END OF FILE" + delimiterIndex) -// Log.e("MYTAG","main array size" + incomingDataStream.toByteArray().size.toString()) -// Log.e("MYTAG","delimiter size" + repeatedString.toByteArray().size.toString()) + val delimiterIndex = findIndexOfSubArray(data, repeatedString.toByteArray()) + + if (delimiterIndex >= 0) { + // File boundary found, extract the file data + val fileBytes = data.copyOfRange(0, delimiterIndex) + incomingDataStream.reset() // Reset the stream after processing the file + // Write the remaining bytes back into the stream (after the delimiter) + if (delimiterIndex + repeatedString.toByteArray().size < data.size) { + incomingDataStream.write( + data, + delimiterIndex + repeatedString.toByteArray().size, + data.size - (delimiterIndex + repeatedString.toByteArray().size) + ) + } viewModel?.isFirst = true -// incomingDataStream.write(data, delimiterIndex + FILE_DELIMITER.length, data.size - (delimiterIndex + FILE_DELIMITER.length)) -// return fileBytes - incomingDataStream.reset() - return null -// return incomingDataStream.toByteArray() + return fileBytes } -// else if(viewModel?.isFirst == true && data.size == 990){ -// incomingDataStream.reset() -// return null -// } + incomingDataStream.reset() - return data + return null } fun findIndexOfSubArray(mainArray: ByteArray, subArray: ByteArray): Int { - if(mainArray.size == repeatedString.toByteArray().size) - return 0 -// for (i in 0 until mainArray.size - subArray.size + 1) { -// if (mainArray.copyOfRange(i, i + subArray.size).contentEquals(subArray)) { -// return i -// } -// } - return -1 // Return -1 if subArray is not found in mainArray + // Properly find the delimiter in the incoming data + for (i in 0 until mainArray.size - subArray.size + 1) { + if (mainArray.copyOfRange(i, i + subArray.size).contentEquals(subArray)) { + return i + } + } + return -1 // Return -1 if subArray is not found } suspend fun sendMessage(bytes: ByteArray): Boolean { return withContext(Dispatchers.IO) { try { + // Ensure AES key is ready before encrypting + if (aesKey == null) { + throw IllegalStateException("AES key not initialized!") + } + // Encrypt the data chunk using AES val encryptedData = CryptoUtils.encrypt(bytes, aesKey!!)