簡體   English   中英

使用 KeyStore 私鑰和 iv 加密和解密“有時”出錯

[英]Encryption and Decryption with KeyStore private key and iv goes wrong “Some times”

我正在像這樣使用 KeyStore 的加密和解密。

這就是流量。 在我將字符串傳遞給加密方法后,我同時保存了加密和 iv,以便我以后可以用它檢索值。問題是有時,某些加密值無法正確檢索......不是全部。 所以認為我加密了 10 個項目並將它們保存在某個地方(加密和 iv)。 然后,當我想檢索其中一個時,無法正確檢索!

 init {
        keyStore = KeyStore.getInstance(ANDROID_KEY_STORE)
        keyStore.load(null)
        cipher = Cipher.getInstance("AES/GCM/NoPadding")
    }

  fun encryptData(text: String): Pair<ByteArray, String>? {
        try {
            cipher.init(Cipher.ENCRYPT_MODE, getSecretKet(ALIAS))
            val iv = cipher.iv.toString(Charsets.ISO_8859_1)
            val result = cipher.doFinal(text.toByteArray(Charsets.ISO_8859_1))
            Timber.i("$TAG encrypted data $result")
            Timber.i("$TAG encrypted iv $iv")
            return if (result != null) {
                Pair(result, iv)
            } else {
                null
            }
        } catch (e: Exception) {
            Timber.e("$TAG error encryptData", e)
            return null
        }
    }

fun decryptData(encryptedData: ByteArray, iv: ByteArray): String {
    return try {
        val spec = GCMParameterSpec(128, iv)
        cipher.init(Cipher.DECRYPT_MODE, getSecretKet(ALIAS), spec)
        val result = cipher.doFinal(encryptedData).toString(Charsets.ISO_8859_1)
        Timber.i("$TAG decrypted data $result")
        result
    } catch (e: Exception) {
        Timber.e("$TAG decryptData error may string was not encrypted", e)
        encryptedData.toString()
    }
}

這是為了獲取密鑰。 首先我認為我的密鑰可能有問題,所以我以這種方式實現了它,這個 class 是單音的。 但是有些時候我重新打開應用程序時,這個密鑰是不一樣的(我認為,因為 iv 和加密值以及密碼都是固定的)。 我也使用Charsets.ISO_8859_1因為發現這個字符集更好地保留所有字符並且丟失更少。 然后我認為可能是保存位置的問題,所以為了測試,我只是從帶有字符串字段的 Room db 移動到帶有字符串的 SharePref。 但是問題是一樣的,所以現在我很確定這與 savig 存儲庫無關。

private fun getSecretKet(alias: String): Key {

    if (keyStore.containsAlias(alias)) {
        //Try for existing key
        return keyStore.getKey(alias, null)
    } else {
        //Key is not present, create new one.
        val keyGenerator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val kGenerator =
                KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE)
            val specs = KeyGenParameterSpec
                .Builder(
                    alias,
                    KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
                )
                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                .build()
            kGenerator.init(specs)
            kGenerator
        } else {
            KeyGenerator.getInstance(ANDROID_KEY_STORE);
        }
        return keyGenerator.generateKey()
    }
}

我認為這很有效,但最終我無法獲得我上面提到的一些加密數據。 任何機構有任何想法?

我最終通過 go 解決了這個問題,更深入地了解了 AES 更改的實現。

  1. 最主要的是IV 簡而言之,IV 是一種使加密更加復雜的工具,我們創建一個 IV 並將其傳遞給密碼。 cipher 在多輪和字節塊中加密數據和混合字節,並且在每一輪中,它都會用邏輯更新 IV 並將其用於下一輪或字節塊。 因此,如果您在完成加密后從密碼中獲得 IV,您將看到它發生了變化!
  2. 第二件事是我使用了 imelemneted cipher singleTone 但我改變了它的創建加密和解密方法本身。 因此,每個用於編碼的字符串都會有新的 IV,並且在編碼完成后,我將它與加密字符串一起傳遞給以后的解密。

首先,我認為它將在@PresidentJamesMovelenPolk 的幫助下從字符串加密中進行,但我測試了即使使用 ISO_8859_1 也能很好地使用這種實施方式。 這是最終的實現:

 companion object {
    const val TRANSFORMATION = "AES/GCM/NoPadding"
    const val ANDROID_KEY_STORE = "AndroidKeyStore"
    const val ALIAS = "MyApp"
    const val TAG = "KeyStoreManager"
}

private var keyStore: KeyStore

init {
    keyStore = KeyStore.getInstance(ANDROID_KEY_STORE)
    keyStore.load(null)
}

fun encryptData(text: String): Pair<ByteArray, String>? {
    try {

        val cipher = Cipher.getInstance(TRANSFORMATION)
        cipher.init(Cipher.ENCRYPT_MODE, getSecretKet(ALIAS))
        val iv = cipher.iv

        val result = cipher.doFinal(text.toByteArray(Charsets.ISO_8859_1))
        val resultIv = Base64.encodeToString(iv, Base64.NO_WRAP)
        Timber.i("$TAG encrypted data $result")
        Timber.i("$TAG encrypted iv $iv")
        return if (result != null) {
            Pair(result, resultIv)
        } else {
            null
        }
    } catch (e: Exception) {
        Timber.e("$TAG error encryptData", e)
        return null
    }
}

fun encryptString(text: String): SecuredData? {
    return try {
        val result = encryptData(text)
        if (result != null) {
            SecuredData(result.first.toString(Charsets.ISO_8859_1), result.second)
        } else {
            null
        }
    } catch (e: Exception) {
        Timber.e("$TAG error encryptString", e)
        null
    }
}

/**
 Get pair of encrypted value and iv
 */
fun decryptString(encryptedString: String, iv: String): String {
    return try {
        val result = decryptData(
            encryptedString.toByteArray(Charsets.ISO_8859_1),
            Base64.decode(iv, Base64.NO_WRAP)
        )
        result
    } catch (e: java.lang.Exception) {
        Timber.e("Error in convert to Base64")
        encryptedString
    }
}

fun decryptData(encryptedData: ByteArray, iv: ByteArray): String {
    return try {
        val cipher = Cipher.getInstance(TRANSFORMATION)
        val spec = GCMParameterSpec(128, iv)
        cipher.init(Cipher.DECRYPT_MODE, getSecretKet(ALIAS), spec)
        val result = cipher.doFinal(encryptedData).toString(Charsets.ISO_8859_1)
        Timber.i("$TAG decrypted data $result")
        result
    } catch (e: Exception) {
        Timber.e("$TAG decryptData error may string was not encrypted", e)
        encryptedData.toString()
    }
}

private fun getSecretKet(alias: String): Key {

    if (keyStore.containsAlias(alias)) {
        // Try for existing key
        return keyStore.getKey(alias, null)
    } else {
        // Key is not present, create new one.
        val keyGenerator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val kGenerator =
                KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE)
            val specs = KeyGenParameterSpec
                .Builder(
                    alias,
                    KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
                )
                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                .build()
            kGenerator.init(specs)
            kGenerator
        } else {
            KeyGenerator.getInstance(ANDROID_KEY_STORE)
        }
        return keyGenerator.generateKey()
    }
}

@Keep
data class SecuredData(val value: String, val iv: String)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM