KeyStore не найден ключ для моего псевдонима

Я пытаюсь зашифровать некоторые данные в своем приложении, используя эту суть.

Я подписал свой apk своим псевдонимом Пабло. Проблема заключается в попытке запустить этот код:

public static String encrypt(String alias, String plaintext) {
    try {
        PublicKey publicKey = getPrivateKeyEntry(alias).getCertificate().getPublicKey();
        Cipher cipher = getCipher();
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return Base64.encodeToString(cipher.doFinal(plaintext.getBytes()), Base64.NO_WRAP);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

private static KeyStore.PrivateKeyEntry getPrivateKeyEntry(String alias) {
    try {
        KeyStore ks = KeyStore
                .getInstance("AndroidKeyStore");
        ks.load(null);
        KeyStore.Entry entry = ks.getEntry(alias, null);

        if (entry == null) {
            Log.w(TAG, "No key found under alias: " + alias);
            Log.w(TAG, "Exiting signData()...");
            return null;
        }

        if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
            Log.w(TAG, "Not an instance of a PrivateKeyEntry");
            Log.w(TAG, "Exiting signData()...");
            return null;
        }
        return (KeyStore.PrivateKeyEntry) entry;
    } catch (Exception e) {
        Log.e(TAG, e.getMessage(), e);
        return null;
    }
}

Но я получаю исключение: ключ не найден под псевдонимом

Есть идеи? Я должен ввести тот же псевдоним, что и мой jks, верно?

Спасибо!


person Pablo Cegarra    schedule 17.05.2017    source источник
comment
Вы пытались перечислить псевдонимы хранилища ключей в командной строке?   -  person thepoosh    schedule 21.05.2017
comment
Да, псевдоним в порядке, я пытаюсь отладить его с подписанным apk   -  person Pablo Cegarra    schedule 21.05.2017
comment
в какой строке кода возникает исключение? Убедитесь, что вы используете правильное хранилище ключей из jre, в котором вы запускаете приложение. Используемая среда выполнения JRE может быть другой, содержащей другое хранилище ключей без вашего псевдонима.   -  person Sonic    schedule 24.05.2017
comment
В этой части кода: KeyStore.Entry entry = ks.getEntry(alias, null);   -  person Pablo Cegarra    schedule 24.05.2017
comment
Я попытался получить apk-релиз и запустить его на своем устройстве с помощью инструментов adb, получая ту же ошибку.   -  person Pablo Cegarra    schedule 24.05.2017


Ответы (2)


Ответ от Sonic верен в том, что Java Key Store, который вы используете для подписи приложения, отличается от KeyStore, который вы используете в своем приложении. Первый — это файл на вашей машине разработчика (ваш ноутбук), а второй — только на телефоне, на который вы устанавливаете приложение (телефон Android или эмулятор). Подписание вашего apk, чтобы его можно было выпустить в Play Store, и шифрование личных данных пользователя в ваших данных — это разные процедуры.

В тех случаях, когда это неясно, вы должны попытаться обратиться к каноническим источникам, а не к произвольным описаниям и руководствам, которые сильно различаются по качеству. В этом случае в официальной документации Android для KeyStore есть полный пример хранения ключи. Обратите внимание, что Android KeyStore, указанный в Gist, доступен только в API 18+.

Следует признать, что примеры кода в официальной документации и Gist довольно сложны, и в них легко ошибиться. Лучшим вариантом может быть что-то вроде Scytale. Это оболочка вокруг KeyStore, которая будет правильно обрабатывать случай, когда API ‹ 18. Вот фрагмент кода для демонстрации:

Store store = new Store(getApplicationContext());
if (!store.hasKey("test")) {
   SecretKey key = store.generateSymmetricKey("test", null);
}
...

// Get key
SecretKey key = store.getSymmetricKey("test", null);

// Encrypt/Decrypt data
Crypto crypto = new Crypto(Options.TRANSFORMATION_SYMMETRIC);
String text = "Sample text";

String encryptedData = crypto.encrypt(text, key);
Log.i("Scytale", "Encrypted data: " + encryptedData);

String decryptedData = crypto.decrypt(encryptedData, key);
Log.i("Scytale", "Decrypted data: " + decryptedData);

Обратите внимание, что вам все равно нужно будет создать ключ для шифрования данных независимо от состояния ваших .jks на вашем хост-компьютере. Код в образце правильный:

if there is no key in the keystore with that alias
    make a new key with that alias
use the key to encrypt and decrypt data.
person David Rawson    schedule 26.05.2017

Хранилище ключей, которое вы запрашиваете в своем приложении, не совпадает с вашим локальным хранилищем ключей для подписи приложения: вы можете проверить это, вызвав ks.containsAlias(alias). Вы должны указать псевдоним в хранилище ключей времени выполнения. Вы должны создать запись для своего псевдонима: setEntry(String alias, KeyStore.Entry entry, KeyStore.ProtectionParameter protParam) (Saves a keystore Entry under the specified alias.)

person Sonic    schedule 24.05.2017
comment
Я не уверен в вашем ответе, мне нужно использовать хранилище ключей для шифрования данных. Зачем мне создавать новый псевдоним? - person Pablo Cegarra; 25.05.2017