ble/milenage: fix and add tests
This commit is contained in:
parent
099ec0a328
commit
9c42e5749f
|
@ -86,7 +86,7 @@ class EapAkaAttributeCustomIV(val payload: ByteArray) : EapAkaAttribute(
|
|||
) {
|
||||
|
||||
init {
|
||||
require(payload.size == 4) { "AT_RES payload size has to be 8 bytes. Payload: ${payload.toHex()}" }
|
||||
require(payload.size == 4) { "CUSTOM_IV payload size has to be 4 bytes. Payload: ${payload.toHex()}" }
|
||||
}
|
||||
|
||||
override fun toByteArray(): ByteArray {
|
||||
|
@ -97,4 +97,4 @@ class EapAkaAttributeCustomIV(val payload: ByteArray) : EapAkaAttribute(
|
|||
|
||||
private const val SIZE = (8 / SIZE_MULTIPLIER).toByte() // type, size, 2 reserved bytes, payload=4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session
|
|||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessagePacket
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageType
|
||||
import retrofit2.http.HEAD
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
enum class EapCode(val code: Byte) {
|
||||
|
@ -35,16 +34,17 @@ class EapAkaMessage(
|
|||
payload = payload,
|
||||
sequenceNumber = sequenceNumber,
|
||||
sas = true // TODO: understand why this is true for PairMessages
|
||||
)) {
|
||||
)
|
||||
) {
|
||||
|
||||
fun toByteArray(): ByteArray {
|
||||
|
||||
val serializedAttributes = attributes?.flatMap{ it.toByteArray().asIterable() }
|
||||
val serializedAttributes = attributes?.flatMap { it.toByteArray().asIterable() }
|
||||
val joinedAttributes = serializedAttributes?.toTypedArray()?.toByteArray()
|
||||
|
||||
val attrSize = joinedAttributes?.size ?: 0
|
||||
val totalSize = HEADER_SIZE + attrSize
|
||||
|
||||
|
||||
var bb = ByteBuffer
|
||||
.allocate(totalSize)
|
||||
.put(code.code)
|
||||
|
@ -53,7 +53,7 @@ class EapAkaMessage(
|
|||
.put((totalSize and 0XFF).toByte())
|
||||
.put(AKA_PACKET_TYPE)
|
||||
.put(SUBTYPE_AKA_CHALLENGE)
|
||||
.put(byteArrayOf(0,0))
|
||||
.put(byteArrayOf(0, 0))
|
||||
.put(joinedAttributes ?: ByteArray(0))
|
||||
|
||||
val ret = bb.array()
|
||||
|
@ -65,4 +65,4 @@ class EapAkaMessage(
|
|||
private const val SUBTYPE_AKA_CHALLENGE = 1.toByte()
|
||||
private const val AKA_PACKET_TYPE = 0x17.toByte()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import javax.crypto.spec.SecretKeySpec
|
|||
class Milenage(private val aapsLogger: AAPSLogger, private val k: ByteArray, val sqn: ByteArray, val _rand: ByteArray? = null) {
|
||||
init {
|
||||
require(k.size == KEY_SIZE) { "Milenage key has to be $KEY_SIZE bytes long. Received: ${k.toHex()}" }
|
||||
require(sqn.size == SEQ_SIZE) { "Milenage SEQ has to be $SEQ_SIZE long. Received: ${sqn.toHex()}" }
|
||||
require(sqn.size == SQN) { "Milenage SQN has to be $SQN long. Received: ${sqn.toHex()}" }
|
||||
}
|
||||
|
||||
private val secretKeySpec = SecretKeySpec(k, "AES")
|
||||
|
@ -31,45 +31,47 @@ class Milenage(private val aapsLogger: AAPSLogger, private val k: ByteArray, val
|
|||
}
|
||||
|
||||
private val opc = cipher.doFinal(MILENAGE_OP) xor MILENAGE_OP
|
||||
private val rand_opc_encrypted = cipher.doFinal(rand xor opc)
|
||||
private val rand_opc_encrypted_opc = rand_opc_encrypted xor opc
|
||||
private val randOpcEncrypted = cipher.doFinal(rand xor opc)
|
||||
private val randOpcEncryptedXorOpc = randOpcEncrypted xor opc
|
||||
private val resAkInput = randOpcEncryptedXorOpc.copyOfRange(0, KEY_SIZE)
|
||||
|
||||
init {
|
||||
rand_opc_encrypted_opc[15] = (rand_opc_encrypted_opc[15].toInt() xor 1).toByte()
|
||||
resAkInput[15] = (resAkInput[15].toInt() xor 1).toByte()
|
||||
}
|
||||
|
||||
private val res_ak = cipher.doFinal(rand_opc_encrypted_opc) xor opc
|
||||
private val resAk = cipher.doFinal(resAkInput) xor opc
|
||||
|
||||
val res = res_ak.copyOfRange(8, 16)
|
||||
val ak = res_ak.copyOfRange(0, 6)
|
||||
val res = resAk.copyOfRange(8, 16)
|
||||
private val ak = resAk.copyOfRange(0, 6)
|
||||
|
||||
private val ck_input = ByteArray(KEY_SIZE)
|
||||
private val ckInput = ByteArray(KEY_SIZE)
|
||||
|
||||
init {
|
||||
for (i in 0..15) {
|
||||
ck_input[(i + 12) % 16] = (rand_opc_encrypted[i].toInt() xor opc[i].toInt()).toByte()
|
||||
ckInput[(i + 12) % 16] = randOpcEncryptedXorOpc[i]
|
||||
}
|
||||
ck_input[15] = (ck_input[15].toInt() xor 2).toByte()
|
||||
ckInput[15] = (ckInput[15].toInt() xor 2).toByte()
|
||||
}
|
||||
|
||||
val ck = cipher.doFinal(ck_input) xor opc
|
||||
val ck = cipher.doFinal(ckInput) xor opc
|
||||
|
||||
private val sqnAmf = sqn + MILENAGE_AMF + sqn + MILENAGE_AMF
|
||||
private val sqnAmfXorOpc = sqnAmf xor opc
|
||||
private val macAInput = ByteArray(KEY_SIZE)
|
||||
|
||||
init {
|
||||
for (i in 0..15) {
|
||||
macAInput[(i + 8) % 16] = (rand_opc_encrypted[i].toInt() xor opc[i].toInt()).toByte()
|
||||
macAInput[(i + 8) % 16] = sqnAmfXorOpc[i]
|
||||
}
|
||||
}
|
||||
|
||||
private val macAFull = cipher.doFinal(macAInput xor opc)
|
||||
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
|
||||
|
||||
init {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage K: ${k.toHex()}")
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage RAND: ${rand.toHex()}")
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage SEQ: ${sqn.toHex()}")
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage SQN: ${sqn.toHex()}")
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage CK: ${ck.toHex()}")
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage AUTN: ${autn.toHex()}")
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Milenage RES: ${res.toHex()}")
|
||||
|
@ -83,7 +85,7 @@ class Milenage(private val aapsLogger: AAPSLogger, private val k: ByteArray, val
|
|||
private val MILENAGE_OP = Hex.decode("cdc202d5123e20f62b6d676ac72cb318")
|
||||
private val MILENAGE_AMF = Hex.decode("b9b9")
|
||||
private const val KEY_SIZE = 16
|
||||
private const val SEQ_SIZE = 6
|
||||
private const val SQN = 6
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,11 +15,39 @@ class MilenageTest {
|
|||
val m = Milenage(
|
||||
aapsLogger,
|
||||
Hex.decode("c0772899720972a314f557de66d571dd"),
|
||||
byteArrayOf(0,0,0,0,0,1),
|
||||
byteArrayOf(0,0,0,0,0,2),
|
||||
Hex.decode("c2cd1248451103bd77a6c7ef88c441ba")
|
||||
)
|
||||
Assert.assertEquals(m.ck.toHex(), "55799fd26664cbf6e476525e2dee52c6")
|
||||
Assert.assertEquals(m.res.toHex(), "a40bc6d13861447e")
|
||||
Assert.assertEquals(m.ck.toHex(), "55799fd26664cbf6e476525e2dee52c6")
|
||||
Assert.assertEquals(m.autn.toHex(), "00c55c78e8d3b9b9e935860a7259f6c0")
|
||||
}
|
||||
|
||||
@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")
|
||||
)
|
||||
Assert.assertEquals(m.res.toHex(), "ec549e00fa668a19")
|
||||
Assert.assertEquals(m.ck.toHex(), "ee3dac761fe358a9f476cc5ee81aa3e9")
|
||||
Assert.assertEquals(m.autn.toHex(), "a3e7a71430c8b9b95245b33b3bd679c4")
|
||||
}
|
||||
|
||||
@Test fun testMilenageIncrementedSQN() {
|
||||
val aapsLogger = AAPSLoggerTest()
|
||||
val m = Milenage(
|
||||
aapsLogger,
|
||||
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")
|
||||
)
|
||||
Assert.assertEquals(m.res.toHex(), "5f807a379a5c5d30")
|
||||
Assert.assertEquals(m.ck.toHex(), "8dd4b3ceb849a01766e37f9d86045c39")
|
||||
Assert.assertEquals(m.autn.toHex(), "0e0264d056fcb9b9752227365a090955")
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue