Android 8.0: IllegalBlocksizeException при использовании RSA/ECB/OAEPWithSHA-512AndMGF1Padding

Я обычно нахожу ответы на большинство наших вопросов здесь, но на этот раз мне нужно спросить:-).

Мы столкнулись с проблемой шифрования / дешифрования RSA в одном из наших приложений, работающих на Android 8.0 (уровень API 26).

Мы использовали RSA с "RSA/ECB/OAEPWithSHA-256AndMGF1Padding", который прекрасно работает на всех версиях до Android 7.1. Тот же код, работающий на Android 8.0, вызывает исключение IllegalBlocksizeException при вызове Cipher.doFinal().

Вот код для воспроизведения проблемы:

private KeyStore mKeyStore;

private static final String KEY_ALIAS = "MyKey";
void testEncryption() throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, KeyStoreException, IOException, CertificateException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException, UnrecoverableEntryException, NoSuchPaddingException {

    mKeyStore = KeyStore.getInstance("AndroidKeyStore");
    mKeyStore.load(null);

    // Generate Key Pair -------------------------------------
    KeyPairGenerator kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
    kpg.initialize(new KeyGenParameterSpec.Builder(
            KEY_ALIAS,
            KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
            .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
            .setKeySize(2048)
            .build());
    KeyPair kp = kpg.generateKeyPair();

    // Encrypt -----------------------------------------------
    KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)mKeyStore.getEntry(KEY_ALIAS, null);
    PublicKey publicKey = (PublicKey) privateKeyEntry.getCertificate().getPublicKey();
    Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    String x = "It doesn't have to be perfect, it's just for demonstration.";

    byte [] vals = cipher.doFinal(x.getBytes("UTF-8"));

    byte[] encryptedBytes = Base64.encode(vals, Base64.DEFAULT);
    String encryptedText = new String(encryptedBytes, "UTF-8");


    // Decrypt -----------------------------------------------
    PrivateKey privateKey = privateKeyEntry.getPrivateKey();

    Cipher output = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
    output.init(Cipher.DECRYPT_MODE, privateKey/*, spec */);

    byte[] bxx = Base64.decode(encryptedText, Base64.DEFAULT);
    byte[] bytes = output.doFinal(bxx);  // <= throws IllegalBlocksizeException

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

Я пробовал и другие алгоритмы заполнения. "RSA/ECB/OAEPWithSHA-1AndMGF1Padding" работает, а также "RSA/ECB/PKCS1Padding" работает нормально. В качестве обходного пути я мог бы изменить заполнение, но это могло бы вызвать проблемы при обновлении с предыдущей версии приложения, в котором использовался "RSA/ECB/OAEPWithSHA-256AndMGF1Padding", поскольку хранимые данные не могли больше считываться.

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

Заранее благодарю и приветствую из Гамбурга, Дмитрия

1 ответ

Возможное решение описано здесь в комментарии № 15 от 8 сентября 2017 г. 19:08:

https://issuetracker.google.com/issues/36708951

Я изменил Инициализацию Шифра с

Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, this.getPrivateKey(context));

в

OAEPParameterSpec sp = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-1"), PSource.PSpecified.DEFAULT);
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, this.getPrivateKey(context), sp);

Я проверил это на Android 6 до Android 8 (эмулятор), и проблема, кажется, ушла. Вам также следует изменить Cipher.ENCRYPT_MODE-реализации.

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