Android public key encryption

Ray :

My Android app implements RSA encryption, however the backend can not decrypt the token generated by the app. Here is the code, the beginning and end lines of the public key have been removed before making the calls, what could be the problem?

String encryptedToken = Base64.encodeToString(encrypt(publicKey, "4111111111111111"), Base64.NO_WRAP);

public static byte[] encrypt(String publicKey, String data) {
        if (TextUtils.isEmpty(publicKey) || TextUtils.isEmpty(data)) {
            return null;
        }
        try {
            // Decode the modified public key into a byte[]
            byte[] publicKeyByteArray = Base64.decode(publicKey.getBytes("UTF-8"),Base64.NO_WRAP);

            Cipher mCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyByteArray);
            Key key = keyFactory.generatePublic(x509KeySpec);
            mCipher.init(Cipher.ENCRYPT_MODE, key);
            return mCipher.doFinal(data.getBytes("UTF-8"));
        }
        catch (UnsupportedEncodingException e) {
            Log.e("RSAKEY", e.getMessage());
        }
        catch (NoSuchPaddingException e) {
            Log.e("RSAKEY", e.getMessage());
        } catch (NoSuchAlgorithmException e) {
            Log.e("RSAKEY", e.getMessage());
        } catch (InvalidKeyException e) {
            Log.e("RSAKEY", e.getMessage());
        } catch (InvalidKeySpecException e) {
            Log.e("RSAKEY", e.getMessage());
        } catch (IllegalBlockSizeException e) {
            Log.e("RSAKEY", e.getMessage());
        } catch (BadPaddingException e) {
            Log.e("RSAKEY", e.getMessage());
        }
        return null;
    }

The backend team provided the below sample code that works, but it is for desktop java. Android library does not have the Base64.getEncoder method. it is very similar to what I wrote but mine just does not work.

 // Decode the modified public key into a byte[]
            byte[] publicKeyByteArray = Base64.getDecoder().decode(publicKey.getBytes(StandardCharsets.UTF_8));

            // Create a PublicKey from the byte array
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyByteArray);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey pubKey = keyFactory.generatePublic(keySpec);

            // Get an instance of the Cipher and perform the encryption
            Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            byte[] cipherText = cipher.doFinal(ccNum.getBytes(StandardCharsets.UTF_8));

            // Get the encrypted value as a Base64-encoded String
            String encodeToStr = Base64.getEncoder().encodeToString(cipherText);

            // Print out the encoded, encrypted string
            System.out.println("Encrypted and Encoded String: " + encodeToStr);

I compared the byte array values at every step. The desktop cipher and android cipher got exactly the same inputs. However the results from the Android code cipher.doFinal can not be decrypted by the backend. If I put the desktop results to the REST call body they work fine, so it is not something caused by REST call.

I also tried to create a public/private key pair on Android, and use the generated public key to encrypt instead of using the public key from our backend, and decrypt using the private key and it works. So the cipher is also working, just somehow the backend is expecting something different

Ray :

Finally someone in the team cracked this. The reason is because the Android OS uses Bouncy castle, the backend uses Sun as the provider, this caused the backend throwing a BadPaddingException. To make it work, the cipher needs to be initialized this way on Android:

 mCipher.init(Cipher.ENCRYPT_MODE, key, new
                    OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1,
                    PSource.PSpecified.DEFAULT));

Check for more details in this post: http://bouncy-castle.1462172.n4.nabble.com/Problems-with-OAEP-SHA-256-hash-crypto-td1466852.html

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=443712&siteId=1