diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/KeyExchange.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/KeyExchange.kt index 90130a29f0..682098e295 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/KeyExchange.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/KeyExchange.kt @@ -1,39 +1,36 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair -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 import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.MessageIOException +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.RandomByteGenerator +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.X25519KeyGenerator import info.nightscout.androidaps.utils.extensions.toHex import org.spongycastle.crypto.engines.AESEngine import org.spongycastle.crypto.macs.CMac import org.spongycastle.crypto.params.KeyParameter -import java.security.SecureRandom +import org.spongycastle.util.encoders.Hex class KeyExchange( private val aapsLogger: AAPSLogger, - var pdmPrivate: ByteArray = X25519.generatePrivateKey(), - val pdmNonce: ByteArray = ByteArray(NONCE_SIZE) -) { - val pdmPublic = X25519.publicFromPrivate(pdmPrivate) + private val x25519: X25519KeyGenerator, + private val randomByteGenerator: RandomByteGenerator +){ + + val pdmNonce: ByteArray = randomByteGenerator.nextBytes(NONCE_SIZE) + val pdmPrivate: ByteArray = x25519.generatePrivateKey() + val pdmPublic = x25519.publicFromPrivate(pdmPrivate) var podPublic = ByteArray(PUBLIC_KEY_SIZE) - var podNonce = ByteArray(NONCE_SIZE) + private set + var podNonce : ByteArray = ByteArray(NONCE_SIZE) val podConf = ByteArray(CMAC_SIZE) val pdmConf = ByteArray(CMAC_SIZE) var ltk = ByteArray(CMAC_SIZE) - init { - if (pdmNonce.all { it == 0.toByte() }) { - // pdmNonce is in the constructor for tests - val random = SecureRandom() - random.nextBytes(pdmNonce) - } - } - fun updatePodPublicData(payload: ByteArray) { if (payload.size != PUBLIC_KEY_SIZE + NONCE_SIZE) { throw MessageIOException("Invalid payload size") @@ -54,7 +51,7 @@ class KeyExchange( } private fun generateKeys() { - val curveLTK = X25519.computeSharedSecret(pdmPrivate, podPublic) + val curveLTK = x25519.computeSharedSecret(pdmPrivate, podPublic) val firstKey = podPublic.copyOfRange(podPublic.size - 4, podPublic.size) + pdmPublic.copyOfRange(pdmPublic.size - 4, pdmPublic.size) + diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt index a7f8349aec..f30f7e5c6a 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt @@ -8,6 +8,8 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message. import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessagePacket import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.StringLengthPrefixEncoding import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.StringLengthPrefixEncoding.Companion.parseKeys +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.RandomByteGenerator +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.X25519KeyGenerator import info.nightscout.androidaps.utils.extensions.hexStringToByteArray import info.nightscout.androidaps.utils.extensions.toHex @@ -19,7 +21,7 @@ internal class LTKExchanger( val podAddress: Id ) { - private val keyExchange = KeyExchange(aapsLogger) + private val keyExchange = KeyExchange(aapsLogger, X25519KeyGenerator(), RandomByteGenerator()) private var seq: Byte = 1 fun negotiateLTK(): PairResult { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/RandomByteGenerator.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/RandomByteGenerator.kt new file mode 100644 index 0000000000..f20fdcca21 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/RandomByteGenerator.kt @@ -0,0 +1,9 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util + +import java.security.SecureRandom + +open class RandomByteGenerator { + private val secureRandom = SecureRandom() + + open fun nextBytes(length: Int): ByteArray = ByteArray(length).also(secureRandom::nextBytes) +} \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/X25519KeyGenerator.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/X25519KeyGenerator.kt new file mode 100644 index 0000000000..dbd15ba799 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/X25519KeyGenerator.kt @@ -0,0 +1,11 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util + +import com.google.crypto.tink.subtle.X25519 + +open class X25519KeyGenerator { + + open fun generatePrivateKey(): ByteArray = X25519.generatePrivateKey() + fun publicFromPrivate(privateKey: ByteArray): ByteArray = X25519.publicFromPrivate(privateKey) + fun computeSharedSecret(privateKey: ByteArray, publicKey: ByteArray): ByteArray = + X25519.computeSharedSecret(privateKey, publicKey) +} \ No newline at end of file diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/KeyExchangeTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/KeyExchangeTest.kt index 51d4bca126..0dc0135541 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/KeyExchangeTest.kt +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/KeyExchangeTest.kt @@ -1,18 +1,38 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair import info.nightscout.androidaps.logging.AAPSLoggerTest +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.RandomByteGenerator +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.X25519KeyGenerator import info.nightscout.androidaps.utils.extensions.toHex -import org.junit.Assert.* +import org.junit.Assert.assertEquals import org.junit.Test +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Mockito +import org.mockito.Mockito.mock +import org.mockito.Mockito.spy import org.spongycastle.util.encoders.Hex class KeyExchangeTest { + + val keyGenerator = X25519KeyGenerator() + val keyGeneratorSpy = spy(keyGenerator) + + var randomByteGenerator: RandomByteGenerator = mock(RandomByteGenerator::class.java) + @Test fun testLTK() { val aapsLogger = AAPSLoggerTest() + + Mockito.doReturn(Hex.decode("27ec94b71a201c5e92698d668806ae5ba00594c307cf5566e60c1fc53a6f6bb6")) + .`when`(keyGeneratorSpy).generatePrivateKey() + + val pdmNonce = Hex.decode("edfdacb242c7f4e1d2bc4d93ca3c5706") + + Mockito.`when`(randomByteGenerator.nextBytes(anyInt())).thenReturn(pdmNonce) + val ke = KeyExchange( aapsLogger, - pdmPrivate = Hex.decode("27ec94b71a201c5e92698d668806ae5ba00594c307cf5566e60c1fc53a6f6bb6"), - pdmNonce = Hex.decode("edfdacb242c7f4e1d2bc4d93ca3c5706") + keyGeneratorSpy, + randomByteGenerator ) val podPublicKey = Hex.decode("2fe57da347cd62431528daac5fbb290730fff684afc4cfc2ed90995f58cb3b74") val podNonce = Hex.decode("00000000000000000000000000000000") @@ -22,4 +42,4 @@ class KeyExchangeTest { ke.validatePodConf(Hex.decode("af4f10db5f96e5d9cd6cfc1f54f4a92f")) assertEquals(ke.ltk.toHex(), "341e16d13f1cbf73b19d1c2964fee02b") } -} +} \ No newline at end of file