From 81ad52ebce8d037c08d17af925c7bc2da4d452be Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Fri, 26 Feb 2021 23:56:39 +0100 Subject: [PATCH] implement SPS1 command I had to add a new dependency: `tink-android:1.5.0` for X25519 --- core/core_dependencies.gradle | 1 + omnipod-dash/build.gradle | 5 +-- .../driver/comm/OmnipodDashBleManagerImpl.kt | 2 + .../dash/driver/comm/command/BleCommand.kt | 6 +++ .../dash/driver/comm/ltk/LTKExchanger.kt | 44 ++++++++++++++----- .../dash/driver/comm/message/MessageIO.kt | 4 +- .../driver/comm/message/PayloadSplitter.kt | 4 +- .../dash/driver/comm/packet/BlePacket.kt | 8 +++- .../driver/comm/scan/BleDiscoveredDevice.kt | 1 - 9 files changed, 56 insertions(+), 19 deletions(-) diff --git a/core/core_dependencies.gradle b/core/core_dependencies.gradle index 552aa32c15..25ecf5b36c 100644 --- a/core/core_dependencies.gradle +++ b/core/core_dependencies.gradle @@ -47,6 +47,7 @@ dependencies { //CryptoUtil api 'com.madgag.spongycastle:core:1.58.0.0' + // Graphview cannot be upgraded api "com.jjoe64:graphview:4.0.1" diff --git a/omnipod-dash/build.gradle b/omnipod-dash/build.gradle index 45c11a93bf..34ca4406c5 100644 --- a/omnipod-dash/build.gradle +++ b/omnipod-dash/build.gradle @@ -21,7 +21,6 @@ dependencies { implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-rxjava2:$room_version" kapt "androidx.room:room-compiler:$room_version" - implementation 'com.github.guepardoapps:kulid:1.1.2.0' - -} \ No newline at end of file + implementation 'com.google.crypto.tink:tink-android:1.5.0' +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt index 3dda0461dc..d08d9c50c9 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt @@ -5,6 +5,7 @@ import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothManager import android.bluetooth.BluetoothProfile import android.content.Context +import com.google.crypto.tink.subtle.X25519 import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.pump.omnipod.dash.BuildConfig @@ -24,6 +25,7 @@ import org.apache.commons.lang3.NotImplementedException import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingDeque import java.util.concurrent.TimeoutException +import javax.crypto.KeyAgreement import javax.inject.Inject import javax.inject.Singleton diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt index a51e738df4..186585676c 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt @@ -1,5 +1,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command +import info.nightscout.androidaps.utils.extensions.toHex + open class BleCommand(val data: ByteArray) { constructor(type: BleCommandType) : this(byteArrayOf(type.value)) @@ -17,6 +19,10 @@ open class BleCommand(val data: ByteArray) { return true } + override fun toString(): String { + return "Raw command: [${data.toHex()}]"; + } + override fun hashCode(): Int { return data.contentHashCode() } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ltk/LTKExchanger.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ltk/LTKExchanger.kt index 666c7c0538..235b6f2261 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ltk/LTKExchanger.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ltk/LTKExchanger.kt @@ -1,31 +1,41 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.ltk +import com.google.crypto.tink.subtle.X25519 import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManagerImpl import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageIO import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.StringLengthPrefixEncoding import info.nightscout.androidaps.utils.extensions.hexStringToByteArray +import java.security.SecureRandom internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgIO: MessageIO) { + private val privateKey = X25519.generatePrivateKey() + private val nonce = ByteArray(16) + private val controllerId = Id.fromInt(OmnipodDashBleManagerImpl.CONTROLLER_ID) + val nodeId = controllerId.increment() + private var seq: Byte = 1 + + init{ + val random = SecureRandom() + random.nextBytes(nonce) + } fun negotiateLTKAndNonce(): LTK? { // send SP1, SP2 - // TODO: get this from somewhere(preferences?) - var seq: Byte = 1 - val controllerId = Id.fromInt(OmnipodDashBleManagerImpl.CONTROLLER_ID) - val nodeId = controllerId.increment() - - var sp1sp2 = sp1sp2(nodeId.address, sp2(), seq, controllerId, nodeId) + var sp1sp2 = sp1sp2(nodeId.address, sp2()) msgIO.sendMesssage(sp1sp2.messagePacket) -/* - var sps1 = + seq++ + var sps1 = sps1() msgIO.sendMesssage(sps1.messagePacket) // send SPS1 + // read SPS1 val podSps1 = msgIO.receiveMessage() - + aapsLogger.info(LTag.PUMPBTCOMM, "Received message: %s", podSps1) +/* // send SPS2 var sps2 = PairMessage() msgIO.sendMesssage(sps2.messagePacket) @@ -46,7 +56,7 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI return GET_POD_STATUS_HEX_COMMAND.hexStringToByteArray() } - fun sp1sp2(sp1: ByteArray, sp2: ByteArray, seq: Byte, controllerId: Id, nodeId: Id): PairMessage { + fun sp1sp2(sp1: ByteArray, sp2: ByteArray): PairMessage { val payload = StringLengthPrefixEncoding.formatKeys( arrayOf("SP1=", ",SP2="), arrayOf(sp1, sp2), @@ -59,6 +69,20 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI ) } + fun sps1(): PairMessage { + val publicKey = X25519.publicFromPrivate(privateKey) + val payload = StringLengthPrefixEncoding.formatKeys( + arrayOf("SPS1="), + arrayOf(publicKey+nonce), + ) + return PairMessage( + sequenceNumber = seq, + source = controllerId, + destination = nodeId, + payload = payload, + ) + } + companion object { private val GET_POD_STATUS_HEX_COMMAND = "ffc32dbd08030e0100008a" // TODO for now we are assuming this command is build out of constant parameters, use a proper command builder for that. diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt index 7f742a4aca..0f04d55c0c 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt @@ -38,7 +38,7 @@ class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) { fun receiveMessage(): MessagePacket { val expectRTS = bleIO.receivePacket(CharacteristicType.CMD) - if (BleCommand(expectRTS) != BleCommandCTS()) { + if (BleCommand(expectRTS) != BleCommandRTS()) { throw UnexpectedCommandException(BleCommand(expectRTS)) } bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandCTS().data) @@ -53,7 +53,7 @@ class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) { } } if (joiner.oneExtra) { - var data = bleIO.receivePacket(CharacteristicType.DATA) + data = bleIO.receivePacket(CharacteristicType.DATA) val accumulateAction = joiner.accumulate(data) if (accumulateAction is PayloadJoinerActionReject) { bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandNack(accumulateAction.idx).data) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitter.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitter.kt index d74032e6fe..6a0c60139b 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitter.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitter.kt @@ -25,6 +25,7 @@ internal class PayloadSplitter(private val payload: ByteArray) { ret.add(LastOptionalPlusOneBlePacket( index = 1, payload = payload.copyOfRange(end, payload.size), + size = (payload.size-end).toByte(), )) } return ret @@ -53,9 +54,10 @@ internal class PayloadSplitter(private val payload: ByteArray) { payload = payload.copyOfRange(middleFragments * MiddleBlePacket.CAPACITY + FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS, middleFragments * MiddleBlePacket.CAPACITY + FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + end), crc32 = crc32, )) - if (rest > 14) { + if (rest > LastBlePacket.CAPACITY) { ret.add(LastOptionalPlusOneBlePacket( index = (middleFragments + 2).toByte(), + size = (rest-LastBlePacket.CAPACITY).toByte(), payload = payload.copyOfRange(middleFragments * MiddleBlePacket.CAPACITY + FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + LastBlePacket.CAPACITY, payload.size), )) } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/packet/BlePacket.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/packet/BlePacket.kt index b9bd30a252..acdd237431 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/packet/BlePacket.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/packet/BlePacket.kt @@ -7,6 +7,7 @@ sealed class BlePacket { abstract fun asByteArray(): ByteArray companion object { + const val MAX_BLE_PACKET_LEN = 20 const val MAX_BLE_BUFFER_LEN = MAX_BLE_PACKET_LEN + 1 // we use this as the size allocated for the ByteBuffer } @@ -33,6 +34,7 @@ data class FirstBlePacket(val totalFragments: Byte, val payload: ByteArray, val } companion object { + internal const val CAPACITY_WITHOUT_MIDDLE_PACKETS = 13 // we are using all fields internal const val CAPACITY_WITH_MIDDLE_PACKETS = 18 // we are not using crc32 or size internal const val CAPACITY_WITH_THE_OPTIONAL_PLUS_ONE_PACKET = 18 @@ -46,6 +48,7 @@ data class MiddleBlePacket(val index: Byte, val payload: ByteArray) : BlePacket( } companion object { + internal const val CAPACITY = 19 } } @@ -66,14 +69,15 @@ data class LastBlePacket(val index: Byte, val size: Byte, val payload: ByteArray } companion object { + internal const val CAPACITY = 14 } } -data class LastOptionalPlusOneBlePacket(val index: Byte, val payload: ByteArray) : BlePacket() { +data class LastOptionalPlusOneBlePacket(val index: Byte, val payload: ByteArray, val size: Byte) : BlePacket() { override fun asByteArray(): ByteArray { - return byteArrayOf(index) + payload + return byteArrayOf(index, size) + payload } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/BleDiscoveredDevice.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/BleDiscoveredDevice.kt index 1b4a2cee2a..bf3d3dd74c 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/BleDiscoveredDevice.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/BleDiscoveredDevice.kt @@ -31,7 +31,6 @@ class BleDiscoveredDevice(val scanResult: ScanResult, private val scanRecord: Sc @Throws(DiscoveredInvalidPodException::class) private fun validatePodId() { - val scanRecord = scanResult.scanRecord val serviceUUIDs = scanRecord.serviceUuids val hexPodId = extractUUID16(serviceUUIDs[3]) + extractUUID16(serviceUUIDs[4]) val podId = hexPodId.toLong(16)