commit
2f9c88594b
14 changed files with 186 additions and 44 deletions
|
@ -29,6 +29,21 @@ data class Id(val address: ByteArray) {
|
||||||
return ByteBuffer.wrap(address).int.toLong() and 0xffffffffL
|
return ByteBuffer.wrap(address).int.toLong() and 0xffffffffL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as Id
|
||||||
|
|
||||||
|
if (!address.contentEquals(other.address)) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return address.contentHashCode()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val PERIPHERAL_NODE_INDEX = 1 // TODO: understand the meaning of this value. It comes from preferences
|
private const val PERIPHERAL_NODE_INDEX = 1 // TODO: understand the meaning of this value. It comes from preferences
|
||||||
|
|
|
@ -61,6 +61,6 @@ class EnDecrypt(private val aapsLogger: AAPSLogger, private val nonce: Nonce, pr
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val MAC_SIZE = 8
|
private const val MAC_SIZE = 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import java.nio.ByteBuffer
|
||||||
/***
|
/***
|
||||||
* String prefix and length encoding and decoding. Example message:
|
* String prefix and length encoding and decoding. Example message:
|
||||||
*/
|
*/
|
||||||
class StringLengthPrefixEncoding {
|
class StringLengthPrefixEncoding private constructor() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair
|
||||||
|
|
||||||
import com.google.crypto.tink.subtle.X25519
|
import com.google.crypto.tink.subtle.X25519
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.AAPSLoggerTest
|
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.BuildConfig
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.BuildConfig
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.MessageIOException
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.MessageIOException
|
||||||
|
@ -12,7 +11,8 @@ import org.spongycastle.crypto.macs.CMac
|
||||||
import org.spongycastle.crypto.params.KeyParameter
|
import org.spongycastle.crypto.params.KeyParameter
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
|
|
||||||
class KeyExchange(private val aapsLogger: AAPSLogger,
|
class KeyExchange(
|
||||||
|
private val aapsLogger: AAPSLogger,
|
||||||
var pdmPrivate: ByteArray = X25519.generatePrivateKey(),
|
var pdmPrivate: ByteArray = X25519.generatePrivateKey(),
|
||||||
val pdmNonce: ByteArray = ByteArray(NONCE_SIZE)
|
val pdmNonce: ByteArray = ByteArray(NONCE_SIZE)
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -23,7 +23,7 @@ enum class EapCode(val code: Byte) {
|
||||||
data class EapMessage(
|
data class EapMessage(
|
||||||
val code: EapCode,
|
val code: EapCode,
|
||||||
val identifier: Byte,
|
val identifier: Byte,
|
||||||
val attributes: Array<EapAkaAttribute>,
|
val attributes: Array<EapAkaAttribute>
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun toByteArray(): ByteArray {
|
fun toByteArray(): ByteArray {
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Eap-Aka start session sequence.
|
|
||||||
* Incremented for each new session
|
|
||||||
*/
|
|
||||||
class EapSqn(var sqn: Long) {
|
|
||||||
|
|
||||||
fun increment(): ByteArray {
|
|
||||||
sqn++
|
|
||||||
return ByteBuffer.allocate(8)
|
|
||||||
.putLong(sqn)
|
|
||||||
.array()
|
|
||||||
.copyOfRange(2, 8)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -37,7 +37,7 @@ class SessionEstablisher(
|
||||||
|
|
||||||
fun negotiateSessionKeys(): SessionKeys {
|
fun negotiateSessionKeys(): SessionKeys {
|
||||||
// send EAP-AKA challenge
|
// send EAP-AKA challenge
|
||||||
msgSeq++ // TODO: get from pod state. This only works for activating a new pod
|
msgSeq++
|
||||||
var challenge = eapAkaChallenge()
|
var challenge = eapAkaChallenge()
|
||||||
msgIO.sendMessage(challenge)
|
msgIO.sendMessage(challenge)
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ class SessionEstablisher(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processChallengeResponse(challengeResponse: MessagePacket) {
|
private fun processChallengeResponse(challengeResponse: MessagePacket) {
|
||||||
// TODO verify that identifier matches identifer from the Challenge
|
// TODO verify that identifier matches identifier from the Challenge
|
||||||
val eapMsg = EapMessage.parse(aapsLogger, challengeResponse.payload)
|
val eapMsg = EapMessage.parse(aapsLogger, challengeResponse.payload)
|
||||||
if (eapMsg.attributes.size != 2) {
|
if (eapMsg.attributes.size != 2) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got message: $eapMsg")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got message: $eapMsg")
|
||||||
|
|
|
@ -11,23 +11,24 @@ class EnDecryptTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun decrypt() {
|
fun decrypt() {
|
||||||
// TODO: add data received from the pod
|
val received =
|
||||||
// this test is failing because the way we increment the nonce
|
"54,57,11,a1,0c,16,03,00,08,20,2e,a9,08,20,2e,a8,34,7c,b9,7b,38,5d,45,a3,c4,0e,40,4c,55,71,5e,f3,c3,86,50,17,36,7e,62,3c,7d,0b,46,9e,81,cd,fd,9a".replace(
|
||||||
|
",",
|
||||||
|
""
|
||||||
|
)
|
||||||
|
val decryptedPayload =
|
||||||
|
"30,2e,30,3d,00,12,08,20,2e,a9,1c,0a,1d,05,00,16,b0,00,00,00,0b,ff,01,fe".replace(",", "")
|
||||||
val aapsLogger = AAPSLoggerTest()
|
val aapsLogger = AAPSLoggerTest()
|
||||||
val enDecrypt = EnDecrypt(
|
val enDecrypt = EnDecrypt(
|
||||||
aapsLogger,
|
aapsLogger,
|
||||||
Nonce(
|
Nonce(
|
||||||
Hex.decode("dda23c090a0a0a0a"),
|
Hex.decode("6c,ff,5d,18,b7,61,6c,ae".replace(",", "")),
|
||||||
0
|
22
|
||||||
),
|
),
|
||||||
Hex.decode("ba1283744b6de9fab6d9b77d95a71d6e")
|
Hex.decode("55,79,9f,d2,66,64,cb,f6,e4,76,52,5e,2d,ee,52,c6".replace(",", ""))
|
||||||
)
|
)
|
||||||
val encryptedMessage = Hex.decode(
|
val encryptedMessage = Hex.decode(received)
|
||||||
"54571101070003400242000002420001" +
|
val decrypted = Hex.decode(decryptedPayload)
|
||||||
"e09158bcb0285a81bf30635f3a17ee73f0afbb3286bc524a8a66" +
|
|
||||||
"fb1bc5b001e56543"
|
|
||||||
)
|
|
||||||
val decrypted = Hex.decode("53302e303d000effffffff00060704ffffffff82b22c47302e30")
|
|
||||||
val msg = MessagePacket.parse(encryptedMessage)
|
val msg = MessagePacket.parse(encryptedMessage)
|
||||||
val decryptedMsg = enDecrypt.decrypt(msg)
|
val decryptedMsg = enDecrypt.decrypt(msg)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
||||||
|
|
||||||
|
import com.google.crypto.tink.subtle.Hex
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLoggerTest
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||||
|
import info.nightscout.androidaps.utils.extensions.toHex
|
||||||
|
import org.junit.Assert.*
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class MessagePacketTest {
|
||||||
|
|
||||||
|
val payload =
|
||||||
|
"54,57,11,01,07,00,03,40,08,20,2e,a8,08,20,2e,a9,ab,35,d8,31,60,9b,b8,fe,3a,3b,de,5b,18,37,24,9a,16,db,f8,e4,d3,05,e9,75,dc,81,7c,37,07,cc,41,5f,af,8a".replace(
|
||||||
|
",",
|
||||||
|
""
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test fun testParseMessagePacket() {
|
||||||
|
val aapsLogger = AAPSLoggerTest()
|
||||||
|
val msg = MessagePacket.parse(Hex.decode(payload))
|
||||||
|
assertEquals(msg.type, MessageType.ENCRYPTED)
|
||||||
|
assertEquals(msg.source, Id.fromLong(136326824))
|
||||||
|
assertEquals(msg.destination, Id.fromLong(136326825))
|
||||||
|
assertEquals(msg.sequenceNumber, 7.toByte())
|
||||||
|
assertEquals(msg.ackNumber, 0.toByte())
|
||||||
|
assertEquals(msg.eqos, 1.toShort())
|
||||||
|
assertEquals(msg.priority, false)
|
||||||
|
assertEquals(msg.lastMessage, false)
|
||||||
|
assertEquals(msg.gateway, false)
|
||||||
|
assertEquals(msg.sas, true)
|
||||||
|
assertEquals(msg.tfs, false)
|
||||||
|
assertEquals(msg.version, 0.toShort())
|
||||||
|
assertEquals(msg.payload.toHex(), payload.substring(32, payload.length))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun testSerializeMessagePacket() {
|
||||||
|
val msg = MessagePacket(
|
||||||
|
type = MessageType.ENCRYPTED,
|
||||||
|
source = Id.fromLong(136326824),
|
||||||
|
destination = Id.fromLong(136326825),
|
||||||
|
sequenceNumber = 7.toByte(),
|
||||||
|
ackNumber = 0.toByte(),
|
||||||
|
eqos = 1.toShort(),
|
||||||
|
priority = false,
|
||||||
|
lastMessage = false,
|
||||||
|
gateway = false,
|
||||||
|
sas = true,
|
||||||
|
tfs = false,
|
||||||
|
payload = Hex.decode(payload.substring(32, payload.length))
|
||||||
|
)
|
||||||
|
assertEquals(msg.asByteArray().toHex(), payload)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
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.utils.extensions.toHex
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class PayloadJoinerTest {
|
||||||
|
|
||||||
|
@Test fun testJoiner() {
|
||||||
|
val f1 = Hex.decode("00,01,54,57,10,23,03,00,00,c0,ff,ff,ff,fe,08,20,2e,a8,50,30".replace(",", ""))
|
||||||
|
val f2 = Hex.decode("01,04,bc,20,1f,f6,3d,00,01,a5,ff,ff,ff,fe,08,20,2e,a8,50,30".replace(",", ""))
|
||||||
|
val payload = "54,57,10,23,03,00,00,c0,ff,ff,ff,fe,08,20,2e,a8,50,30,3d,00,01,a5".replace(",", "")
|
||||||
|
val joiner = PayloadJoiner(f1)
|
||||||
|
joiner.accumulate(f2)
|
||||||
|
val actual = joiner.finalize()
|
||||||
|
assertEquals(payload, actual.toHex())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
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.utils.extensions.toHex
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class PayloadSplitJoinTest {
|
||||||
|
private val random = Random(42)
|
||||||
|
|
||||||
|
@Test fun testSplitAndJoinBack() {
|
||||||
|
for (s in 0..250) {
|
||||||
|
val payload = ByteArray(s)
|
||||||
|
random.nextBytes(payload)
|
||||||
|
val splitter = PayloadSplitter(payload)
|
||||||
|
val packets = splitter.splitInPackets()
|
||||||
|
val joiner = PayloadJoiner(packets.get(0).asByteArray())
|
||||||
|
for (p in packets.subList(1, packets.size)) {
|
||||||
|
joiner.accumulate(p.asByteArray())
|
||||||
|
}
|
||||||
|
val got = joiner.finalize()
|
||||||
|
assertEquals(got.toHex(), payload.toHex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
||||||
|
|
||||||
|
import com.google.crypto.tink.subtle.Hex
|
||||||
|
import info.nightscout.androidaps.utils.extensions.toHex
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class PayloadSplitterTest {
|
||||||
|
@Test fun testSplitter() {
|
||||||
|
val f1 = "00,01,54,57,10,23,03,00,00,c0,ff,ff,ff,fe,08,20,2e,a8,50,30".replace(",", "")
|
||||||
|
val f2 = "01,04,bc,20,1f,f6,3d,00,01,a5,ff,ff,ff,fe,08,20,2e,a8,50,30".replace(",", "")
|
||||||
|
val payload = Hex.decode("54,57,10,23,03,00,00,c0,ff,ff,ff,fe,08,20,2e,a8,50,30,3d,00,01,a5".replace(",", ""))
|
||||||
|
|
||||||
|
val splitter = PayloadSplitter(payload)
|
||||||
|
val packets = splitter.splitInPackets()
|
||||||
|
|
||||||
|
assertEquals(packets.size, 2)
|
||||||
|
assertEquals(f1, packets.get(0).asByteArray().toHex())
|
||||||
|
val p2 = packets.get(1).asByteArray()
|
||||||
|
assertTrue(p2.size >= 10)
|
||||||
|
assertEquals(f2.subSequence(0, 20), p2.copyOfRange(0, 10).toHex())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
||||||
|
|
||||||
|
import com.google.crypto.tink.subtle.Hex
|
||||||
|
import info.nightscout.androidaps.utils.extensions.toHex
|
||||||
|
import org.junit.Assert.*
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class StringLengthPrefixEncodingTest {
|
||||||
|
private val p0Payload = Hex.decode("50,30,3d,00,01,a5".replace(",", "")) // from logs
|
||||||
|
private val p0Content = Hex.decode("a5")
|
||||||
|
|
||||||
|
@Test fun testFormatKeysP0() {
|
||||||
|
val payload = StringLengthPrefixEncoding.formatKeys(arrayOf("P0="), arrayOf(p0Content))
|
||||||
|
assertEquals(p0Payload.toHex(), payload.toHex())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun testParseKeysP0() {
|
||||||
|
val parsed = StringLengthPrefixEncoding.parseKeys(arrayOf("P0="), p0Payload)
|
||||||
|
assertEquals(parsed.size, 1)
|
||||||
|
assertEquals(parsed[0].toHex(), p0Content.toHex())
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair
|
||||||
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLoggerTest
|
import info.nightscout.androidaps.logging.AAPSLoggerTest
|
||||||
import info.nightscout.androidaps.utils.extensions.toHex
|
import info.nightscout.androidaps.utils.extensions.toHex
|
||||||
import org.junit.Assert
|
|
||||||
import org.junit.Assert.*
|
import org.junit.Assert.*
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.spongycastle.util.encoders.Hex
|
import org.spongycastle.util.encoders.Hex
|
||||||
|
|
Loading…
Reference in a new issue