用KeyStore私钥和iv加解密出错"Some times"
Encryption and Decryption with KeyStore private key and iv goes wrong "Some times"
我正在像这样使用 KeyStore 进行加密和解密。
这是流程。在我将字符串传递给加密方法后,我保存了加密和 iv,所以我可以用它检索值 later.Problem 有时,一些加密值无法正确检索......不是全部!所以想想我加密了 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 因为发现这个字符集更好地保留所有字符并且丢失更少。
然后我想可能是保存位置有问题所以为了测试我只是从带有 sstring 字段的 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()
}
}
我认为这个 sould 可以正常工作,但最终我无法获得我上面提到的一些加密数据。有人知道吗?
我最终通过更深入地了解 AES 更改实现来解决这个问题。
- 最主要的是IV!简而言之,Iv 是一种使加密更加复杂的工具。我们创建一个 IV 并将其传递给密码,密码在多轮和字节块中加密数据和混合字节,并且在每一轮中它用逻辑更新 IV 并将其用于下一轮或字节块。因此,如果您在完成加密后从密码中获取 IV,您将看到它发生了变化!
- 第二件事是我使用 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)
我正在像这样使用 KeyStore 进行加密和解密。
这是流程。在我将字符串传递给加密方法后,我保存了加密和 iv,所以我可以用它检索值 later.Problem 有时,一些加密值无法正确检索......不是全部!所以想想我加密了 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 因为发现这个字符集更好地保留所有字符并且丢失更少。 然后我想可能是保存位置有问题所以为了测试我只是从带有 sstring 字段的 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()
}
}
我认为这个 sould 可以正常工作,但最终我无法获得我上面提到的一些加密数据。有人知道吗?
我最终通过更深入地了解 AES 更改实现来解决这个问题。
- 最主要的是IV!简而言之,Iv 是一种使加密更加复杂的工具。我们创建一个 IV 并将其传递给密码,密码在多轮和字节块中加密数据和混合字节,并且在每一轮中它用逻辑更新 IV 并将其用于下一轮或字节块。因此,如果您在完成加密后从密码中获取 IV,您将看到它发生了变化!
- 第二件事是我使用 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)