Android Keystore в Котлине - PullRequest
0 голосов
/ 14 мая 2019

Я работаю над приложением, которое должно быть достаточно безопасным, поэтому мы хотим использовать 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("")))

Надеюсь, у меня есть какой-то смысл в том, куда я хочу пойти, я просто не совсем уверен, что я на правильном пути.

Любая помощь приветствуется!

...