我正在制作一个与服务器通信的 android 应用程序。我在我的服务器上使用基于 token 的身份验证,为了将信息从服务器传递给客户端,我使用了非对称加密。
过程是这样的
- 生成的公钥和私钥事先已经存在
- 公钥用于加密信息,然后从服务器传递给客户端
- 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/