Замена KeyPairGeneratorSpec на KeyGenParameterSpec.Builder эквиваленты - Сбой операции хранилища ключей

Следующий метод устарел

KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");

KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this)
                            .setAlias(alias)
                            .setSubject(new X500Principal("CN=Sample Name, O=Android Authority"))
                            .setSerialNumber(BigInteger.ONE)
                            .setStartDate(start.getTime())
                            .setEndDate(end.getTime())
                            .build();

generator.initialize(spec);

Замена, на которую я натолкнулся, выглядит так

KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");

generator.initialize(new KeyGenParameterSpec.Builder
                            (alias, KeyProperties.PURPOSE_SIGN)
                            .setDigests(KeyProperties.DIGEST_SHA256)
                            .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
                            .build());

Хотя я могу использовать это для генерации записи пары ключей и шифрования значения, я не могу расшифровать ее

 public void encryptString(String alias) {
        try {
            KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
            RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey();

            String initialText = startText.getText().toString();
            if(initialText.isEmpty()) {
                Toast.makeText(this, "Enter text in the 'Initial Text' widget", Toast.LENGTH_LONG).show();
                return;
            }

            //Security.getProviders();

            Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidKeyStoreBCWorkaround");
            inCipher.init(Cipher.ENCRYPT_MODE, publicKey);

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            CipherOutputStream cipherOutputStream = new CipherOutputStream(
                    outputStream, inCipher);
            cipherOutputStream.write(initialText.getBytes("UTF-8"));
            cipherOutputStream.close();

            byte [] vals = outputStream.toByteArray();
            encryptedText.setText(Base64.encodeToString(vals, Base64.DEFAULT));
        } catch (Exception e) {
            Toast.makeText(this, "Exception " + e.getMessage() + " occured", Toast.LENGTH_LONG).show();
            Log.e(TAG, Log.getStackTraceString(e));
        }
    }

public void decryptString(String alias) {
        try {
            KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);

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

            String cipherText = encryptedText.getText().toString();
            CipherInputStream cipherInputStream = new CipherInputStream(
                    new ByteArrayInputStream(Base64.decode(cipherText, Base64.DEFAULT)), output);
            ArrayList<Byte> values = new ArrayList<>();
            int nextByte;
            while ((nextByte = cipherInputStream.read()) != -1) {
                values.add((byte)nextByte);
            }

            byte[] bytes = new byte[values.size()];
            for(int i = 0; i < bytes.length; i++) {
                bytes[i] = values.get(i).byteValue();
            }

            String finalText = new String(bytes, 0, bytes.length, "UTF-8");
            decryptedText.setText(finalText);

        } catch (Exception e) {
            Toast.makeText(this, "Exception " + e.getMessage() + " occured", Toast.LENGTH_LONG).show();
            Log.e(TAG, Log.getStackTraceString(e));
        }

в decrypt метод, следующая команда не выполняется:

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

с

java.security.InvalidKeyException: Keystore operation failed

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

Но все это можно проследить до использования нового KeygenParameterSpec.Builder, так как использование устаревшего устаревшего метода позволяет мне шифровать и дешифровать.

Как исправить?

2 ответа

Как упомянул Алекс, одна недостающая часть KeyProperties.PURPOSE_DECRYPT другой setSignaturePaddings вместо этого вы должны использовать setEncryptionPaddings метод. Вот образец фрагмента.

    new KeyGenParameterSpec.Builder(ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
            // other options
           .build()

Обратитесь к документации для получения дополнительной информации.

Трудно быть на 100% уверенным, учитывая, что вы не предоставили полную трассировку стека исключения.

Ваш код генерирует закрытый ключ так, что он разрешается использовать только для подписи, но не для расшифровки. Шифрование работает нормально, потому что оно не использует закрытый ключ - оно использует открытый ключ, и открытые ключи Android Keystore можно использовать без каких-либо ограничений. Дешифрование завершается неудачно, потому что ему нужно использовать закрытый ключ, но ваш код не разрешил использовать закрытый ключ для расшифровки.

Похоже, что немедленное решение - авторизовать закрытый ключ, который будет использоваться для расшифровки. Это достигается путем перечисления KeyProperties.PURPOSE_DECRYPT при вызове конструктора KeyGenParameterSpec.Builder. Если ключ не должен использоваться для подписи, удалите KeyProperties.PURPOSE_SIGN оттуда, а также удалите setSignaturePaddings.

Вам также необходимо авторизовать использование закрытого ключа с помощью PKCS1Padding: invoke setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)

Другие вопросы по тегам