java - 在 Android Keystore 中安全地存储 key

标签 java android security encryption android-keystore

我正在制作一个与服务器通信的 android 应用程序。我在我的服务器上使用基于 token 的身份验证,为了将信息从服务器传递给客户端,我使用了非对称加密。

过程是这样的

  1. 生成的公钥和私钥事先已经存在
  2. 公钥用于加密信息,然后从服务器传递给客户端
  3. App使用私钥解密信息

但是,我不知道如何将私钥安全地存储在 keystore 中。如果我在运行时存储它, key 将在代码中出现,如果我在 REST 连接期间发送私钥,那么加密就没有意义,因为黑客可以找到这两个 key 。任何人都可以帮助我创建最佳解决方案吗?提前致谢!

最佳答案

您可以将您的私钥存储在共享首选项中,但使用生成的 key 加密,该 key 将存储在 Android KeyStore 中,这将在存储私钥时提供更多安全性。

请参阅下面的 Kotlin 示例。 首先,您需要生成 key :

fun generateSecretKey(): SecretKey {
    val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
    val spec = KeyGenParameterSpec
            .Builder(secretKeyAlias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
            .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
            .build()

    keyGenerator.init(spec)
    return keyGenerator.generateKey()
}

它将自动存储在 KeyStore 中,因为我们在获取 KeyGenerator 实例时将其作为提供者提及。

以后需要再次获取秘钥的时候可以这样:

fun getSecretKey(): SecretKey {
    val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
    val secretKeyEntry = keyStore.getEntry(secretKeyAlias, null) as KeyStore.SecretKeyEntry
    return secretKeyEntry.secretKey
}

或者你总是可以使用 getSecretKey() 方法,如果从 KeyStore 中获取的是 null ,它将生成一个新的,通过改变最后线到:

return secretKeyEntry.secretKey ?: generateSecretKey()

得到SecretKey后就可以进行加密了:

fun encrypt(data: String): ByteArray? {
    val cipher = Cipher.getInstance("AES/GCM/NoPadding")
    cipher.init(Cipher.ENCRYPT_MODE, getSecretKey())
    iv = cipher.iv
    return cipher.doFinal(data.toByteArray())
}

这里,方法 encrypt 将返回一个 ByteArray,您可以将其存储在 SharedPreferences 中。 注意:您还应该存储初始化 vector (IV)。这里它存储到 iv 属性。

要解密存储的数据,请使用此方法:

fun decrypt(encrypted: ByteArray): String {
    val cipher = Cipher.getInstance("AES/GCM/NoPadding")
    val spec = GCMParameterSpec(128, iv)
    cipher.init(Cipher.DECRYPT_MODE, getSecretKey(), spec)
    val decoded = cipher.doFinal(encrypted)
    return String(decoded, Charsets.UTF_8)
}

在这里,您必须将存储初始化 vector (IV) 传递给 GCMParameterSpec

希望对大家有帮助。

关于java - 在 Android Keystore 中安全地存储 key ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32298956/

相关文章:

java - 绘制网格偏移

java - 如果从下拉列表中进行选择,如何在选择后放置 if 语句

java - 在单个请求中获取多个用户的最新推文

android - Ubuntu 12.04 编译安卓大师

android - "table or subquery expected, got "Android Room 错误

android - Kindle Fire 主屏幕应用程序。图标

amazon-web-services - 禁用 AWS S3 管理控制台

java - 启用 Google 位置服务 Intent

php - 动态包括安全

.net - Base64 编码数据最大大小