From c456d455ef9ad93960d32cbd7f3a43d2aa280a48 Mon Sep 17 00:00:00 2001 From: Christopher O'Grady Date: Thu, 9 Jan 2025 15:24:10 -0500 Subject: [PATCH] Implement Secrets Repository Add proto plugin and dependencies Create Secrets Proto Create Secrets Proto DataStore Replace old secrets with proto secrets Fix importers and tests to use new proto secrets. --- app/build.gradle.kts | 26 +++++++ .../nacabaro/vbhelper/di/AppContainer.kt | 2 + .../vbhelper/di/DefaultAppContainer.kt | 19 ++++- .../vbhelper/source/ApkSecretsImporter.kt | 3 +- .../source/DataStoreSecretsRepository.kt | 46 ++++++++++++ .../vbhelper/source/DexFileSecretsImporter.kt | 70 +++++++++---------- .../nacabaro/vbhelper/source/Secrets.kt | 9 --- .../vbhelper/source/SecretsImporter.kt | 3 +- .../vbhelper/source/SecretsRepository.kt | 11 +++ .../vbhelper/source/SecretsSerializer.kt | 24 +++++++ .../nacabaro/vbhelper/source/Secrets.proto | 19 +++++ .../vbhelper/source/ApkSecretsImporterTest.kt | 19 ++--- .../source/DexFileSecretsImporterTest.kt | 20 ++++-- build.gradle.kts | 6 ++ gradle/libs.versions.toml | 6 ++ 15 files changed, 221 insertions(+), 62 deletions(-) create mode 100644 app/src/main/java/com/github/nacabaro/vbhelper/source/DataStoreSecretsRepository.kt delete mode 100644 app/src/main/java/com/github/nacabaro/vbhelper/source/Secrets.kt create mode 100644 app/src/main/java/com/github/nacabaro/vbhelper/source/SecretsRepository.kt create mode 100644 app/src/main/java/com/github/nacabaro/vbhelper/source/SecretsSerializer.kt create mode 100644 app/src/main/proto/com/github/nacabaro/vbhelper/source/Secrets.proto diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1c2a848..784ff18 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -3,6 +3,7 @@ plugins { alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.compose) id("com.google.devtools.ksp") version "2.0.21-1.0.27" + id("com.google.protobuf") } android { @@ -38,6 +39,29 @@ android { buildFeatures { compose = true } + + lint { + baseline = file("lint-baseline.xml") + } +} + +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:4.27.0" + } + + // Generates the java Protobuf-lite code for the Protobufs in this project. See + // https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation + // for more information. + generateProtoTasks { + all().forEach { task -> + task.builtins { + create("java") { + option("lite") + } + } + } + } } dependencies { @@ -51,6 +75,7 @@ dependencies { implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.datastore) implementation(libs.androidx.ui) implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) @@ -64,5 +89,6 @@ dependencies { debugImplementation(libs.androidx.ui.test.manifest) implementation("androidx.navigation:navigation-compose:2.7.0") implementation("com.google.android.material:material:1.2.0") + implementation(libs.protobuf.javalite) implementation("androidx.compose.material:material") } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/di/AppContainer.kt b/app/src/main/java/com/github/nacabaro/vbhelper/di/AppContainer.kt index 239b946..bc447f2 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/di/AppContainer.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/di/AppContainer.kt @@ -1,7 +1,9 @@ package com.github.nacabaro.vbhelper.di import com.github.nacabaro.vbhelper.database.AppDatabase +import com.github.nacabaro.vbhelper.source.DataStoreSecretsRepository interface AppContainer { val db: AppDatabase + val dataStoreSecretsRepository: DataStoreSecretsRepository } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/di/DefaultAppContainer.kt b/app/src/main/java/com/github/nacabaro/vbhelper/di/DefaultAppContainer.kt index f83cfa8..e84819e 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/di/DefaultAppContainer.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/di/DefaultAppContainer.kt @@ -1,9 +1,22 @@ import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.dataStore import androidx.room.Room import com.github.nacabaro.vbhelper.database.AppDatabase import com.github.nacabaro.vbhelper.di.AppContainer +import com.github.nacabaro.vbhelper.source.DataStoreSecretsRepository +import com.github.nacabaro.vbhelper.source.SecretsSerializer +import com.github.nacabaro.vbhelper.source.proto.Secrets + +private const val SECRETS_DATA_STORE_NAME = "secrets.pb" + +val Context.secretsStore: DataStore by dataStore( + fileName = SECRETS_DATA_STORE_NAME, + serializer = SecretsSerializer +) class DefaultAppContainer(private val context: Context) : AppContainer { + override val db: AppDatabase by lazy { Room.databaseBuilder( context = context, @@ -11,4 +24,8 @@ class DefaultAppContainer(private val context: Context) : AppContainer { "internalDb" ).build() } -} \ No newline at end of file + + override val dataStoreSecretsRepository = DataStoreSecretsRepository(context.secretsStore) + +} + diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/source/ApkSecretsImporter.kt b/app/src/main/java/com/github/nacabaro/vbhelper/source/ApkSecretsImporter.kt index df63d20..e56d2a1 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/source/ApkSecretsImporter.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/source/ApkSecretsImporter.kt @@ -1,5 +1,6 @@ package com.github.nacabaro.vbhelper.source +import com.github.nacabaro.vbhelper.source.proto.Secrets import java.io.InputStream import java.util.zip.ZipInputStream @@ -10,7 +11,7 @@ class ApkSecretsImporter(private val dexFileSecretsImporter: SecretsImporter = D } // importSecrets imports the secrets from the apk input stream, and validates them. - override fun importSecrets(inputStream: InputStream): Map { + override fun importSecrets(inputStream: InputStream): Secrets { ZipInputStream(inputStream).use { zip -> var zipEntry = zip.nextEntry while(zipEntry != null) { diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/source/DataStoreSecretsRepository.kt b/app/src/main/java/com/github/nacabaro/vbhelper/source/DataStoreSecretsRepository.kt new file mode 100644 index 0000000..8d9ef96 --- /dev/null +++ b/app/src/main/java/com/github/nacabaro/vbhelper/source/DataStoreSecretsRepository.kt @@ -0,0 +1,46 @@ +package com.github.nacabaro.vbhelper.source + +import androidx.datastore.core.DataStore +import com.github.cfogrady.vbnfc.CryptographicTransformer +import com.github.cfogrady.vbnfc.data.DeviceType +import com.github.nacabaro.vbhelper.source.proto.Secrets +import com.github.nacabaro.vbhelper.source.proto.Secrets.HmacKeys +import kotlinx.coroutines.flow.single + +class DataStoreSecretsRepository( + private val secretsDataStore: DataStore, +): SecretsRepository { + override val secretsFlow = secretsDataStore.data + + override suspend fun updateSecrets(secrets: Secrets) { + secretsDataStore.updateData { + secrets + } + } + + override suspend fun getSecrets(): Secrets { + return secretsFlow.single() + } +} + +private fun Secrets.getHmacKeys(deviceTypeId: UShort): HmacKeys { + return when(deviceTypeId) { + DeviceType.VitalBraceletBEDeviceType -> this.beHmacKeys + DeviceType.VitalCharactersDeviceType -> this.vbcHmacKeys + DeviceType.VitalSeriesDeviceType -> this.vbdmHmacKeys + else -> throw IllegalArgumentException("Unknown DeviceTypeId") + } +} + +fun Secrets.getCryptographicTransformerMap(): Map { + val cipher = this.vbCipherList.toIntArray() + val beCipher = this.beCipherList.toIntArray() + val vbdmHmacKeys = this.getHmacKeys(DeviceType.VitalSeriesDeviceType) + val vbcHmacKeys = this.getHmacKeys(DeviceType.VitalCharactersDeviceType) + val beHmacKeys = this.getHmacKeys(DeviceType.VitalBraceletBEDeviceType) + return mapOf( + Pair(DeviceType.VitalSeriesDeviceType, CryptographicTransformer(vbdmHmacKeys.hmacKey1, vbdmHmacKeys.hmacKey2, this.aesKey, cipher)), + Pair(DeviceType.VitalCharactersDeviceType, CryptographicTransformer(vbcHmacKeys.hmacKey1, vbcHmacKeys.hmacKey2, this.aesKey, cipher)), + Pair(DeviceType.VitalBraceletBEDeviceType, CryptographicTransformer(beHmacKeys.hmacKey1, beHmacKeys.hmacKey2, this.aesKey, beCipher)), + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/source/DexFileSecretsImporter.kt b/app/src/main/java/com/github/nacabaro/vbhelper/source/DexFileSecretsImporter.kt index ca6f4e7..0b396e0 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/source/DexFileSecretsImporter.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/source/DexFileSecretsImporter.kt @@ -1,6 +1,9 @@ package com.github.nacabaro.vbhelper.source +import com.github.cfogrady.vbnfc.CryptographicTransformer import com.github.cfogrady.vbnfc.data.DeviceType +import com.github.nacabaro.vbhelper.source.proto.Secrets +import com.github.nacabaro.vbhelper.source.proto.Secrets.HmacKeys import java.io.InputStream import java.nio.ByteBuffer import java.nio.ByteOrder @@ -28,63 +31,58 @@ class DexFileSecretsImporter: SecretsImporter { const val VBC_TEST_TAG_PASSWORD = "a71dfb22" } - override fun importSecrets(inputStream: InputStream): Map { + override fun importSecrets(inputStream: InputStream): Secrets { val deviceToSecrets = readSecrets(inputStream) verifySecretCorrectness(deviceToSecrets) return deviceToSecrets } - private fun readSecrets(inputStream: InputStream): Map { + private fun readSecrets(inputStream: InputStream): Secrets { val dexFile = inputStream.readBytes() val byteOrder = ByteOrder.BIG_ENDIAN val vbdmSubstitutionCipher = dexFile.sliceArray(VBDM_SUBSTITUTION_CIPHER_IDX until VBDM_SUBSTITUTION_CIPHER_IDX+(16*4)).toIntArray(byteOrder) val beSubstitutionCipher = dexFile.sliceArray(BE_SUBSTITUTION_CIPHER_IDX until BE_SUBSTITUTION_CIPHER_IDX+(16*4)).toIntArray(byteOrder) val aesKey = dexFile.sliceArray(AES_KEY_IDX until AES_KEY_IDX+24).toString(StandardCharsets.UTF_8) - val secretsByDevices = mapOf( - Pair(DeviceType.VitalSeriesDeviceType, buildSecrets(dexFile, VBDM_HMAC_KEY_1_IDX, VBDM_HMAC_KEY_2_IDX, aesKey, vbdmSubstitutionCipher)), - Pair(DeviceType.VitalBraceletBEDeviceType, buildSecrets(dexFile, BE_HMAC_KEY_1_IDX, BE_HMAC_KEY_2_IDX, aesKey, beSubstitutionCipher)), - Pair(DeviceType.VitalCharactersDeviceType, buildSecrets(dexFile, VBC_HMAC_KEY_1_IDX, VBC_HMAC_KEY_2_IDX, aesKey, vbdmSubstitutionCipher)), - ) - return secretsByDevices + return Secrets.newBuilder() + .setAesKey(aesKey) + .addAllVbCipher(vbdmSubstitutionCipher.toList()) + .addAllBeCipher(beSubstitutionCipher.toList()) + .setVbdmHmacKeys(getHmac(dexFile, VBDM_HMAC_KEY_1_IDX, VBDM_HMAC_KEY_2_IDX)) + .setVbcHmacKeys(getHmac(dexFile, VBC_HMAC_KEY_1_IDX, VBC_HMAC_KEY_2_IDX)) + .setBeHmacKeys(getHmac(dexFile, BE_HMAC_KEY_1_IDX, BE_HMAC_KEY_2_IDX)) + .build() } - private fun buildSecrets(dexFile: ByteArray, hmacKeyIdx1: Int, hmacKeyIdx2: Int, aesKey: String, substitutionCipher: IntArray): Secrets { + private fun getHmac(dexFile: ByteArray, hmacKeyIdx1: Int, hmacKeyIdx2: Int): HmacKeys { val hmacKey1 = dexFile.sliceArray(hmacKeyIdx1 until hmacKeyIdx1+24).toString(StandardCharsets.UTF_8) val hmacKey2 = dexFile.sliceArray(hmacKeyIdx2 until hmacKeyIdx2+24).toString(StandardCharsets.UTF_8) - return Secrets(hmacKey1, hmacKey2, aesKey, substitutionCipher) + return HmacKeys.newBuilder() + .setHmacKey1(hmacKey1) + .setHmacKey2(hmacKey2) + .build() } @OptIn(ExperimentalStdlibApi::class) - private fun verifySecretCorrectness(deviceToSecrets: Map) { - for (keyValue in deviceToSecrets) { + private fun verifySecretCorrectness(secrets: Secrets) { + val deviceToCryptographicTransformers = secrets.getCryptographicTransformerMap() + for (keyValue in deviceToCryptographicTransformers) { when(keyValue.key) { - DeviceType.VitalBraceletBEDeviceType -> { - val result = keyValue.value.toCryptographicTransformer().createNfcPassword( - TEST_TAG - ) - if( result.toHexString() != BE_TEST_TAG_PASSWORD) { - throw InvalidKeyException("Secrets were loaded, but were unsuccessful at generating the test password: ${result.toHexString()}") - } - } - DeviceType.VitalCharactersDeviceType -> { - val result = keyValue.value.toCryptographicTransformer().createNfcPassword( - TEST_TAG - ) - if( result.toHexString() != VBC_TEST_TAG_PASSWORD) { - throw InvalidKeyException("Secrets were loaded, but were unsuccessful at generating the test password: ${result.toHexString()}") - } - } - DeviceType.VitalSeriesDeviceType -> { - val result = keyValue.value.toCryptographicTransformer().createNfcPassword( - TEST_TAG - ) - if( result.toHexString() != VBDM_TEST_TAG_PASSWORD) { - throw InvalidKeyException("Secrets were loaded, but were unsuccessful at generating the test password: ${result.toHexString()}") - } - } + DeviceType.VitalBraceletBEDeviceType -> assertBuildsCorrectPassword(keyValue.value, BE_TEST_TAG_PASSWORD) + DeviceType.VitalCharactersDeviceType -> assertBuildsCorrectPassword(keyValue.value, VBC_TEST_TAG_PASSWORD) + DeviceType.VitalSeriesDeviceType -> assertBuildsCorrectPassword(keyValue.value, VBDM_TEST_TAG_PASSWORD) } } } + + @OptIn(ExperimentalStdlibApi::class) + private fun assertBuildsCorrectPassword(cryptographicTransformer: CryptographicTransformer, expectedPassword: String) { + val result = cryptographicTransformer.createNfcPassword( + TEST_TAG + ) + if( result.toHexString() != expectedPassword) { + throw InvalidKeyException("Secrets were loaded, but were unsuccessful at generating the test password") + } + } } fun ByteArray.toIntArray(byteOrder: ByteOrder): IntArray { diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/source/Secrets.kt b/app/src/main/java/com/github/nacabaro/vbhelper/source/Secrets.kt deleted file mode 100644 index 485a670..0000000 --- a/app/src/main/java/com/github/nacabaro/vbhelper/source/Secrets.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.github.nacabaro.vbhelper.source - -import com.github.cfogrady.vbnfc.CryptographicTransformer - -data class Secrets(val hmacKey1: String, val hmacKey2: String, val aesKey: String, val substitutionCipher: IntArray) { - fun toCryptographicTransformer(): CryptographicTransformer { - return CryptographicTransformer(hmacKey1, hmacKey2, aesKey, substitutionCipher) - } -} diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/source/SecretsImporter.kt b/app/src/main/java/com/github/nacabaro/vbhelper/source/SecretsImporter.kt index e1a8e77..544afb6 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/source/SecretsImporter.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/source/SecretsImporter.kt @@ -1,7 +1,8 @@ package com.github.nacabaro.vbhelper.source +import com.github.nacabaro.vbhelper.source.proto.Secrets import java.io.InputStream fun interface SecretsImporter { - fun importSecrets(inputStream: InputStream): Map + fun importSecrets(inputStream: InputStream): Secrets } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/source/SecretsRepository.kt b/app/src/main/java/com/github/nacabaro/vbhelper/source/SecretsRepository.kt new file mode 100644 index 0000000..dce522c --- /dev/null +++ b/app/src/main/java/com/github/nacabaro/vbhelper/source/SecretsRepository.kt @@ -0,0 +1,11 @@ +package com.github.nacabaro.vbhelper.source + +import com.github.nacabaro.vbhelper.source.proto.Secrets +import kotlinx.coroutines.flow.Flow + +interface SecretsRepository { + val secretsFlow: Flow + + suspend fun getSecrets(): Secrets + suspend fun updateSecrets(secrets: Secrets) +} \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/source/SecretsSerializer.kt b/app/src/main/java/com/github/nacabaro/vbhelper/source/SecretsSerializer.kt new file mode 100644 index 0000000..9c4df68 --- /dev/null +++ b/app/src/main/java/com/github/nacabaro/vbhelper/source/SecretsSerializer.kt @@ -0,0 +1,24 @@ +package com.github.nacabaro.vbhelper.source + +import androidx.datastore.core.CorruptionException +import androidx.datastore.core.Serializer +import com.github.nacabaro.vbhelper.source.proto.Secrets +import com.google.protobuf.InvalidProtocolBufferException +import java.io.InputStream +import java.io.OutputStream + +object SecretsSerializer: Serializer { + override val defaultValue = Secrets.getDefaultInstance() + + override suspend fun readFrom(input: InputStream): Secrets { + try { + return Secrets.parseFrom(input) + } catch (exception: InvalidProtocolBufferException) { + throw CorruptionException("Cannot read proto.", exception) + } + } + + override suspend fun writeTo(t: Secrets, output: OutputStream) { + t.writeTo(output) + } +} \ No newline at end of file diff --git a/app/src/main/proto/com/github/nacabaro/vbhelper/source/Secrets.proto b/app/src/main/proto/com/github/nacabaro/vbhelper/source/Secrets.proto new file mode 100644 index 0000000..b389d59 --- /dev/null +++ b/app/src/main/proto/com/github/nacabaro/vbhelper/source/Secrets.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +option java_package = "com.github.nacabaro.vbhelper.source.proto"; +option java_multiple_files = true; + +message Secrets { + string aes_key = 1; + repeated int32 vb_cipher = 2; + repeated int32 be_cipher = 3; + + message HmacKeys { + string hmac_key_1 = 1; + string hmac_key_2 = 2; + } + HmacKeys vbdm_hmac_keys = 4; + HmacKeys vbc_hmac_keys = 5; + HmacKeys be_hmac_keys = 6; + +} \ No newline at end of file diff --git a/app/src/test/java/com/github/nacabaro/vbhelper/source/ApkSecretsImporterTest.kt b/app/src/test/java/com/github/nacabaro/vbhelper/source/ApkSecretsImporterTest.kt index 19177f2..82babc5 100644 --- a/app/src/test/java/com/github/nacabaro/vbhelper/source/ApkSecretsImporterTest.kt +++ b/app/src/test/java/com/github/nacabaro/vbhelper/source/ApkSecretsImporterTest.kt @@ -1,6 +1,6 @@ package com.github.nacabaro.vbhelper.source -import com.github.cfogrady.vbnfc.data.DeviceType +import com.github.nacabaro.vbhelper.source.proto.Secrets import org.junit.Assert import org.junit.Test import java.io.ByteArrayInputStream @@ -14,15 +14,18 @@ import java.util.zip.ZipOutputStream class ApkSecretsImporterTest { @Test - fun testThatRealImportSecretsHasAllDeviceTypes() { + fun testThatRealImportSecretsPasses() { val apkFileSecretsImporter = ApkSecretsImporter() val url = getAndAssertApkFile() val file = File(url.path) file.inputStream().use { - val deviceIdToSecrets = apkFileSecretsImporter.importSecrets(it) - Assert.assertNotNull("BE Device Type", deviceIdToSecrets[DeviceType.VitalBraceletBEDeviceType]) - Assert.assertNotNull("VBDM Device Type", deviceIdToSecrets[DeviceType.VitalSeriesDeviceType]) - Assert.assertNotNull("VBC Device Type", deviceIdToSecrets[DeviceType.VitalCharactersDeviceType]) + val secrets = apkFileSecretsImporter.importSecrets(it) + Assert.assertEquals("Cipher size isn't correct", 16, secrets.vbCipherCount) + Assert.assertEquals("BE Cipher size isn't correct", 16, secrets.beCipherCount) + Assert.assertFalse("AES Key is empty", secrets.aesKey.isEmpty()) + assertHmacKeysArePopulated("VBDM", secrets.vbdmHmacKeys) + assertHmacKeysArePopulated("VBC", secrets.vbcHmacKeys) + assertHmacKeysArePopulated("BE", secrets.beHmacKeys) } } @@ -34,7 +37,7 @@ class ApkSecretsImporterTest { val inputStreamContents = it.readAllBytes() Assert.assertTrue("Unexpected file contents received by DexSecretsImporter", inputStreamContents.contentEquals(expectedDexContents)) foundFile = true - emptyMap() + Secrets.newBuilder().build() } val apkBytes = constructTestApk(expectedDexContents) ByteArrayInputStream(apkBytes).use { @@ -70,4 +73,4 @@ class ApkSecretsImporterTest { } return url!! } -} \ No newline at end of file +} diff --git a/app/src/test/java/com/github/nacabaro/vbhelper/source/DexFileSecretsImporterTest.kt b/app/src/test/java/com/github/nacabaro/vbhelper/source/DexFileSecretsImporterTest.kt index e58dfe1..ca2f2b7 100644 --- a/app/src/test/java/com/github/nacabaro/vbhelper/source/DexFileSecretsImporterTest.kt +++ b/app/src/test/java/com/github/nacabaro/vbhelper/source/DexFileSecretsImporterTest.kt @@ -1,6 +1,6 @@ package com.github.nacabaro.vbhelper.source -import com.github.cfogrady.vbnfc.data.DeviceType +import com.github.nacabaro.vbhelper.source.proto.Secrets.HmacKeys import org.junit.Assert import org.junit.Test import java.io.ByteArrayInputStream @@ -10,18 +10,26 @@ import java.nio.ByteOrder import java.security.InvalidKeyException +fun assertHmacKeysArePopulated(msg: String, hmacKeys: HmacKeys) { + Assert.assertFalse("$msg hmacKey1 is empty", hmacKeys.hmacKey1.isEmpty()) + Assert.assertFalse("$msg hmacKey2 is empty", hmacKeys.hmacKey2.isEmpty()) +} + class DexFileSecretsImporterTest { @Test - fun testThatImportSecretsHasAllDeviceTypes() { + fun testThatImportSecretsIsPopulated() { val dexFileSecretsImporter = DexFileSecretsImporter() val url = getAndAssertClassesDexFile() val file = File(url.path) file.inputStream().use { - val deviceIdToSecrets = dexFileSecretsImporter.importSecrets(it) - Assert.assertNotNull("BE Device Type", deviceIdToSecrets[DeviceType.VitalBraceletBEDeviceType]) - Assert.assertNotNull("VBDM Device Type", deviceIdToSecrets[DeviceType.VitalSeriesDeviceType]) - Assert.assertNotNull("VBC Device Type", deviceIdToSecrets[DeviceType.VitalCharactersDeviceType]) + val secrets = dexFileSecretsImporter.importSecrets(it) + Assert.assertEquals("Cipher size isn't correct", 16, secrets.vbCipherCount) + Assert.assertEquals("BE Cipher size isn't correct", 16, secrets.beCipherCount) + Assert.assertFalse("AES Key is empty", secrets.aesKey.isEmpty()) + assertHmacKeysArePopulated("VBDM", secrets.vbdmHmacKeys) + assertHmacKeysArePopulated("VBC", secrets.vbcHmacKeys) + assertHmacKeysArePopulated("BE", secrets.beHmacKeys) } } diff --git a/build.gradle.kts b/build.gradle.kts index 952b930..1662ff3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,4 +3,10 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.compose) apply false +} + +buildscript { + dependencies { + classpath(libs.protobuf.gradle.plugin) + } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8036069..2186327 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,6 @@ [versions] agp = "8.7.3" +datastore = "1.1.1" kotlin = "2.0.0" coreKtx = "1.15.0" junit = "4.13.2" @@ -8,12 +9,15 @@ espressoCore = "3.6.1" lifecycleRuntimeKtx = "2.8.7" activityCompose = "1.9.3" composeBom = "2024.04.01" +protobufGradlePlugin = "0.9.4" +protobufJavalite = "4.27.0" roomRuntime = "2.6.1" vbNfcReader = "0.1.0" dimReader = "2.1.0" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" } androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "roomRuntime" } androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "roomRuntime" } junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -29,6 +33,8 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" } +protobuf-gradle-plugin = { module = "com.google.protobuf:protobuf-gradle-plugin", version.ref = "protobufGradlePlugin" } +protobuf-javalite = { module = "com.google.protobuf:protobuf-javalite", version.ref = "protobufJavalite" } vb-nfc-reader = { module = "com.github.cfogrady:vb-nfc-reader", version.ref = "vbNfcReader" } dim-reader = { module = "com.github.cfogrady:vb-dim-reader", version.ref = "dimReader" }