Archived Forum Post

Index of archived forum posts

Question:

AES128/CBC/PKCS5Padding

Feb 11 '15 at 10:52

Hello,

I am using the following Delphi code: (http://www.example-code.com/delphi/aes_javaJceAesCbc.asp)

*** BEGIN DELPHI ****

procedure TForm1.Button2Click(Sender: TObject);
var
  success: integer;
  crypt:   TChilkatCrypt2;
  crypt2:  TChilkatCrypt2;
  pswhex:  String;
  text:    String;
  encText: String;
  encText1:String;
  ivhex:   String;
begin

crypt   := TChilkatCrypt2.Create(Self);
  success := crypt.UnlockComponent('30-day trial');
  if (success <> 1) then
    ShowMessage('Crypt component unlock failed');

crypt2  := TChilkatCrypt2.Create(Self);
  success := crypt2.UnlockComponent('30-day trial');
  if (success <> 1) then
    ShowMessage('Crypt component unlock failed');

crypt.CryptAlgorithm := 'aes';
  crypt.CipherMode     := 'cbc';
  crypt.KeyLength      := 128;
  crypt.PaddingScheme  := 0;
  crypt.EncodingMode   := 'hex';

// IV
  ivhex := '605bd70efed2c6374823b54bbc560b58';
  crypt.SetEncodedIV(ivhex, 'hex');

// Key
  pswhex := '605bd70efed2c6374823b54bbc560b58';
  crypt.SetEncodedKey(pswhex,'hex');

// Encrypted text
  text := 'Test';
  encText := crypt.EncryptStringENC(text);

crypt2.CryptAlgorithm := 'none';
  crypt2.EncodingMode   := 'base64';

encText1 := crypt.GetEncodedIV('hex') + encText;
  encText1 := crypt2.EncryptStringENC(encText1);
  Memo1.Lines.Add(encText1);

end;

*** END DELPHI
****

... to implement the following Java function:

*** BEGIN JAVA
****

private static final String ALGORITMO = "AES/CBC/PKCS5Padding";
private static final String CODIFICACION = "UTF-8";

public static String encrypt(String plaintext, String key)
        throws NoSuchAlgorithmException, NoSuchPaddingException,
        InvalidKeyException, IllegalBlockSizeException,
        BadPaddingException, IOException, DecoderException {

    byte[] raw = DatatypeConverter.parseHexBinary(key);

    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    Cipher cipher = Cipher.getInstance(ALGORITMO);
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

    byte[] cipherText = cipher.doFinal(plaintext.getBytes(CODIFICACION));
    byte[] iv = cipher.getIV();

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    outputStream.write(iv);
    outputStream.write(cipherText);

    byte[] finalData = outputStream.toByteArray();

    String encodedFinalData = DatatypeConverter
            .printBase64Binary(finalData);

    return encodedFinalData;

}

*** END JAVA
****

But Delphi encryption is different to Java encryption.

Please, Can you tell me why?


Answer

In Java, you are encrypting a UTF-8 byte array, but in Delphi you are encrypting a String - I'm unfamiliar with Delphi Strings, but are they UTF-8 encoded? If not, this could be the source of the different results.

What about your IVs? Are you sure they are the same in Delphi and in Java?

Lastly - It looks like you are encrypting twice in your Delphi code? Once to hex, then again by merging the IV and encrypted hex, and then re-encrypting to Base64? Why not use bas64 encoding for the first pass, and skip the second encryption step?


Answer

Your Java code was not following the same as what was provided in the reference example:

This is the equivalent code using Java JCE:

String password = "secretPassphrase";

MessageDigest md = MessageDigest.getInstance("MD5");
md.update(password.getBytes("UTF-8"), 0, password.length());
byte[] rawKey = md.digest();
String text = "Though this be madness, yet there is method in 't";

SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(rawKey);

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);

byte[] encrypted = cipher.doFinal(text.getBytes("UTF-8"));

System.out.println(toHex(encrypted));

This is the toHex method in Java:
public static String toHex (byte buf[]) {

StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;

for (i = 0; i < buf.length; i++) 
    {
    if (((int) buf[i] & 0xff) < 0x10)
    strbuf.append("0");

strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
    }

return strbuf.toString();
}