Я работаю над приложением, которое должно быть достаточно безопасным, поэтому мы хотим использовать Android Keystore, чтобы сделать определенные вещи, такие как accessTokens для бэкэнда, более безопасными и более безопасными.
Я пытался реализовать некоторые из них, и похоже, что это работает, но я работал в основном на примерах, в основном Безопасное хранение ключей в Android Keystore
Вот мой код:
object AndroidKeyStore {
const val ANDROID_KEY_STORE = "AndroidKeyStore"
const val AES_MODE = "AES/GCM/NoPadding"
private var iv: ByteArray = byteArrayOf(55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44)
//IS IT SAFE TO HAVE THIS HERE?
const val SECRET_ALIAS = "TEST"
private fun generateSecretKey(keyAlias: String): SecretKey {
val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE)
val spec = KeyGenParameterSpec.Builder(keyAlias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setRandomizedEncryptionRequired(false)
.build()
keyGenerator.init(spec)
return keyGenerator.generateKey()
}
private fun getSecretKey(keyAlias: String): SecretKey {
val keyStore = KeyStore.getInstance(ANDROID_KEY_STORE).apply { load(null) }
if (keyStore.getEntry(keyAlias, null) != null) {
val secretKeyEntry = keyStore.getEntry(keyAlias, null) as KeyStore.SecretKeyEntry
return secretKeyEntry.secretKey ?: generateSecretKey(keyAlias)
}
return generateSecretKey(keyAlias)
}
fun encrypt(data: String): String {
val cipher = Cipher.getInstance(AES_MODE)
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(SECRET_ALIAS), GCMParameterSpec(128, iv))
iv = cipher.iv
val encodedBytes = cipher.doFinal(data.toByteArray())
return Base64.encodeToString(encodedBytes, Base64.NO_WRAP)
}
fun decrypt(encrypted: String): String {
val cipher = Cipher.getInstance(AES_MODE)
val spec = GCMParameterSpec(128, iv)
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(SECRET_ALIAS), spec)
val encodedBytes = Base64.decode(encrypted, Base64.NO_WRAP)
val decoded = cipher.doFinal(encodedBytes)
return String(decoded, Charsets.UTF_8)
}
}
Это мой код хранилища ключей, похоже, он хорошо шифрует / дешифрует. Но мне трудно понять, что такое секретный псевдоним и где его безопасно разместить.
В то же время я также использую безопасное хранилище настроек. Поэтому моя идея состояла в том, чтобы сохранить accessToken в безопасном хранилище настроек, но зашифровать его с помощью этого кода хранилища ключей.
Вот код для безопасного хранилища pref.
object SecurePreferenceUtils {
enum class SecurePreferenceKeys {
AccessToken, Test
}
fun putString(key: SecurePreferenceKeys, value: String) {
SecurePrefs.securePreferences.edit().putString(key.name, value).commit()
}
fun getString(key: SecurePreferenceKeys, defaultValue: String): String {
return SecurePrefs.securePreferences.getString(key.name, defaultValue) ?: ""
}
object SecurePrefs {
lateinit var securePreferences: SecurePreferences
}
В конце я хотел бы иметь возможность делать это, когда получаю accessToken из бэкэнда.
SecurePreferenceUtils.putString(SecurePreferenceUtils.SecurePreferenceKeys.AccessToken, AndroidKeyStore.encrypt(""))
val token = AndroidKeyStore.decrypt(SecurePreferenceUtils.getString(SecurePreferenceUtils.SecurePreferenceKeys.AccessToken, AndroidKeyStore.encrypt("")))
Надеюсь, у меня есть какой-то смысл в том, куда я хочу пойти, я просто не совсем уверен, что я на правильном пути.
Любая помощь приветствуется!