1

I want to encrypt with a public RSA key in Android received from my php server in a HEX format.
Here is an example of RSA public key:

b74420f5a4d9abfd2072c9d936dd53e2de2aa790822ad1608807bda3e176b335c51902ca2177824198181ce8bea85de132aaea1104fd043e4ad2c0af705bda966b5d2f92a6ab5170d161eb1e8f7a6b1d5fba673f8a4dcebe55407ef9707782c91b17527af820a2c3a3b586341ae54ef03739074d4738e3ff35257bdfb9233c53

After receiving I tried to use it to encrypt a String.
Here is my code sample in ANDROID :

        try {
        String arg = "b74420f5a4d9abfd2072c9d936dd53e2de2aa790822ad1608807bda3e176b335c51902ca2177824198181ce8bea85de132aaea1104fd043e4ad2c0af705bda966b5d2f92a6ab5170d161eb1e8f7a6b1d5fba673f8a4dcebe55407ef9707782c91b17527af820a2c3a3b586341ae54ef03739074d4738e3ff35257bdfb9233c53";

        byte[] bytes = org.apache.commons.codec.binary.Hex.decodeHex(arg.toCharArray());
        System.out.println(new String(bytes, "UTF-8"));

        String message = "oussaki";

        byte[] publicBytes = org.apache.commons.codec.binary.Hex.decodeHex(arg.toCharArray());

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
        try {

            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey pubKey = keyFactory.generatePublic(keySpec);
            // Encrypt the message
            byte[] encryptedBytes = null;
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);

            encryptedBytes = cipher.doFinal(message.getBytes());
            System.out.println(encryptedBytes);

            byte[] b2 = new byte[encryptedBytes.length + 1];
            b2[0] = 1;
            System.arraycopy(encryptedBytes, 0, b2, 1, encryptedBytes.length);
            String s = new BigInteger(b2).toString(36);
            System.out.println("Encrypted text" + s);

        } catch (BadPaddingException | IllegalBlockSizeException | InvalidKeyException
                | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeySpecException k) {
            k.printStackTrace();
        }
    } catch (DecoderException e) {
        e.printStackTrace();
    }

After running the code it shows me an invalid key format:

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format

This error it is shown when generating the public key.

2 Answers 2

3

First of all, that is not an RSA public key in any format I know of, and certainly not in the format expect by the X509EncodedKeySpec class. It looks like the raw dump of an RSA modulus. You are missing the public exponent. One might guess that the exponent is 65537, but you need to verify that.

You can turn your RSA modulus into a BigInteger by using the sign-magnitude BigInteger constructor, and then create an RSA public key via the RSAPublicKeySpec class, not the X509EncodedKeySpec class. Here are few lines by way example using your code as a basis:

byte[] publicBytes = org.apache.commons.codec.binary.Hex.decodeHex(arg.toCharArray());

BigInteger modulus = new BigInteger(1, publicBytes);
BigInteger publicExponent = BigInteger.valueOf(65537L);

RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);

KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);

Another issue: You are using defaults in Cipher.getInstance(). Don't do that. Find out what RSA padding scheme is expected by the server and specify that explicitly. For example, instead of Cipher.getInstance("RSA") you might have

Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding")

or

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

depending on what the server expects.

Sign up to request clarification or add additional context in comments.

3 Comments

Hi , You're right about using modulus and Exponent , and 65537 is the correct modulus i tried your suggestions and the code running without errors , i tried to use RSA/ECB/PKCS1Padding but the result of encryption seems not the same as in my JAVASCRIPT code , because i have an example in JS and the encryption result is not the same as the one i got from Android
@Oussaki RSA encryption most likely uses randomized padding. So you can encrypt multiple times the exact same thing and get different ciphertexts. That's a security property. You need to encrypt in one and decrypt in the other in order to check for compatibility.
Yes , it working now , i will share the full code Here
1

In my code i missed two things :

1 - choosing the right Padding Scheme .

2 - using the two factors N and E to generate the public key

Also my server is expecting a HEX value to be returned i have to convert the Byte array to a HexString

and Here is the full code to do that :

   try {
        String arg = "b74420f5a4d9abfd2072c9d936dd53e2de2aa790822ad1608807bda3e176b335c51902ca2177824198181ce8bea85de132aaea1104fd043e4ad2c0af705bda966b5d2f92a6ab5170d161eb1e8f7a6b1d5fba673f8a4dcebe55407ef9707782c91b17527af820a2c3a3b586341ae54ef03739074d4738e3ff35257bdfb9233c53";
        String message = "plain text";
        byte[] publicBytes = org.apache.commons.codec.binary.Hex.decodeHex(arg.toCharArray());

        BigInteger modulus = new BigInteger(1, publicBytes);
        BigInteger publicExponent = BigInteger.valueOf(65537L);

        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey pubKey = keyFactory.generatePublic(keySpec);

        try {
            // decrypts the message
            byte[] encryptedBytes = null;
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            encryptedBytes = cipher.doFinal(message.getBytes());

            System.out.println( "Encrypted text : "+ convertToHexString(encryptedBytes));
        } catch (BadPaddingException | IllegalBlockSizeException | InvalidKeyException
                | NoSuchPaddingException | NoSuchAlgorithmException k) {
            k.printStackTrace();
        }
    } catch (DecoderException e) {
        e.printStackTrace();
    }

Here is the function to Convert the Byte array to HexString

 private static String convertToHexString(byte[] data) {
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < data.length; i++) {
        int halfbyte = (data[i] >>> 4) & 0x0F;
        int two_halfs = 0;
        do {
            if ((0 <= halfbyte) && (halfbyte <= 9))
                buf.append((char) ('0' + halfbyte));
            else
                buf.append((char) ('a' + (halfbyte - 10)));
            halfbyte = data[i] & 0x0F;
        } while(two_halfs++ < 1);
    }
    return buf.toString();
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.