0
votes

We are using below java code to decrypt the data which is encrypted using AES-256 in CBC mode and PKCS7 padding.

Java Code:

import javax.crypto.spec.SecretKeySpec;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import java.security.*;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;


public class AES256 {

    private static byte[] initVector = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

    public String decrypt (String encryptedDataBase64, String keyBase64)
    {
       try {
           Security.setProperty("crypto.policy", "unlimited");
           IvParameterSpec ivSpec = new IvParameterSpec(initVector);  // Get the init vector

           // Get the Base64-encoded key
           byte[] key = Base64.decodeBase64(keyBase64.getBytes("UTF-8"));
           Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");  // AES / CBC / PKCS5 padding
           SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
           cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
           byte[] encryptedData = Base64.decodeBase64(encryptedDataBase64.getBytes("UTF-8"));
           byte[] decryptedData = cipher.doFinal(encryptedData);

           return new String(decryptedData);
       }
       catch (Exception e) {
           logger.error("AES256 Decrypt: Decryption exception: "+ e.getMessage());
           return null;
       }
    }
}

Now we need to convert this decryption logic to Python as our app is sending the encrypted data in the headers while requesting for index.html from server. I tried to decrypt using Crypto. It is giving the decrypted string but also some additional characters in the end.

import base64
from Crypto.Cipher import AES

key = base64.b64decode(myKeyBase64)
enc = base64.b64decode(encDataBase64)
ivBase = base64.b64decode('AAAAAAAAAAAAAAAAAAAAAA==');
cipher = AES.new(key, AES.MODE_CBC, ivBase)
cipher.decrypt(enc).decode('utf-8')

It is decrypting properly but in the end it is giving some extra characters which are not in the original string like 'myText\x06\x06\x06\x06\x06\x06'.

I tried this after reading some of stack over flow questions. Can any one please let me know if there is any error in the code.

1
On Java side you are instantiate your cipher with '...PKCS5PADDING' that means that the plaintext is filled up with characters to have a length of 16 (or multiple of 16). The number of character that are added is the value added, so when adding 6 characters each padding character gets the value x06 as in your example. When decrypting (that's your part above) you need to strip of the last 6 x06 characters.Michael Fehr
Is it true for all the strings? I mean for any string I encrypt, does it always return 6 extra characters if I decrypt through my python code. Btw, my team is using PKCS7 padding when they are encrypting on Java side. I guess I didn't understand your comment properly. Can you please elaborate.kadina

1 Answers

2
votes

To encrypt a byte array with AES you do need exactly a 16 byte long array - then you could use a '...NoPadding'.

Having e.g. a 13 character long string and you transform the string to a byte array this array is 13 bytes long. Using PKCS5 the byte array is filled up with 3 bytes of value x03. If you need to fill up 7 characters all 7 bytes will have the value x07, missing 10 chars result in 10 bytes of x0a.

To strip of the padding just read the last byte (e.g. x0a = '10') and remove the last 10 bytes to get the original string.

On Java-side the naming is PKCS5Padding that is (mostly) identical to PKCS7Padding (this naming is used in other frameworks/languages).