communistWatermelon communistWatermelon - 16 days ago 9
Android Question

BadPaddingException while decrypting RSA from other client

I'm writing an Android application that broadcasts its RSA public key to the network, and allows other clients to connect to it via TCP. I have my own custom protocol and packet structure, which I then encrypt and send to the client (packet -> AES -> RSA with client's public key -> client).

private String encryptPacket(String packet, String pubKey)
{
PublicKey clientPub = KeyFunctions.stringToKey(pubKey);
String aesEncryptedData = null;
byte[] rsaEncryptedData = null;
String temp = null;

try
{
// AES
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
final SecretKeySpec secretKey = new SecretKeySpec(Constants.KEY.getBytes(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
aesEncryptedData = Base64.encodeToString(cipher.doFinal(packet.getBytes()), Base64.NO_PADDING|Base64.NO_WRAP); //base64 the aes

// RSA
Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
c.init(Cipher.ENCRYPT_MODE, clientPub);
rsaEncryptedData = c.doFinal(aesEncryptedData.getBytes());
temp = Base64.encodeToString(rsaEncryptedData, Base64.NO_PADDING|Base64.NO_WRAP); // base 64 the rsa
Log.d("ENC SEND", temp);
} catch (Exception e)
{
e.printStackTrace();
}
return temp;
}

public String decryptPacket(String encryptedData, Context context)
{
// get the keys
PrivateKey pri = KeyFunctions.getPrivateKey(context);
byte[] packet = null;
byte[] decrypted = null;
String temp = null;

try
{
//RSA
Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
c.init(Cipher.DECRYPT_MODE, pri);
byte[] rsaTempArray = Base64.decode(encryptedData, Base64.NO_PADDING|Base64.NO_WRAP);
packet = c.doFinal(rsaTempArray);

// AES
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
final SecretKeySpec secretKey = new SecretKeySpec(Constants.KEY.getBytes(), "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
final String decryptedString = new String(cipher.doFinal(Base64.decode(packet, Base64.NO_PADDING|Base64.NO_WRAP)));
temp = decryptedString;
} catch (Exception e)
{
e.printStackTrace();
}
Log.d("ENC REC", temp);
return temp;
}


This code works when the client sends the data to themselves. However, it does not work when sending it to another client, giving me the following error:
javax.crypto.BadPaddingException: error:0407106B:rsa routines:RSA_padding_check_PKCS1_type_2:block type is not 02


This exception is raised on the decryptPacket call,
packet = c.doFinal(rsaTempArray);


I've attempted to verify that the value of the public key is correct through debug, and there doesn't seem to be any issues there.

Update

Here is the updated code

private byte[] encryptPacket(Packet packet, String pubKey)
{
PublicKey clientPub = KeyFunctions.stringToKey(pubKey);
byte[] aesEncryptedData = null;
byte[] rsaEncryptedData = null;
byte[] temp = null;

Log.d("START", "==========ENCRYPT==========");
try
{
// AES
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
final SecretKeySpec secretKey = new SecretKeySpec(Constants.KEY.getBytes(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte aesTempArray[] = cipher.doFinal(packet.getBytes());
Log.d("ENC AES TEMP", new String(aesTempArray, "UTF-8"));
aesEncryptedData = Base64.encode(aesTempArray, Base64.NO_PADDING | Base64.NO_WRAP); //base64 the aes
Log.d("ENC AES ENCR", new String(aesEncryptedData, "UTF-8"));

// RSA
Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
c.init(Cipher.ENCRYPT_MODE, clientPub);
rsaEncryptedData = c.doFinal(aesEncryptedData);
Log.d("ENC RSA ENCR", new String(rsaEncryptedData, "UTF-8"));
temp = Base64.encode(rsaEncryptedData, Base64.NO_PADDING | Base64.NO_WRAP); // base 64 the rsa
Log.d("ENC RSA TEMP", new String(temp, "UTF-8"));
} catch (Exception e)
{
e.printStackTrace();
}
return temp;
}

public Packet decryptPacket(byte[] encryptedData, Context context)
{
// get the keys
PrivateKey pri = KeyFunctions.getPrivateKey(context);
Packet p = null;
byte[] aesDecryptedData = null;
byte[] rsaDecryptedData = null;


Log.d("START", "==========DECRYPT==========");
try
{
//RSA
Log.d("DEC INIT", new String(encryptedData, "UTF-8"));
Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
c.init(Cipher.DECRYPT_MODE, pri);
byte[] rsaTempArray = Base64.decode(encryptedData, Base64.NO_PADDING | Base64.NO_WRAP);
Log.d("DEC RSA TEMP", new String(rsaTempArray, "UTF-8"));
rsaDecryptedData = c.doFinal(rsaTempArray);
Log.d("DEC RSA ENCR", new String(rsaDecryptedData, "UTF-8"));

// AES
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
final SecretKeySpec secretKey = new SecretKeySpec(Constants.KEY.getBytes(), "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] aesTempArray = Base64.decode(rsaDecryptedData, Base64.NO_PADDING | Base64.NO_WRAP);
Log.d("DEC AES TEMP", new String(aesTempArray, "UTF-8"));
aesDecryptedData = cipher.doFinal(aesTempArray);
Log.d("DEC AES DEC", new String(aesDecryptedData, "UTF-8"));
p = new Packet(aesDecryptedData);
} catch (Exception e)
{
e.printStackTrace();
}
return p;
}


The code no longer uses any strings, but still comes up with the same exception. I've now made sure that the receiver has received the exact same data that the client sent. The program works perfectly when the client sends the data to the server on the same device, but I get the exception above when I try to send to another devices server. Both devices have their own private key/ public key pair. Each device has each others public key.

Answer

Encryption/Decryption code was fine, I was using the wrong IP address to figure out the public key. Thanks for the help though!

Comments