web-dev-qa-db-ja.com

Android:SecretKeyをKeyStoreに保存する

SecretKey を使用して、アプリケーションの機密データを暗号化します。現在、SecretKeyをBase64でエンコードされた形式でDBまたはSharedPrefsに保存していますが、これはルート化された電話にSecretを保存するのに安全な場所ではありません。したがって、SecretKeyを Android KeyStore に移動したいと思います。私が直面している問題は、Googleから このサンプルコード を試してみると、SecretKeyではなくPrivateKeyが必要になることです。 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

サンプルコードはどれも大いに役立ちます。

11
Rajkiran

違う
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

7
dev.bmax

回避策は、SecretKeyを暗号化し、SharedPreferencesに保存することです。次に、キーを格納して、キーを復号化します。 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");
0
AtomicBoolean