Page 1 of 1

javax.crypto.BadPaddingException

Posted: Wed Jun 28, 2017 11:40 pm
by Heather
I have coded a part of an applet which sends the public key from the smart card to an offcard side. To check the public key is sent properly, I am trying to encode a text with the public key of the smart card in the offcard side and sent to the smart card which decode it with its private key and return the plain text. But when I run the offcard side, it appears the following error:
javax.crypto.BadPaddingException: Message is larger than modulus


Have anyone experienced this issue? Please help me out.

The code of the off card side:

Code: Select all

// Text to send
byte [] s = {(byte) 'H', (byte) 'i'};
RSAPublicKeySpec pubKeySpec;
KeyFactory keyFactory = null;
PublicKey pubKey = null ;
Cipher cipher = null;

// Get the data from the apdu
byte[] publicKeyMessage = apdu.getDataOut();
byte[] modulusArray = new byte [64];

// Get the modulus from the public key sent in the apdu
for (int i=0; i<64; i++){
       modulusArray[i] = publicKeyMessage[i+2];
}
byte[] exponentArray = new byte [3];

// Get the modulus from the public key sent in the apdu
for (int i=0; i<3; i++){
     exponentArray[i] = publicKeyMessage[i+68];
}

BigInteger modulus = new BigInteger(modulusArray);
BigInteger exponent = new BigInteger(exponentArray);
       
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
pubKeySpec = new RSAPublicKeySpec(modulus, exponent);
keyFactory = KeyFactory.getInstance("RSA");

// Build the public Key by means of the modulus and exponent specs
pubKey = keyFactory.generatePublic(pubKeySpec);

// Indicate the cipher to use the pubKey which has just been built
cipher.init(Cipher.ENCRYPT_MODE,pubKey);
byte[] p = new byte[64];

// Encrypt with the public key
cipher.doFinal(s, 0, s.length, p, 0);



Part of the applet code:

Code: Select all


// In the constructor:
...
RSACipher = Cipher.getInstance(Cipher.ALG_RSA_PKCS1,false);
...

//In the process method:
...
buffer = apdu.getBuffer();
byte [] buf = null;

// Get the encoded message
short numBytes = apdu.setIncomingAndReceive();

// Copy to a aux buffer
Util.arrayCopy(buf, ISO7816.OFFSET_CDATA, buffer, (short)0, numBytes);

// Initialize the cipher and decrypt to send the plain text again
RSACipher.init(PrivateKeyRSAEnc,Cipher.MODE_DECRYPT); 
RSACipher.doFinal(buf,(short)0,numBytes,buffer,(short)0);
apdu.setOutgoingAndSend((short) 0, numBytes);
...

Re: javax.crypto.BadPaddingException

Posted: Thu Jun 29, 2017 4:11 am
by mabel
Try to replace the following code

Code: Select all

byte[] p = new byte[64];
 
// Encrypt with the public key
cipher.doFinal(s, 0, s.length, p, 0);


with

Code: Select all

// Encrypt with the public key
byte[] p = cipher.doFinal(s);

Re: javax.crypto.BadPaddingException

Posted: Thu Jun 29, 2017 5:10 am
by Heather
I did as you said, but the error is still there. :cry:

Re: javax.crypto.BadPaddingException

Posted: Fri Jun 30, 2017 5:31 am
by Tarantino
You just need to add a check for a negative modulus coming from the card. In RSA encryption, you use large integers for the calculation. Even the message is converted to a large integer. For the equation to work, the message has to be smaller than the modulus.
If the first bit of your modulus from the card is set, add a 0x00 byte to front before setting the modulus in your key spec instance.

Re: javax.crypto.BadPaddingException

Posted: Sun Jul 02, 2017 9:17 am
by tay00000
I noticed some possible programming flaws:

Code: Select all

// In the constructor:
...
RSACipher = Cipher.getInstance(Cipher.ALG_RSA_PKCS1,false);
...

//In the process method:
...
buffer = apdu.getBuffer();
byte [] buf = null;  // <----- buf variable is null, what is it used for ??

// Get the encoded message
short numBytes = apdu.setIncomingAndReceive();

// Copy to a aux buffer
Util.arrayCopy(buf, ISO7816.OFFSET_CDATA, buffer, (short)0, numBytes); // <---- why are you copying null buf as source to buffer ??

// Initialize the cipher and decrypt to send the plain text again
RSACipher.init(PrivateKeyRSAEnc,Cipher.MODE_DECRYPT); 
RSACipher.doFinal(buf,(short)0,numBytes,buffer,(short)0); // <---- why are you attempting to put a null buf variable as source for RSA operation ?????!!
apdu.setOutgoingAndSend((short) 0, numBytes);


I noticed a null type 'buf' object that is not having any value of it's own being put into the RSA decrytion operation in my comments above. Are you actually trying to copy data from 'buffer' into 'buf' and messed that part up ?

Also, another alternative is to directly read the buffer and decrypt. Not highly advisable but can be done to simplify the codes and with lesser codes comes lesser errors as shown below. Below, it will read directly from the incoming APDU buffer and then perform RSA operation on the data within APDU buffer without needing to store somewhere else.

Code: Select all

// Allocate a temporary RAM memory flag for storing amount of processed bytes for RSA op
short[] sBuf = JCSystem.makeTransientShortArray((short 1, JCSystem.CLEAR_ON_DESELECT);

// Perform RSA op and store in temp flag the amount of processed bytes
sBuf[0] = RSACipher.doFinal(buffer, (short) 0, numBytes, buffer, (short) 0);

// Send out the processed bytes as per the amount of bytes returned from RSA op
apdu.setOutgoingAndSend((short) 0, sBuff[0]);


A lazier method as shown below if you feel very adventurous and very lazy by simply combining the RSA op with the output of result.

Code: Select all

// Send out the processed bytes as per the amount of bytes returned from RSA op using a single line of code
apdu.setOutgoingAndSend((short) 0, RSACipher.doFinal(buffer, (short) 0, numBytes, buffer, (short) 0));