diff --git a/android/app/src/main/java/com/eddy/atomrelay/BleRelayManager.kt b/android/app/src/main/java/com/eddy/atomrelay/BleRelayManager.kt index da70abf..a29569d 100644 --- a/android/app/src/main/java/com/eddy/atomrelay/BleRelayManager.kt +++ b/android/app/src/main/java/com/eddy/atomrelay/BleRelayManager.kt @@ -7,6 +7,10 @@ import android.content.Context import android.os.Handler import android.os.Looper import java.util.UUID +import java.nio.ByteBuffer +import java.nio.ByteOrder +import javax.crypto.Mac +import javax.crypto.spec.SecretKeySpec class BleRelayManager( private val context: Context, @@ -20,6 +24,8 @@ class BleRelayManager( private const val SCAN_TIMEOUT_MS = 30000L private const val RECONNECT_DELAY_MS = 2000L private const val MAX_SCAN_RETRIES = 3 + private const val HMAC_PKT_SIZE = 37 + private const val HMAC_LEN = 32 } private var bluetoothGatt: BluetoothGatt? = null @@ -37,9 +43,52 @@ class BleRelayManager( fun stopScan() {} fun sendRelayCommand(cmd: Byte) {} fun disconnect() {} - fun updateKeys() {} - fun resetTriedAddresses() {} + fun updateKeys() { + loadState() + } + + fun resetTriedAddresses() { + triedAddresses.clear() + } + fun hasPermissions(): Boolean = false fun getRequiredPermissions(): Array = emptyArray() - fun destroy() {} + + fun destroy() { + handler.removeCallbacksAndMessages(null) + } + + private fun loadState() { + val prefs = PrefsHelper.getPrefs(context) + val hexKey = prefs.getString(PrefsHelper.PREF_KEY, null) + hmacKey = hexKey?.let { hexStringToBytes(it) } + val hexUuid = prefs.getString(PrefsHelper.PREF_UUID, null) + deviceUuid = hexUuid?.let { hexStringToBytes(it) } + seq = prefs.getInt(PrefsHelper.PREF_SEQ, 1).coerceAtMost(PrefsHelper.SEQ_MAX) + } + + private fun hexStringToBytes(hex: String): ByteArray? { + val cleaned = hex.uppercase().filter { it in "0123456789ABCDEF" } + if (cleaned.isEmpty() || cleaned.length % 2 != 0) return null + return cleaned.chunked(2).map { it.toInt(16).toByte() }.toByteArray() + } + + private fun hmacSha256(data: ByteArray, key: ByteArray): ByteArray { + val mac = Mac.getInstance("HmacSHA256") + mac.init(SecretKeySpec(key, "HmacSHA256")) + return mac.doFinal(data) + } + + private fun buildPacket(cmd: Byte, key: ByteArray): ByteArray { + val seqBytes = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(seq).array() + val hmacData = ByteArray(5) + hmacData[0] = cmd + System.arraycopy(seqBytes, 0, hmacData, 1, 4) + val hmac = hmacSha256(hmacData, key) + val packet = ByteArray(HMAC_PKT_SIZE) + packet[0] = cmd + System.arraycopy(seqBytes, 0, packet, 1, 4) + System.arraycopy(hmac, 0, packet, 5, HMAC_LEN) + return packet + } }