@@ -343,10 +343,9 @@ byte[] RSADecrypt(byte[] encryptedInput) throws IncompatibleDeviceException, Cry
343343 Cipher cipher = Cipher .getInstance (RSA_TRANSFORMATION );
344344 cipher .init (Cipher .DECRYPT_MODE , privateKey , OAEP_SPEC );
345345 return cipher .doFinal (encryptedInput );
346- } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e ) {
346+ } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
347+ | InvalidAlgorithmParameterException e ) {
347348 /*
348- * This exceptions are safe to be ignored:
349- *
350349 * - NoSuchPaddingException:
351350 * Thrown if PKCS1Padding is not available. Was introduced in API 1.
352351 * - NoSuchAlgorithmException:
@@ -361,6 +360,24 @@ byte[] RSADecrypt(byte[] encryptedInput) throws IncompatibleDeviceException, Cry
361360 */
362361 Log .e (TAG , "The device can't decrypt input using a RSA Key." , e );
363362 throw new IncompatibleDeviceException (e );
363+ } catch (ProviderException e ) {
364+ /*
365+ * - ProviderException:
366+ * Thrown on Android 12+ (API 31+, Keystore2) when the RSA key's padding
367+ * restriction does not match the cipher transformation. For example, an RSA
368+ * key generated with ENCRYPTION_PADDING_RSA_PKCS1 will trigger this when
369+ * initialised with an OAEPWithSHA-1AndMGF1Padding cipher. On API 23-30 the
370+ * same condition surfaces as InvalidKeyException.
371+ *
372+ * This is NOT a device-level incompatibility -- the key can be deleted and
373+ * regenerated with the correct padding. Wrapping as CryptoException (rather
374+ * than IncompatibleDeviceException) ensures the caller falls through to key
375+ * cleanup and regeneration instead of permanently blocking the user.
376+ */
377+ Log .e (TAG , "RSA key padding mismatch detected (Android 12+ Keystore2)." , e );
378+ deleteAESKeys ();
379+ throw new CryptoException (
380+ "The RSA key's padding mode is incompatible with the current cipher." , e );
364381 } catch (IllegalArgumentException | IllegalBlockSizeException | BadPaddingException e ) {
365382 /*
366383 * Any of this exceptions mean the encrypted input is somehow corrupted and cannot be recovered.
@@ -394,10 +411,9 @@ byte[] RSAEncrypt(byte[] decryptedInput) throws IncompatibleDeviceException, Cry
394411 Cipher cipher = Cipher .getInstance (RSA_TRANSFORMATION );
395412 cipher .init (Cipher .ENCRYPT_MODE , certificate .getPublicKey (), OAEP_SPEC );
396413 return cipher .doFinal (decryptedInput );
397- } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e ) {
414+ } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
415+ | InvalidAlgorithmParameterException e ) {
398416 /*
399- * This exceptions are safe to be ignored:
400- *
401417 * - NoSuchPaddingException:
402418 * Thrown if PKCS1Padding is not available. Was introduced in API 1.
403419 * - NoSuchAlgorithmException:
@@ -412,6 +428,24 @@ byte[] RSAEncrypt(byte[] decryptedInput) throws IncompatibleDeviceException, Cry
412428 */
413429 Log .e (TAG , "The device can't encrypt input using a RSA Key." , e );
414430 throw new IncompatibleDeviceException (e );
431+ } catch (ProviderException e ) {
432+ /*
433+ * - ProviderException:
434+ * Thrown on Android 12+ (API 31+, Keystore2) when the RSA key's padding
435+ * restriction does not match the cipher transformation. For example, an RSA
436+ * key generated with ENCRYPTION_PADDING_RSA_PKCS1 will trigger this when
437+ * initialised with an OAEPWithSHA-1AndMGF1Padding cipher. On API 23-30 the
438+ * same condition surfaces as InvalidKeyException.
439+ *
440+ * This is NOT a device-level incompatibility -- the key can be deleted and
441+ * regenerated with the correct padding. Wrapping as CryptoException (rather
442+ * than IncompatibleDeviceException) ensures the caller falls through to key
443+ * cleanup and regeneration instead of permanently blocking the user.
444+ */
445+ Log .e (TAG , "RSA key padding mismatch detected (Android 12+ Keystore2)." , e );
446+ deleteAESKeys ();
447+ throw new CryptoException (
448+ "The RSA key's padding mode is incompatible with the current cipher." , e );
415449 } catch (IllegalBlockSizeException | BadPaddingException e ) {
416450 /*
417451 * They really should not be thrown at all since padding is requested in the transformation.
@@ -467,10 +501,12 @@ private byte[] attemptPKCS1Migration(byte[] encryptedAESBytes) {
467501
468502 } catch (BadPaddingException | IllegalBlockSizeException e ) {
469503 Log .e (TAG , "PKCS1 decryption failed. Data may be corrupted." , e );
470- } catch (KeyStoreException | CertificateException | IOException |
504+ } catch (KeyStoreException | CertificateException | IOException |
471505 NoSuchAlgorithmException | UnrecoverableEntryException |
472506 NoSuchPaddingException | InvalidKeyException e ) {
473507 Log .e (TAG , "Migration failed due to key access error." , e );
508+ } catch (ProviderException e ) {
509+ Log .e (TAG , "PKCS1 migration failed: key padding incompatible (Android 12+ Keystore2)." , e );
474510 } catch (CryptoException e ) {
475511 Log .e (TAG , "Failed to re-encrypt AES key with OAEP." , e );
476512 }
@@ -593,7 +629,9 @@ private byte[] tryMigrateLegacyAESKey() {
593629 KeyStore .PrivateKeyEntry rsaKeyEntry = getRSAKeyEntry ();
594630
595631 byte [] decryptedAESKey = RSADecryptLegacyPKCS1 (encryptedOldAESBytes , rsaKeyEntry .getPrivateKey ());
596-
632+
633+ deleteRSAKeys ();
634+
597635 // Re-encrypt with OAEP and store at new location
598636 byte [] encryptedAESWithOAEP = RSAEncrypt (decryptedAESKey );
599637 String newEncodedEncryptedAES = new String (Base64 .encode (encryptedAESWithOAEP , Base64 .DEFAULT ), StandardCharsets .UTF_8 );
@@ -603,7 +641,8 @@ private byte[] tryMigrateLegacyAESKey() {
603641 Log .d (TAG , "Legacy AES key migrated successfully" );
604642 return decryptedAESKey ;
605643 } catch (CryptoException | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException |
606- BadPaddingException | IllegalBlockSizeException | IllegalArgumentException e ) {
644+ BadPaddingException | IllegalBlockSizeException | IllegalArgumentException |
645+ ProviderException e ) {
607646 Log .e (TAG , "Could not migrate legacy AES key. Will generate new key." , e );
608647 deleteAESKeys ();
609648 return null ;
@@ -632,8 +671,11 @@ private byte[] generateNewAESKey() throws IncompatibleDeviceException, CryptoExc
632671 } catch (NoSuchAlgorithmException e ) {
633672 Log .e (TAG , "AES algorithm not available." , e );
634673 throw new IncompatibleDeviceException (e );
674+ } catch (IncompatibleDeviceException e ) {
675+ deleteRSAKeys ();
676+ deleteAESKeys ();
677+ throw e ;
635678 } catch (CryptoException e ) {
636- // Re-throw CryptoException and its subclasses (including IncompatibleDeviceException)
637679 throw e ;
638680 } catch (Exception e ) {
639681 Log .e (TAG , "Unexpected error while creating new AES key." , e );
0 commit comments