We have a system which includes Android and iPhone apps as well as a backend server. The applications can send certain sensitive information to one another. In order to do so they generate a keypair when logging in and send the public key to the server. The server then uses that public key to encrypt the sensitive data and only the receiving app can decrypt it using its private key. We currently have it up and running for Android but are facing issues for iPhone. I have looked all over and seen some suggestions but cannot seem to fix it.

The public key is sent to and stored on the server as a base64 encoded string and used serverside by

byte[] publicKeyBytes = Base64.decodeBase64(base64EncodedPublicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey publicKey = kf.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(rawStringToEncrypt.getBytes("UTF-8"));

This works for both iOS and Android. When generating the public key on iOS we needed to add the ASN1 headers etc manually before sending it to the server. But the server now accepts the keys sent from iOS and uses them for encrypting (everything looks OK there).
When an Android app receives encrypted data it simply does

byte[] privateKeyBytes = Base64.decodeBase64(base64EncodedPrivateKey.getBytes("UTF-8"));
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privateKey = kf.generatePrivate(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
String decryptedString = new String(cipher.doFinal(toDecrypt), "UTF-8");
return decryptedString;

where it creates its private key from a stored base64 string that it got when generating its key pair. For iOS however, we have tried a large number of different solutions but are never able to decrypt data that the server encrypts with our public key. We generate the KeyPair, manipulate the public key so we can send it to the server and then store our private key. We get the SecKeyRef from our keychain (also has tried to store it as bytes and create it from bytes) and perform SecKeyDecrypt with that key and have tested both kSecPaddingPKCS1 as well as kSecPaddingNone.

Does anyone have a working solution for decrypting data that a Java server encrypt the way I have described?

This content was originally published here.