【问题标题】:Android: Store SecretKey in KeyStoreAndroid:将 SecretKey 存储在 KeyStore 中
【发布时间】:2016-08-11 03:33:48
【问题描述】:

我使用SecretKey 来加密我的应用程序中的敏感数据。目前,我将我的 SecretKey 以 Base64 编码格式存储在 DB 或 SharedPrefs 中,这不是在有根手机上存储 Secret 的安全地方。因此,我想将我的 SecretKey 移动到 Android KeyStore。我面临的问题是,当我从 Google 尝试 this sample code 时,它需要一个 PrivateKey 而不是 SecretKey。我想不出一种方法来将我的 SecretKey 存储在 KeyStore 中并获取它以供以后使用。我试过这个:

private static void writeSecretKeyToKeystore(SecretKey secretKey, Context context) {
KeyStore keyStore = null;
try {
  keyStore = KeyStore.getInstance("AndroidKeyStore");
  keyStore.load(null);
  KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry(secretKey);
  keyStore.setKeyEntry("Key", secretKeyEntry.getSecretKey().getEncoded(), null);
} catch (KeyStoreException e) {
  e.printStackTrace();
} catch (CertificateException e) {
  e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
  e.printStackTrace();
} catch (IOException e) {
  e.printStackTrace();
}

当我尝试上面的代码时,它会抛出异常Operation not supported because encoding is unknown

任何示例代码都会有很大帮助。

【问题讨论】:

  • 尝试以下操作:keyStore.setEntry("Key", secretKeyEntry, null);
  • 它不会编译,说Wrong 2nd argument type. Found 'SecretKeyEntry'; required 'byte[]'
  • 请将“setKeyEntry”更改为“setEntry”。
  • 该死!我现在把它改成了setEntry,我看到了这个异常java.security.KeyStoreException: Entry must be a PrivateKeyEntry or TrustedCertificateEntry; was SecretKeyEntry: algorithm - AES

标签: android encryption keystore android-keystore secret-key


【解决方案1】:

错误
java.security.KeyStore 可以存储对称和非对称密钥。您只需在构造函数中实例化 KeyStore.SecretKeyEntry 并将您的 SecretKey 传递给它,然后使用 KeyStore#setEntry 方法保存它:

keyStore.setEntry(
     "key1",
     new KeyStore.SecretKeyEntry(secretKey),
     new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
             .setBlockMode(KeyProperties.BLOCK_MODE_GCM)
             .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
             .build());

要取出它,请使用:

SecretKey keyStoreKey = (SecretKey) keyStore.getKey("key1", null);

更新
经过一番研究,我惊讶地发现 AndroidKeyStore 不支持对称密钥。 (见讨论:https://groups.google.com/forum/#!topic/android-developers/gbmIRKRbfq8

【讨论】:

  • 我在 KeyStore 上看不到任何接受 SecretKeyEntry 对象的方法。此外,您的答案提到了如何获得条目,而不是如何设置条目。请检查我更新的问题。
  • 两种方法(getEntry 和 setEntry)都处理 KeyStore.Entry 接口(参见:developer.android.com/reference/java/security/…)。 KeyStore.SecretKeyEntry 实现了这个接口,所以你可以在任何需要 KeyStore.Entry 的地方使用它。
  • 这不适用于 API
  • 我尝试了 API 28,从密钥库获取 SecretKeyEntry,返回 null。 Java SE:没问题。
  • SecretKeyEntry 当然适用于最新的 Android 版本(API 28),这里是一个例子:github.com/fkirc/secure-zip-notes。但是,我认为 AndroidKeyStore 不支持任何低于 23 的 API 版本的对称加密。
【解决方案2】:

解决方法是加密您的 SecretKey 并将其存储在 SharedPreferences 中。然后将用于解密密钥的密钥存储在 Keystore 中。这是使用scytale 的实现。

public static String getBase64EncodedSecretKey(){
    Store store = new Store(context);
    Crypto crypto = new Crypto(Options.TRANSFORMATION_SYMMETRIC);
    SecretKey key = store.getSymmetricKey("key_alias", null);
    String encryptedData = PreferenceManager.getDefaultSharedPreferences(context).getString("myEncryptedSecretKey", "");
    return crypto.decrypt(encryptedData, key);
}

public static void storeKey(String base64EncodedSecretKey){
    Store store = new Store(context);
    if (store.hasKey("key_alias")) {
        store.deleteKey("key_alias");
    }
    SecretKey key = store.generateSymmetricKey("key_alias", null);
    Crypto crypto = new Crypto(Options.TRANSFORMATION_SYMMETRIC);
    String encryptedData = crypto.encrypt(base64EncodedSecretKey, key);
    PreferenceManager.getDefaultSharedPreferences(context).edit().putString("myEncryptedSecretKey",encryptedData).apply();
}

// Usage:
//store SecretKey
byte[] encodedKey = secretKeyEntry.getSecretKey().getEncoded();
String base64EncodedKey = Base64.encodeToString(encodedKey);
storeKey(base64EncodedKey);

//get SecretKey
String base64EncodedKey = getBase64EncodedSecretKey();
byte[] encodedKey = Base64.decode(base64EncodedKey);
SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");

【讨论】:

    猜你喜欢
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-05
    • 2016-04-02
    • 1970-01-01
    • 2017-10-15
    • 1970-01-01
    相关资源
    最近更新 更多