user21300258
user21300258

Reputation:

How to check code integrity with SHA1 fingerprint?

I would like to check code integrity where where an attacker could modify an Android application package (APK) without proper authorization.

I have created functions that check SHA1, if it the same as mine from local.properties

    private fun checkIntegrity() {
        val expectedSignature = BuildConfig.PROD_SHA1_SIGNATURE

        if (integrityChecker.checkCodeIntegrity(expectedSignature)) {
        } else {
            nonFatalLogger.logNonFatal(Exception(integrityChecker.getErrorMessageIntegrity()))
            integrityChecker.finishApplication()
        }
    }
    fun checkCodeIntegrity(expectedSignature: String): Boolean {
        val actualSignature = getCertificateSHA1Fingerprint()
        return actualSignature == expectedSignature
    }
    private fun getCertificateSHA1Fingerprint(): String? {
        val pm: PackageManager = context.packageManager
        val packageName: String = context.packageName
        var signatures: Array<Signature>? = null

        try {
            signatures = with(pm) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                    getPackageInfoCompat(packageName, PackageManager.GET_SIGNING_CERTIFICATES)
                        .signingInfo
                        .apkContentsSigners
                } else {
                    getPackageInfoCompat(packageName, PackageManager.GET_SIGNATURES)
                        .signatures
                }
            }
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
        }
        val cert = signatures?.get(0)?.toByteArray()
        val input: InputStream = ByteArrayInputStream(cert)
        var cf: CertificateFactory? = null
        try {
            cf = CertificateFactory.getInstance("X509")
        } catch (e: CertificateException1) {
            e.printStackTrace()
        }
        var c: X509Certificate? = null
        try {
            c = cf?.generateCertificate(input) as X509Certificate
        } catch (e: CertificateException1) {
            e.printStackTrace()
        }
        var hexString: String? = null
        try {
            val md = MessageDigest.getInstance(SHA1_NAME)
            val publicKey = md.digest(c?.encoded)
            hexString = byte2HexFormatted(publicKey)
        } catch (e1: NoSuchAlgorithmException) {
            e1.printStackTrace()
        } catch (e: CertificateEncodingException) {
            e.printStackTrace()
        }
        return hexString
    }

Everything works fine, but when I create Signed Bundle/APK or generate my app on bitrise it goes to the else function finishApplication which means for me SHA1 is not the same as generated before? Why? I have generated SHA1 from my release-keystore or productionRelease build and it is correct, but after launch apk from Signed Bundle it is not and I quite do not understand that. Of course I could manage it, to lognotfatal error to firebase with my proper SHA1 from signed bundle apk, but first I would like to understand it and maybe instead of two SHA values in local.properties, use just one.

Upvotes: 0

Views: 113

Answers (0)

Related Questions