Search code examples
javaandroidencryptionrsa

how to use (RSA/ECB/PKCS1Padding) in android


About a year ago, I wrote an application for Android and used a class in it RSA In this class, there was the following code snippet and the application worked

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")

But when I re-entered the application code, I did not open the new encrypted information to change the private key until I changed the above code line to the following code line.

Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

The problem is that if I replace the above code snippet in class RSA it is no longer possible to open previously encrypted information (with the same keys as before). And I see the following error

javax.crypto.BadPaddingException: error:04000084:RSA routines:OPENSSL_internal:PKCS_DECODING_ERROR

RSA decryption

public static byte[] decryptByPrivateKey(byte[] data, String key)
            throws Exception {

        byte[] keyBytes = decryptBASE64(key);


        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        
        // Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());


        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        return cipher.doFinal(data);
    }

Solution

  • RSA key pairs can be used within different RSA based schemes, such as PKCS#1 and OAEP padding for encryption, and PKCS#1 and PSS padding for signing. However, there is only one key pair generation possible, which is simply denoted "RSA".

    If only "RSA" is used as input string it will use the defaults set for the specific cryptography provider, which is - in this case - the first provider that implements RSA using keys in software. Apparently that's different on Android from PKCS#1 padding (assuming that you still use the original list of providers, of course). One stupid thing in Java is that you cannot programmatically find out which defaults are used; getAlgorithm() ususally just returns the string you've provided earlier. The only thing you can do is to get the provider using getProvider() and then lookup the defaults...

    I would never go for any defaults (except for SecureRandom defaults) as it is unspecified which defaults will be used for Java. Always specify the algorithm in full; your earlier string was fine.