Search code examples
javaandroidbase64bouncycastleboringssl

Decrypted String has valid and invalid characters


I'm decrypting an RSA encrypted base64 encoded string using the following code. However the decrypted string has some invalid characters prepended to real string. I've been trying to figure out what might be causing this garbage data to appear but my limited expertise in this are limiting me.

The data is encrypted using the following commands using openssl in terminal.

OpenSSL Commands used:

openssl genrsa -out priv_key.pem 2048  
openssl rsa -pubout -in priv_key.pem -out pub_key.pem 
openssl rsautl -encrypt -in userdata.json -out user_encrypted_with_pub_key -inkey pub_key.pem –pubin

The only thing that I'm doing programmatically is to decode the data encrypted using the above commands. I'm using bouncyCastle latest release.

Code:

decipherString(priv, decodeBase64(base64StringBuilder.toString()).toByteArray());

private static void decipherString(PrivateKey privateKey, byte[] encodedStringData) {
        byte[] dectyptedText = null;
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            dectyptedText = cipher.doFinal(encodedStringData);
            Timber.w("Deciphered text is: %s", new String(dectyptedText, "UTF-8"));
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

Output:

T1.O�Y1�{�l�M�X�`�������/9���Z��yt�戔��Eo��Z3���~7Aܴ�rtj)j��x')��e�/�$iJ���;���1&��I�U�#�$����}�C�����4P��E�-ρ�����?�wQ���Z�n�b��Py�%�>�I�X����TqDv�_���?��{ "ssid": "PT", "password": "XYZ123" , "security": "WPA2" }


Solution

  • Never, ever, do this:

    Cipher cipher = Cipher.getInstance("RSA");
    

    Always specify the full transformation string: "algorithm/mode/padding". Failure to do so will result in non-portable code, because the defaults are provider-specific. In your case the defaults are equivalent to something like

    Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
    

    But that isn't what you need here. openssl rsautl by default uses PKCS#1 v1.5 encryption padding, so what you need is

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