mirror of
https://github.com/nacabaro/vbhelper.git
synced 2026-10-01 07:31:37 +00:00
Verify Secret correctness as part of loading.
Improve tests
This commit is contained in:
@@ -3,13 +3,14 @@ package com.github.nacabaro.vbhelper.source
|
||||
import java.io.InputStream
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
class ApkSecretsImporter(private val dexFileSecretsImporter: DexFileSecretsImporter = DexFileSecretsImporter()) {
|
||||
class ApkSecretsImporter(private val dexFileSecretsImporter: SecretsImporter = DexFileSecretsImporter()): SecretsImporter {
|
||||
|
||||
companion object {
|
||||
const val DEX_FILE = "classes.dex"
|
||||
}
|
||||
|
||||
fun importSecrets(inputStream: InputStream): Map<UShort, Secrets> {
|
||||
// importSecrets imports the secrets from the apk input stream, and validates them.
|
||||
override fun importSecrets(inputStream: InputStream): Map<UShort, Secrets> {
|
||||
ZipInputStream(inputStream).use { zip ->
|
||||
var zipEntry = zip.nextEntry
|
||||
while(zipEntry != null) {
|
||||
|
||||
@@ -5,9 +5,10 @@ import java.io.InputStream
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.security.InvalidKeyException
|
||||
|
||||
|
||||
class DexFileSecretsImporter {
|
||||
class DexFileSecretsImporter: SecretsImporter {
|
||||
companion object {
|
||||
|
||||
const val VBDM_SUBSTITUTION_CIPHER_IDX = 1080145
|
||||
@@ -20,20 +21,31 @@ class DexFileSecretsImporter {
|
||||
const val BE_HMAC_KEY_1_IDX = 1580157
|
||||
const val BE_HMAC_KEY_2_IDX = 1593759
|
||||
const val AES_KEY_IDX = 1277527
|
||||
|
||||
val TEST_TAG = byteArrayOf(0x34, 0x01, 0x10, 0xff.toByte(), 0xf5.toByte(), 0x00, 0xa2.toByte())
|
||||
const val BE_TEST_TAG_PASSWORD = "be29a87e"
|
||||
const val VBDM_TEST_TAG_PASSWORD = "6ea33673"
|
||||
const val VBC_TEST_TAG_PASSWORD = "a71dfb22"
|
||||
}
|
||||
|
||||
fun importSecrets(inputStream: InputStream): Map<UShort, Secrets> {
|
||||
override fun importSecrets(inputStream: InputStream): Map<UShort, Secrets> {
|
||||
val deviceToSecrets = readSecrets(inputStream)
|
||||
verifySecretCorrectness(deviceToSecrets)
|
||||
return deviceToSecrets
|
||||
}
|
||||
|
||||
private fun readSecrets(inputStream: InputStream): Map<UShort, 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 cryptographicTransformerByDevices = mapOf(
|
||||
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 cryptographicTransformerByDevices
|
||||
return secretsByDevices
|
||||
}
|
||||
|
||||
private fun buildSecrets(dexFile: ByteArray, hmacKeyIdx1: Int, hmacKeyIdx2: Int, aesKey: String, substitutionCipher: IntArray): Secrets {
|
||||
@@ -41,6 +53,38 @@ class DexFileSecretsImporter {
|
||||
val hmacKey2 = dexFile.sliceArray(hmacKeyIdx2 until hmacKeyIdx2+24).toString(StandardCharsets.UTF_8)
|
||||
return Secrets(hmacKey1, hmacKey2, aesKey, substitutionCipher)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private fun verifySecretCorrectness(deviceToSecrets: Map<UShort, Secrets>) {
|
||||
for (keyValue in deviceToSecrets) {
|
||||
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()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ByteArray.toIntArray(byteOrder: ByteOrder): IntArray {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.github.nacabaro.vbhelper.source
|
||||
|
||||
import java.io.InputStream
|
||||
|
||||
fun interface SecretsImporter {
|
||||
fun importSecrets(inputStream: InputStream): Map<UShort, Secrets>
|
||||
}
|
||||
Reference in New Issue
Block a user