Shahbaz Hussain
Shahbaz Hussain

Reputation: 620

Android: Installed APK Certificate SHA-256 Fingerprint Mismatch with App's Certificate SHA-256 Fingerprint

In my Android project, I encountered a frustrating issue where the certificate fingerprint SHA-256 of the installed APK does not contain the SHA-256 fingerprint of the app's certificate for some users. This mismatch is causing problems with my app's functionality, and I'm not sure how to resolve it.

I've verified that the certificate and keystore used to sign the app are the same for all users. I've also ensured that I'm using the correct signing configuration.

Here's the code which I used to compare the SHA-256

// Get list of Installed APK's Signature's SHA-256
private fun getSignatures(): List<String>? {
    val packageInfo = getPackageInfo() ?: return null
    return try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            if (packageInfo.signingInfo == null) {
                return null
            }
            
            if (packageInfo.signingInfo.hasMultipleSigners()) {
                signatureDigest(packageInfo.signingInfo.apkContentsSigners)
            } else {
                signatureDigest(packageInfo.signingInfo.signingCertificateHistory)
            }
        } else {
            val signatures = packageInfo.signatures
            if (signatures.isNullOrEmpty() || signatures[0] == null) {
                null
            } else {
                signatureDigest(signatures)
            }
        }
    } catch (exception: PackageManager.NameNotFoundException) {
        Utility.sendException(exception)
        null
    }
}

private fun getPackageInfo(): PackageInfo? =
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        packageManager.getPackageInfo(
            PACKAGE_NAME,
            PackageManager.PackageInfoFlags.of(PackageManager.GET_SIGNING_CERTIFICATES.toLong())
        )
    } else {
        packageManager.getPackageInfo(
            PACKAGE_NAME,
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                PackageManager.GET_SIGNING_CERTIFICATES
            } else {
                PackageManager.GET_SIGNATURES
            }
        )
    }

// Method to create a list of SHA256 APK signatures
private fun signatureDigest(sigList: Array<Signature>?): List<String>? {
    if (sigList.isNullOrEmpty()) {
        return null
    }
    
    return mutableListOf<String>().also {
        sigList.forEach { signature ->
            it.add(getSignatureSha256(signature.toByteArray()))
        }
    }
}


private fun getSignatureSha256(certificate: ByteArray): String {
    val md: MessageDigest
    try {
        md = MessageDigest.getInstance("SHA256")
    } catch (exception: NoSuchAlgorithmException) {
        Utility.sendException(exception)
        return ""
    }
    
    md.update(certificate)
    return md.digest().joinToString(":") { String.format("%02x", it) }
}

// Test method to compare APK's fingerprint with the Public key of the signing credentials of the app
fun test(): Boolean {
    return getSignatures()?.contains(APP_SHA256)
}

This is working fine for all my test devices, but when I put this APK for some real users, it returned false for many of them, while also being successful for most of them. I don't think so these many users would be using a modified version of the app.

Has anyone else encountered this problem before, and if so, how did you resolve it? Any insights or suggestions would be greatly appreciated. Thank you!

Upvotes: 0

Views: 453

Answers (0)

Related Questions