[英]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 更改的實現。
首先,我認為它將在@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.