From a29874dc6d0ca72a8a39a65485cd61d47be6b804 Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Sat, 3 Apr 2021 12:20:11 +0200 Subject: [PATCH] implement EAP-AKA resynchronization --- .../driver/comm/OmnipodDashBleManagerImpl.kt | 16 +++++- .../driver/comm/callbacks/BleCommCallbacks.kt | 4 +- .../pump/omnipod/dash/driver/comm/io/BleIO.kt | 7 ++- .../dash/driver/comm/session/Connection.kt | 37 ++++++++----- .../driver/comm/session/EapAkaAttribute.kt | 26 +++++++++ .../dash/driver/comm/session/EapMessage.kt | 6 +- .../dash/driver/comm/session/EapSqn.kt | 31 +++++++++++ .../dash/driver/comm/session/Milenage.kt | 38 +++++++++++-- .../driver/comm/session/SessionEstablisher.kt | 55 ++++++++++++++++--- .../dash/driver/comm/session/SessionKeys.kt | 7 ++- .../state/OmnipodDashPodStateManagerImpl.kt | 6 +- .../dash/ui/DashPodManagementActivity.kt | 3 +- .../driver/comm/message/PayloadJoinerTest.kt | 2 +- .../comm/message/PayloadSplitJoinTest.kt | 3 +- .../comm/message/PayloadSplitterTest.kt | 1 + .../dash/driver/comm/session/MilenageTest.kt | 38 +++++++++---- 16 files changed, 227 insertions(+), 53 deletions(-) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt 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 e56fc13b53..69ec21f599 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 @@ -17,6 +17,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response. import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager import info.nightscout.androidaps.utils.extensions.toHex import io.reactivex.Observable +import java.nio.ByteBuffer import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject import javax.inject.Singleton @@ -142,8 +143,19 @@ class OmnipodDashBleManagerImpl @Inject constructor( val podId = uniqueId?.let { Id.fromLong(uniqueId) } ?: myId.increment() // pod not activated - val eapSqn = podState.increaseEapAkaSequenceNumber() - conn.establishSession(ltk, msgSeq, myId, podId, eapSqn) + var eapSqn = podState.increaseEapAkaSequenceNumber() + + var newSqn = conn.establishSession(ltk, msgSeq, myId, podId, eapSqn) + + if (newSqn != null) { + aapsLogger.info(LTag.PUMPBTCOMM, "Updating EAP SQN to: $newSqn") + podState.eapAkaSequenceNumber = newSqn.toLong() + var newSqn = conn.establishSession(ltk, msgSeq, myId, podId, podState.increaseEapAkaSequenceNumber()) + if (newSqn != null) { + throw SessionEstablishmentException("Received resynchronization SQN for the second time") + } + } + podState.commitEapAkaSequenceNumber() } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt index 0b613e1a93..1fcafca0d8 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt @@ -21,7 +21,7 @@ class BleCommCallbacks( private val incomingPackets: IncomingPackets, ) : BluetoothGattCallback() { - private val serviceDiscoveryComplete: CountDownLatch = CountDownLatch(1) + private var serviceDiscoveryComplete: CountDownLatch = CountDownLatch(1) private var connected: CountDownLatch = CountDownLatch(1) private val writeQueue: BlockingQueue = LinkedBlockingQueue(1) @@ -152,7 +152,9 @@ class BleCommCallbacks( } fun resetConnection() { + aapsLogger.debug(LTag.PUMPBTCOMM, "Reset connection") connected = CountDownLatch(1) + serviceDiscoveryComplete = CountDownLatch(1) flushConfirmationQueue() } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt index fc7e1d3645..88583a82b8 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt @@ -54,15 +54,15 @@ open class BleIO( * @param payload the data to send */ fun sendAndConfirmPacket(payload: ByteArray): BleSendResult { - aapsLogger.debug(LTag.PUMPBTCOMM, "BleIO: Sending on ${type.name}: ${payload.toHex()}") + aapsLogger.debug(LTag.PUMPBTCOMM, "BleIO: Sending on $type: ${payload.toHex()}") val set = characteristic.setValue(payload) if (!set) { - return BleSendErrorSending("Could set setValue on ${type.name}") + return BleSendErrorSending("Could set setValue on $type") } bleCommCallbacks.flushConfirmationQueue() val sent = gatt.writeCharacteristic(characteristic) if (!sent) { - return BleSendErrorSending("Could not writeCharacteristic on {$type.name}") + return BleSendErrorSending("Could not writeCharacteristic on $type") } return when ( @@ -111,6 +111,7 @@ open class BleIO( if (!wrote) { throw ConnectException("Could not enable indications on descriptor") } + aapsLogger.debug(LTag.PUMPBTCOMM, "Enabling indications for $type") val confirmation = bleCommCallbacks.confirmWrite( BluetoothGattDescriptor.ENABLE_INDICATION_VALUE, descriptor.uuid.toString(), diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Connection.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Connection.kt index 463be77b1a..8de4493854 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Connection.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Connection.kt @@ -13,6 +13,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.ServiceD import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.BleCommCallbacks import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt.EnDecrypt import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.FailedToConnectException +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.SessionEstablishmentException import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.BleSendSuccess import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CmdBleIO @@ -87,13 +88,14 @@ class Connection(val podDevice: BluetoothDevice, private val aapsLogger: AAPSLog if (waitForConnection() is NotConnected) { throw FailedToConnectException(podDevice.address) } - + discoverer.discoverServices() cmdBleIO.hello() cmdBleIO.readyToRead() dataBleIO.readyToRead() } fun disconnect() { + aapsLogger.debug(LTag.PUMPBTCOMM, "Disconnecting") bleCommCallbacks.resetConnection() gattConnection.disconnect() session = null @@ -118,20 +120,27 @@ class Connection(val podDevice: BluetoothDevice, private val aapsLogger: AAPSLog return Connected } - fun establishSession(ltk: ByteArray, msgSeq: Byte, myId: Id, podID: Id, eapSqn: ByteArray) { - val eapAkaExchanger = SessionEstablisher(aapsLogger, msgIO, ltk, eapSqn, myId, podID, msgSeq) - val keys = eapAkaExchanger.negotiateSessionKeys() - if (BuildConfig.DEBUG) { - aapsLogger.info(LTag.PUMPCOMM, "CK: ${keys.ck.toHex()}") - aapsLogger.info(LTag.PUMPCOMM, "msgSequenceNumber: ${keys.msgSequenceNumber}") - aapsLogger.info(LTag.PUMPCOMM, "Nonce: ${keys.nonce}") + fun establishSession(ltk: ByteArray, msgSeq: Byte, myId: Id, podID: Id, eapSqn: ByteArray): EapSqn? { + var eapAkaExchanger = SessionEstablisher(aapsLogger, msgIO, ltk, eapSqn, myId, podID, msgSeq) + var keys = eapAkaExchanger.negotiateSessionKeys() + return when (keys) { + is SessionNegotiationResynchronization -> + keys.syncronizedEapSqn + is SessionKeys -> { + if (BuildConfig.DEBUG) { + aapsLogger.info(LTag.PUMPCOMM, "CK: ${keys.ck.toHex()}") + aapsLogger.info(LTag.PUMPCOMM, "msgSequenceNumber: ${keys.msgSequenceNumber}") + aapsLogger.info(LTag.PUMPCOMM, "Nonce: ${keys.nonce}") + } + val enDecrypt = EnDecrypt( + aapsLogger, + keys.nonce, + keys.ck + ) + session = Session(aapsLogger, msgIO, myId, podID, sessionKeys = keys, enDecrypt = enDecrypt) + null + } } - val enDecrypt = EnDecrypt( - aapsLogger, - keys.nonce, - keys.ck - ) - session = Session(aapsLogger, msgIO, myId, podID, sessionKeys = keys, enDecrypt = enDecrypt) } companion object { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt index d02bb1a835..ea0d1f69b9 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt @@ -9,6 +9,7 @@ enum class EapAkaAttributeType(val type: Byte) { AT_RAND(1), AT_AUTN(2), AT_RES(3), + AT_AUTS(4), AT_CLIENT_ERROR_CODE(22), AT_CUSTOM_IV(126); @@ -47,6 +48,8 @@ sealed class EapAkaAttribute { ret.add(EapAkaAttributeCustomIV.parse(tail.copyOfRange(2, EapAkaAttributeCustomIV.SIZE))) EapAkaAttributeType.AT_AUTN -> ret.add(EapAkaAttributeAutn.parse(tail.copyOfRange(2, EapAkaAttributeAutn.SIZE))) + EapAkaAttributeType.AT_AUTS -> + ret.add(EapAkaAttributeAuts.parse(tail.copyOfRange(2, EapAkaAttributeAuts.SIZE))) EapAkaAttributeType.AT_RAND -> ret.add(EapAkaAttributeRand.parse(tail.copyOfRange(2, EapAkaAttributeRand.SIZE))) EapAkaAttributeType.AT_CLIENT_ERROR_CODE -> @@ -112,6 +115,29 @@ data class EapAkaAttributeAutn(val payload: ByteArray) : EapAkaAttribute() { } } +data class EapAkaAttributeAuts(val payload: ByteArray) : EapAkaAttribute() { + + init { + require(payload.size == 14) { "AT_AUTS payload size has to be 14 bytes. Payload: ${payload.toHex()}" } + } + + override fun toByteArray(): ByteArray { + return byteArrayOf(EapAkaAttributeType.AT_AUTS.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, 0) + payload + } + + companion object { + + fun parse(payload: ByteArray): EapAkaAttribute { + if (payload.size < SIZE-2) { + throw MessageIOException("Could not parse AUTS attribute: ${payload.toHex()}") + } + return EapAkaAttributeAuts(payload) + } + + const val SIZE = 16 // type, size, 2 reserved bytes, payload=16 + } +} + data class EapAkaAttributeRes(val payload: ByteArray) : EapAkaAttribute() { init { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt index e66684a770..edee7fcdd3 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt @@ -23,6 +23,7 @@ enum class EapCode(val code: Byte) { data class EapMessage( val code: EapCode, val identifier: Byte, + val subType: Byte = 0, val attributes: Array ) { @@ -56,6 +57,8 @@ data class EapMessage( private const val HEADER_SIZE = 8 private const val SUBTYPE_AKA_CHALLENGE = 1.toByte() + const val SUBTYPE_SYNCRONIZATION_FAILURE = 4.toByte() + private const val AKA_PACKET_TYPE = 0x17.toByte() fun parse(aapsLogger: AAPSLogger, payload: ByteArray): EapMessage { @@ -81,7 +84,8 @@ data class EapMessage( return EapMessage( code = EapCode.byValue(payload[0]), identifier = payload[1], - attributes = EapAkaAttribute.parseAttributes(aapsLogger, attributesPayload).toTypedArray() + attributes = EapAkaAttribute.parseAttributes(aapsLogger, attributesPayload).toTypedArray(), + subType = payload[5], ) } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt new file mode 100644 index 0000000000..f1e8f0e118 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt @@ -0,0 +1,31 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session + +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id +import java.nio.ByteBuffer + +class EapSqn(val value: ByteArray) { + constructor(v: Long): this(fromLong(v)) + + init { + require(value.size == SIZE) {"Eap SQN is $SIZE bytes long"} + } + + fun increment(): EapSqn { + return EapSqn(toLong() + 1) + } + + fun toLong(): Long { + return ByteBuffer.wrap( + byteArrayOf(0x00, 0x00) + + value + ).long + } + + companion object { + private const val SIZE = 6 + private fun fromLong(v: Long): ByteArray { + return ByteBuffer.allocate(8).putLong(v).array().copyOfRange(2, 8) + } + + } +} \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Milenage.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Milenage.kt index ba10b74db1..dbab6ae991 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Milenage.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Milenage.kt @@ -12,12 +12,17 @@ class Milenage( private val aapsLogger: AAPSLogger, private val k: ByteArray, val sqn: ByteArray, - private val randParam: ByteArray? = null + randParam: ByteArray? = null, + val auts: ByteArray = ByteArray(AUTS_SIZE), + val amf: ByteArray = MILENAGE_AMF, ) { init { require(k.size == KEY_SIZE) { "Milenage key has to be $KEY_SIZE bytes long. Received: ${k.toHex()}" } require(sqn.size == SQN) { "Milenage SQN has to be $SQN long. Received: ${sqn.toHex()}" } + require(auts.size == AUTS_SIZE) { "Milenage AUTS has to be $AUTS_SIZE long. Received: ${auts.toHex()}"} + require(amf.size == MILENAGE_AMF.size) { "Milenage AMF has to be ${MILENAGE_AMF.size} long." + + "Received: ${amf.toHex()}"} } private val secretKeySpec = SecretKeySpec(k, "AES") @@ -61,7 +66,7 @@ class Milenage( val ck = cipher.doFinal(ckInput) xor opc - private val sqnAmf = sqn + MILENAGE_AMF + sqn + MILENAGE_AMF + private val sqnAmf = sqn + amf + sqn + amf private val sqnAmfXorOpc = sqnAmf xor opc private val macAInput = ByteArray(KEY_SIZE) @@ -73,7 +78,24 @@ class Milenage( private val macAFull = cipher.doFinal(macAInput xor randOpcEncrypted) xor opc private val macA = macAFull.copyOfRange(0, 8) - val autn = (ak xor sqn) + MILENAGE_AMF + macA + val macS = macAFull.copyOfRange(8, 16) + + val autn = (ak xor sqn) + amf + macA + + // Used for re-synchronisation AUTS = SQN^AK || MAC-S + private val akStarInput = ByteArray(KEY_SIZE) + init { + for (i in 0..15) { + akStarInput[(i + 4) % 16] = randOpcEncryptedXorOpc[i] + } + akStarInput[15] = (akStarInput[15].toInt() xor 8).toByte() + } + private val akStarFull = cipher.doFinal(akStarInput) xor opc + private val akStar = akStarFull.copyOfRange(0, 6) + + private val seqXorAkStar = auts.copyOfRange(0, 6) + val synchronizationSqn = akStar xor seqXorAkStar + val receivedMacS = auts.copyOfRange(6, 14) init { aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage K: ${k.toHex()}") @@ -83,15 +105,23 @@ class Milenage( aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage AUTN: ${autn.toHex()}") aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage RES: ${res.toHex()}") aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage AK: ${ak.toHex()}") + aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage AK STAR: ${akStar.toHex()}") aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage OPC: ${opc.toHex()}") + aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage FullMAC: ${macAFull.toHex()}") aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage MacA: ${macA.toHex()}") + aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage MacS: ${macS.toHex()}") + aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage AUTS: ${auts.toHex()}") + aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage synchronizationSqn: ${synchronizationSqn.toHex()}") + aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage receivedMacS: ${receivedMacS.toHex()}") } companion object { + val RESYNC_AMF = Hex.decode("0000") private val MILENAGE_OP = Hex.decode("cdc202d5123e20f62b6d676ac72cb318") private val MILENAGE_AMF = Hex.decode("b9b9") - private const val KEY_SIZE = 16 + const val KEY_SIZE = 16 + const val AUTS_SIZE = 14 private const val SQN = 6 } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt index 5a62e00bfc..2f50ea9149 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt @@ -16,8 +16,8 @@ import java.util.* class SessionEstablisher( private val aapsLogger: AAPSLogger, private val msgIO: MessageIO, - ltk: ByteArray, - eapSqn: ByteArray, + private val ltk: ByteArray, + private val eapSqn: ByteArray, private val myId: Id, private val podId: Id, private var msgSeq: Byte @@ -37,7 +37,7 @@ class SessionEstablisher( random.nextBytes(controllerIV) } - fun negotiateSessionKeys(): SessionKeys { + fun negotiateSessionKeys(): SessionNegotiationResponse { msgSeq++ var challenge = eapAkaChallenge() val sendResult = msgIO.sendMessage(challenge) @@ -47,7 +47,13 @@ class SessionEstablisher( val challengeResponse = msgIO.receiveMessage() ?: throw SessionEstablishmentException("Could not establish session") - processChallengeResponse(challengeResponse) + val newSqn = processChallengeResponse(challengeResponse) + if (newSqn != null) { + return SessionNegotiationResynchronization( + syncronizedEapSqn = newSqn, + msgSequenceNumber = msgSeq + ) + } msgSeq++ var success = eapSuccess() @@ -84,7 +90,7 @@ class SessionEstablisher( ) } - private fun processChallengeResponse(challengeResponse: MessagePacket) { + private fun processChallengeResponse(challengeResponse: MessagePacket): EapSqn? { val eapMsg = EapMessage.parse(aapsLogger, challengeResponse.payload) if (eapMsg.identifier != identifier) { aapsLogger.debug( @@ -93,22 +99,56 @@ class SessionEstablisher( ) throw SessionEstablishmentException("Received incorrect EAP identifier: ${eapMsg.identifier}") } + + if (eapMsg.subType == EapMessage.SUBTYPE_SYNCRONIZATION_FAILURE && + eapMsg.attributes.size == 1 && + eapMsg.attributes[0] is EapAkaAttributeAuts + ) { + val auts = eapMsg.attributes[0] as EapAkaAttributeAuts + val autsMilenage = Milenage( + aapsLogger = aapsLogger, + k = ltk, + sqn = eapSqn, + randParam = milenage.rand, + auts = auts.payload + ) + + val newSqnMilenage = Milenage( + aapsLogger = aapsLogger, + k = ltk, + sqn = autsMilenage.synchronizationSqn, + randParam = milenage.rand, + auts = auts.payload, + amf = Milenage.RESYNC_AMF, + ) + + if (!newSqnMilenage.macS.contentEquals(newSqnMilenage.receivedMacS)) { + throw SessionEstablishmentException( + "MacS mismatch. " + + "Expected: ${newSqnMilenage.macS.toHex()}. " + + "Received: ${newSqnMilenage.receivedMacS.toHex()}" + ) + } + return EapSqn(autsMilenage.synchronizationSqn) + } + if (eapMsg.attributes.size != 2) { aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got message: $eapMsg") if (eapMsg.attributes.size == 1 && eapMsg.attributes[0] is EapAkaAttributeClientErrorCode) { throw SessionEstablishmentException( "Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${ - eapMsg.attributes[0].toByteArray().toHex() + eapMsg.attributes[0].toByteArray().toHex() }" ) } throw SessionEstablishmentException("Expecting two attributes, got: ${eapMsg.attributes.size}") } + for (attr in eapMsg.attributes) { when (attr) { is EapAkaAttributeRes -> if (!milenage.res.contentEquals(attr.payload)) { - throw SessionEstablishmentException("RES missmatch. Expected: ${milenage.res.toHex()} Actual: ${attr.payload.toHex()} ") + throw SessionEstablishmentException("RES mismatch. Expected: ${milenage.res.toHex()} Actual: ${attr.payload.toHex()} ") } is EapAkaAttributeCustomIV -> nodeIV = attr.payload.copyOfRange(0, IV_SIZE) @@ -116,6 +156,7 @@ class SessionEstablisher( throw SessionEstablishmentException("Unknown attribute received: $attr") } } + return null } private fun eapSuccess(): MessagePacket { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionKeys.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionKeys.kt index e4fb6a04d5..cfd0be4c38 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionKeys.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionKeys.kt @@ -2,8 +2,13 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt.Nonce -data class SessionKeys(val ck: ByteArray, val nonce: Nonce, var msgSequenceNumber: Byte) { +sealed class SessionNegotiationResponse + +data class SessionKeys(val ck: ByteArray, val nonce: Nonce, var msgSequenceNumber: Byte):SessionNegotiationResponse() { init { require(ck.size == 16) { "CK has to be 16 bytes long" } } } + +data class SessionNegotiationResynchronization(val syncronizedEapSqn: EapSqn?, val msgSequenceNumber: Byte) + :SessionNegotiationResponse() \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt index 94aaca41cc..dd073c8c50 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt @@ -8,6 +8,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.EventOmnipodDashPump import info.nightscout.androidaps.plugins.pump.omnipod.dash.R import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair.PairResult +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.EapSqn import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.* import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.AlarmStatusResponse import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.DefaultStatusResponse @@ -173,10 +174,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( override fun increaseEapAkaSequenceNumber(): ByteArray { podState.eapAkaSequenceNumber++ - return ByteBuffer.allocate(8) - .putLong(podState.eapAkaSequenceNumber) - .array() - .copyOfRange(2, 8) + return EapSqn(podState.eapAkaSequenceNumber).value } override fun commitEapAkaSequenceNumber() { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/DashPodManagementActivity.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/DashPodManagementActivity.kt index 6dc63d5c46..27f93766f6 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/DashPodManagementActivity.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/DashPodManagementActivity.kt @@ -117,8 +117,7 @@ class DashPodManagementActivity : NoSplashAppCompatActivity() { // Only show the discard button to reset a cached unique ID before the unique ID has actually been set // Otherwise, users should use the Deactivate Pod Wizard. In case proper deactivation fails, // they will get an option to discard the Pod there - val discardButtonEnabled = - podStateManager.uniqueId != null && podStateManager.activationProgress.isBefore(ActivationProgress.SET_UNIQUE_ID) + val discardButtonEnabled = true binding.buttonDiscardPod.visibility = discardButtonEnabled.toVisibility() binding.buttonActivatePod.isEnabled = podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED) diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoinerTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoinerTest.kt index 5ceed4dd49..d3efcaaf29 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoinerTest.kt +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoinerTest.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message import com.google.crypto.tink.subtle.Hex -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.PayloadJoiner +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.PayloadJoiner import info.nightscout.androidaps.utils.extensions.toHex import org.junit.Assert.assertEquals import org.junit.Test diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitJoinTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitJoinTest.kt index fc495c6e87..f7edec20b4 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitJoinTest.kt +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitJoinTest.kt @@ -1,6 +1,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.PayloadJoiner +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.PayloadJoiner +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.PayloadSplitter import info.nightscout.androidaps.utils.extensions.toHex import org.junit.Assert.assertEquals import org.junit.Test diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitterTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitterTest.kt index a18349d82d..4ac605f1d2 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitterTest.kt +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitterTest.kt @@ -1,6 +1,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message import com.google.crypto.tink.subtle.Hex +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.PayloadSplitter import info.nightscout.androidaps.utils.extensions.toHex import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/MilenageTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/MilenageTest.kt index b72bd2fb73..d16c20028a 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/MilenageTest.kt +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/MilenageTest.kt @@ -11,10 +11,10 @@ class MilenageTest { @Test fun testMilenage() { val aapsLogger = AAPSLoggerTest() val m = Milenage( - aapsLogger, - Hex.decode("c0772899720972a314f557de66d571dd"), - byteArrayOf(0, 0, 0, 0, 0, 2), - Hex.decode("c2cd1248451103bd77a6c7ef88c441ba") + aapsLogger = aapsLogger, + k = Hex.decode("c0772899720972a314f557de66d571dd"), + sqn = byteArrayOf(0, 0, 0, 0, 0, 2), + randParam = Hex.decode("c2cd1248451103bd77a6c7ef88c441ba") ) Assert.assertEquals(m.res.toHex(), "a40bc6d13861447e") Assert.assertEquals(m.ck.toHex(), "55799fd26664cbf6e476525e2dee52c6") @@ -24,10 +24,10 @@ class MilenageTest { @Test fun testMilenage2() { val aapsLogger = AAPSLoggerTest() val m = Milenage( - aapsLogger, - Hex.decode("78411ccad0fd0fb6f381a47fb3335ecb"), - byteArrayOf(0, 0, 0, 0, 0, 2), // 1 + 1 - Hex.decode("4fc01ac1a94376ae3e052339c07d9e1f") + aapsLogger = aapsLogger, + k = Hex.decode("78411ccad0fd0fb6f381a47fb3335ecb"), + sqn = byteArrayOf(0, 0, 0, 0, 0, 2), // 1 + 1 + randParam = Hex.decode("4fc01ac1a94376ae3e052339c07d9e1f") ) Assert.assertEquals(m.res.toHex(), "ec549e00fa668a19") Assert.assertEquals(m.ck.toHex(), "ee3dac761fe358a9f476cc5ee81aa3e9") @@ -37,14 +37,28 @@ class MilenageTest { @Test fun testMilenageIncrementedSQN() { val aapsLogger = AAPSLoggerTest() val m = Milenage( - aapsLogger, - Hex.decode("c0772899720972a314f557de66d571dd"), + aapsLogger = aapsLogger, + k = Hex.decode("c0772899720972a314f557de66d571dd"), // byteArrayOf(0,0,0,0,0x01,0x5d), this is in logs. SQN has to be incremented. - byteArrayOf(0, 0, 0, 0, 0x01, 0x5e), - Hex.decode("d71cc44820e5419f42c62ae97c035988") + sqn = byteArrayOf(0, 0, 0, 0, 0x01, 0x5e), + randParam = Hex.decode("d71cc44820e5419f42c62ae97c035988") ) Assert.assertEquals(m.res.toHex(), "5f807a379a5c5d30") Assert.assertEquals(m.ck.toHex(), "8dd4b3ceb849a01766e37f9d86045c39") Assert.assertEquals(m.autn.toHex(), "0e0264d056fcb9b9752227365a090955") } + + @Test fun testMileageSynchronization() { + val aapsLogger = AAPSLoggerTest() + val m = Milenage( + aapsLogger = aapsLogger, + k = Hex.decode("689b860fde3331dd7e1671ad39985e3b"), + sqn = byteArrayOf(0, 0, 0, 0, 0, 8), // 1 + 1 + auts = Hex.decode("84ff173947a67567985de71e4890"), + randParam = Hex.decode("396707041ca3a5931fc0e52d2d7b9ecf"), + amf = byteArrayOf(0, 0), + ) + Assert.assertEquals(m.receivedMacS.toHex(), m.macS.toHex()) + Assert.assertEquals(m.sqn.toHex(), m.synchronizationSqn.toHex()) + } }