在Android Keystore中安全存储密钥 [英] Securely Storing Keys in Android Keystore

查看:436
本文介绍了在Android Keystore中安全存储密钥的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个与服务器通信的android应用程序.我在服务器上使用基于令牌的身份验证,并且使用非对称加密将信息从服务器传递到客户端,

I am making an android application that communicates with a server. I'm using token based authentication on my server, and to pass information to the client from the server, I am using asymmetric encryption.

过程就是这样

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

但是,我不知道如何将私钥安全地存储在密钥库中.如果我在运行时存储它,密钥将在代码中消失,并且如果我在REST连接期间发送私钥,则没有必要进行加密,因为黑客可以找到两个密钥.有人可以帮助我创建最佳解决方案吗?提前THX!

However, I do not know how to securely store the private key in the keystore. If I store it during runtime, the key will be out in the code, and if I send the private key during the REST connection, then there's no point of having the encryption because a hacker can find both keys. Can anyone help me on creating the best possible solution? THX in advance!

推荐答案

您可以将私钥存储在共享首选项中,但是使用生成的私钥进行加密,该私钥将存储在Android KeyStore 中,将在存储私钥方面提供更大的安全性.

You can store your private key in shared preferences, but encrypted with generated secret key, which will be stored in Android KeyStore, which will give much more security in storing the private key.

请参阅以下Kotlin中的示例.首先,您需要生成密钥:

Please see example below in Kotlin. First, you need to generate secret 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 的实例时将其称为提供程序.

It will be automatically stored in the KeyStore since we're mentioning it as a provider when getting instance of a KeyGenerator.

稍后,当您需要再次获取密钥时,可以这样做:

Later, when you will need to obtain secret key again you can do it like this:

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 ,则该方法将生成一个新的方法,方法是更改​​最后一个行到:

Or you can always use getSecretKey() method, which will generate new one if the obtained from the KeyStore is null by changing last line to:

return secretKeyEntry.secretKey ?: generateSecretKey()

获得 SecretKey 后,您可以继续进行加密:

When SecretKey is obtained you can proceed with encryption:

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 中.注意:您还应该存储初始化向量(IV).此处将其存储到 iv 属性.

Here, method encrypt will return a ByteArray that you can store in the SharedPreferences. NOTE: that you should also store initialization vector (IV). Here it is stored to the iv property.

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

To decrypt stored data, use this method:

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)
}

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

Here, you must pass store initialization vector (IV) to GCMParameterSpec.

希望它将对某人有所帮助.

Hope it will helps someone.

这篇关于在Android Keystore中安全存储密钥的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆