Подтвердить что ты не робот

Crash casting AndroidKeyStoreRSAPrivateKey для RSAPrivateKey

Я следую этому руководству: Как использовать Keystore Android для хранения паролей и другой конфиденциальной информации. Он (свободно) связан с приложением Google Sample: BasicAndroidKeyStore.

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

java.lang.RuntimeException: Unable to create application com.android.test: java.lang.ClassCastException: android.security.keystore.AndroidKeyStoreRSAPrivateKey cannot be cast to java.security.interfaces.RSAPrivateKey

Вот код, с которым он падает:

KeyStore.Entry entry;

//Get Android KeyStore
ks = KeyStore.getInstance(KeystoreHelper.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);

// Weird artifact of Java API.  If you don't have an InputStream to load, you still need to call "load", or it'll crash.
ks.load(null);

// Load the key pair from the Android Key Store
entry = ks.getEntry(mAlias, null);

KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) entry;

//ERROR OCCURS HERE::
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKeyEntry.getPrivateKey();

Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");

output.init(Cipher.DECRYPT_MODE, rsaPrivateKey);

Я не хочу приводить это в зависимость от Android M, поскольку не вижу причин, по которым библиотеки криптовариантов java бы изменились. Если релиз M появится, и наше приложение сразу же сработает на M, у меня будут большие проблемы.

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

Большое спасибо.

4b9b3361

Ответ 1

Мне удалось получить эту работу, удалив провайдера из Cipher.getInstance и not для трансляции в RSAprivateKey.

KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) entry;

Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding");
output.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey());

Я не 100%, но я думаю, что причиной этого я считаю изменение зефира от OpenSSL до BoringSSL. https://developer.android.com/preview/behavior-changes.html#behavior-apache-http-client

В любом случае, выше сказанное работало для M и ниже.

Ответ 2

Вопрос

  • Мы пытаемся разобрать "java.security. PrivateKey на java.security.interfaces. RSAPrivateKey" и "java.security. PublicKey в java.security.interfaces. RSAPublicKey". Вот почему мы получаем ClassCastException.

Решение

  • Нам не нужно анализировать ключ, мы можем напрямую использовать "java.security. PrivateKey" и "java.security. PublicKey" для шифрования и дешифрование.

Шифрование

KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)entry; 
PublicKey publicKey = privateKeyEntry.getCertificate().getPublicKey(); // Don't TypeCast to RSAPublicKey

дешифрование

KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)entry;
PrivateKey privateKey = privateKeyEntry.getPrivateKey(); // Don't TypeCast to RSAPrivateKey

Ответ 3

Я решил эту проблему, следуя этому (кроме ответа @James выше): На Android 6.0 вы не должны использовать "AndroidOpenSSL" для создания шифрования, с ошибкой "Необходимый частный или открытый ключ RSA" в шифре init для дешифрования. Просто используйте Cipher.getInstance( "RSA/ECB/PKCS1Padding" ), и он будет работать.

Ответ 4

Я не пробовал это, но вы должны были бы отличить android.security.keystore.AndroidKeyStoreRSAPrivateKey к следующему отдельно. Это должны быть необходимые вам интерфейсы:

  • java.security.PrivateKey
  • java.security.interfaces.RSAKey