KeyStoreException:尝试解密时签名/ MAC验证失败

时间:2019-04-13 12:17:29

标签: android encryption kotlin keystore android-keystore

我正在尝试创建一个简单的Kotlin对象,该对象通过在保存内容之前对其进行加密来包装对应用程序共享首选项的访问。

加密似乎可以正常工作,但是当我尝试解密时,我收到一个javax.crypto.AEADBadTagException,它从“ android.security.KeyStoreException:签名/ MAC验证失败”触发。

我尝试调试以了解潜在的问题,但找不到任何东西。没有任何搜索给我任何线索,我似乎遵循了这封信的一些指南,但没有成功。

private val context: Context?
    get() = this.application?.applicationContext
private var application: Application? = null

private val transformation = "AES/GCM/NoPadding"
private val androidKeyStore = "AndroidKeyStore"
private val ivPrefix = "_iv"
private val keyStore by lazy { this.createKeyStore() }

private fun createKeyStore(): KeyStore {
    val keyStore = KeyStore.getInstance(this.androidKeyStore)
    keyStore.load(null)
    return keyStore
}

private fun createSecretKey(alias: String): SecretKey {
    val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, this.androidKeyStore)

    keyGenerator.init(
        KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
            .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
            .build()
    )

    return keyGenerator.generateKey()
}

private fun getSecretKey(alias: String): SecretKey {
    return if (this.keyStore.containsAlias(alias)) {
        (this.keyStore.getEntry(alias, null) as KeyStore.SecretKeyEntry).secretKey
    } else {
        this.createSecretKey(alias)
    }
}

private fun removeSecretKey(alias: String) {
    this.keyStore.deleteEntry(alias)
}

private fun encryptText(alias: String, textToEncrypt: String): String {
    val cipher = Cipher.getInstance(this.transformation)
    cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(alias))

    val ivString = Base64.encodeToString(cipher.iv, Base64.DEFAULT)
    this.storeInSharedPrefs(alias + this.ivPrefix, ivString)

    val byteArray = cipher.doFinal(textToEncrypt.toByteArray(charset("UTF-8")))
    return String(byteArray)
}

private fun decryptText(alias: String, textToDecrypt: String): String? {
    val ivString = this.retrieveFromSharedPrefs(alias + this.ivPrefix) ?: return null

    val iv = Base64.decode(ivString, Base64.DEFAULT)
    val spec = GCMParameterSpec(iv.count() * 8, iv)
    val cipher = Cipher.getInstance(this.transformation)
    cipher.init(Cipher.DECRYPT_MODE, getSecretKey(alias), spec)

    try {
        val byteArray = cipher.doFinal(textToDecrypt.toByteArray(charset("UTF-8")))
        return String(byteArray)
    } catch (e: Exception) {
        e.printStackTrace()
        return null
    }
}

private fun storeInSharedPrefs(key: String, value: String) {
    this.context?.let {
        PreferenceManager.getDefaultSharedPreferences(it).edit()?.putString(key, value)?.apply()
    }
}

private fun retrieveFromSharedPrefs(key: String): String? {
    val validContext = this.context ?: return null
    return PreferenceManager.getDefaultSharedPreferences(validContext).getString(key, null)
}

谁能指出我正确的方向?

2 个答案:

答案 0 :(得分:1)

我遇到了类似的问题。一切都是关于android:allowBackup="true"

问题:

卸载应用程序然后重新安装时会出现此问题。 KeyStore 将在卸载时被清除,但首选项不会被删除,因此最终会尝试使用新密钥进行解密,从而引发异常。

解决方案:

尝试禁用 android:allowBackup

<application android:allowBackup="false" ... >

答案 1 :(得分:0)

将身份验证标签的长度从iv.count()更改为128时,它将起作用。