Как сохранить ключ с помощью поставщика хранилища ключей Android

Я пытаюсь использовать поставщика хранилища ключей Android, который стал доступен в Android 4.3, для безопасного сохранения закрытого ключа, а затем использовать этот закрытый ключ для шифрования и декодирования данных.

Я думаю, что до сих пор реализовал правильный подход и код для этого, однако в настоящее время я сталкиваюсь со странной проблемой, которую не могу понять.

У меня есть класс под названием KeyStorage, который я использую для создания пары ключей, загрузки KeyStore и получения закрытого ключа, код для этого класса выглядит следующим образом:

public class KeyStorage {

public static final String ANDROID_KEYSTORE = "AndroidKeyStore";
private KeyStore keyStore;

public void loadKeyStore() {
    try {
        keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
        keyStore.load(null);
        Enumeration<String> aliases = keyStore.aliases();
        while(aliases.hasMoreElements())
            Log.e("E", "Aliases = " + aliases.nextElement());
    } catch (Exception e) {
        // TODO: Handle this appropriately in your app
        e.printStackTrace();
    }
}

public void generateNewKeyPair(String alias, Context context)
        throws Exception {

    Calendar start = Calendar.getInstance();
    Calendar end = Calendar.getInstance();
    // expires 1 year from today
    end.add(1, Calendar.YEAR);

    KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
            .setAlias(alias)
            .setSubject(new X500Principal("CN=" + alias))
            .setSerialNumber(BigInteger.TEN)
            .setStartDate(start.getTime())
            .setEndDate(end.getTime())
            .build();

    // use the Android keystore
    KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA", ANDROID_KEYSTORE);
    gen.initialize(spec);

    // generates the keypair
    gen.generateKeyPair();
}

public PrivateKey loadPrivteKey(String alias) throws Exception {

    if (keyStore.isKeyEntry(alias)) {
        Log.e("E", "Could not find key alias: " + alias);
        return null;
    }

    KeyStore.Entry entry = keyStore.getEntry(EnhancedCredentialStore.KEY_ALIAS, null);

    if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
        Log.e("E", " alias: " + alias + " is not a PrivateKey");
        return null;
    }

    return ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();
}

Затем у меня есть класс CredentialStore, в котором я пытаюсь использовать это. Я создаю псевдоним с именем «MySecureKey» и пытаюсь создать и сохранить закрытый ключ на его основе. Итак, как вы можете видеть, я пытаюсь создать новую пару ключей на основе псевдонима, загрузить хранилище ключей, а затем, наконец, получить закрытый ключ. Однако это не работает.

public class CredentialStore {

public static final String KEY_ALIAS  = "MySecureKey";

private KeyStorage KeyStorage;

public CredentialStore(Activity context){

    keyStorage = new KeyStorage();
    try {
        keyStorage.generateNewKeyPair(KEY_ALIAS, context);
    } catch (Exception e) {
        e.printStackTrace();
    }
    blueBirdKeyStorage.loadKeyStore();

    try {
        keyStorage.loadPrivteKey(KEY_ALIAS);
    } catch (Exception e) {
        e.printStackTrace();
    }

}

Я получаю журналы следующим образом:

Aliases = MySecureKey
Could not find key alias: MySecureKey

Поэтому, когда я проверяю псевдонимы в методе loadKeyStore, похоже, что они есть, поскольку они возвращаются в журнал. Однако, когда я пытаюсь вызвать его с помощью метода loadKeyStore, я получаю журнал, в котором говорится, что он не может найти ключ «MySecureKey».

Я не могу найти причину этого, и поиск в Интернете оказался безрезультатным, поэтому мне было интересно, есть ли у кого-нибудь идеи, что может пойти не так?


person Donal Rafferty    schedule 25.09.2014    source источник
comment
1. Вы создаете KeyPair и не используете его. Ваш метод generateNewKeyPair ничего не возвращает. 2. Вы ничего не сохраняете в KeyStore, чтобы загрузить его позже. см. пример использования KeyStore. Это может помочь вам developer.android.com/samples/BasicAndroidKeyStore/index.html   -  person Alexander Zhak    schedule 25.09.2014
comment
@AlexanderZhak, несмотря на множество голосов, ваш комментарий неверен: ознакомьтесь с официальным документом: developer.android.com/training/articles/ именно так вы используете хранилище ключей Android — нет необходимости указывать ключ явно, если вы используете KeyFactory с экземпляром хранилища ключей Android.   -  person Patrick Favre    schedule 21.09.2016


Ответы (3)


Почему это blueBirdKeyStore в:

blueBirdKeyStorage.loadKeyStore();

Разве не должно быть:

keyStorage.loadKeyStore();

Кроме того, вы не использовали псевдоним в своем loadPrivateKey():

KeyStore.Entry entry = keyStore.getEntry(EnhancedCredentialStore.KEY_ALIAS, null);

Я не уверен, но разве вы не должны использовать здесь «псевдоним»?

person Sid    schedule 30.06.2016

Ваш метод проверки существования вашего ключа ошибочен:

if (keyStore.isKeyEntry(alias)) {
    Log.e("E", "Could not find key alias: " + alias);
    return null;
}

Согласно javadoc .isKeyEntry() имеет следующее поведение

Возвращает значение true, если запись, идентифицированная данным псевдонимом, была создана вызовом setKeyEntry или вызовом setEntry с использованием PrivateKeyEntry или SecretKeyEntry.

но ваш ключ не был создан через setEntry(). Я думаю, если вы просто загрузите ключ с помощью

KeyStore.Entry entry = ks.getEntry(alias, null);

он не будет нулевым.

Вот полный пример с простыми методами использования Android Keystore с pre-M и M Apis.

person Patrick Favre    schedule 21.09.2016

loadPrivateKey в вашем классе не использует «псевдоним» для получения ключа. Он использует константу другого класса, поэтому я не уверен, чего вы ожидаете здесь.

person Community    schedule 11.07.2016