My problem is: what I encrypt in Java I can decrypt perfectly in Java, but PHP mcrypt can't decrypt. What I encrypt with mcrypt I can decrypt with mcrypt, but can't in Java.

I want to send and receive cryptographed data from a Java application to a PHP page, so I need it to be compatible.

Here's what I have...

JAVA...

public static String crypt(String input, String key){
    byte[] crypted = null;
    try{
        SecretKeySpec skey = new SecretKeySpec(Base64.decodeBase64(key), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, skey);
        crypted = cipher.doFinal(input.getBytes());
    }catch(Exception e){
    }
    return Base64.encodeBase64String(crypted);
}

public static String decrypt(String input, String key){
    byte[] output = null;
    try{
        SecretKeySpec skey = new SecretKeySpec(Base64.decodeBase64(key), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, skey);
        output = cipher.doFinal(Base64.decodeBase64(input));
    }catch(Exception e){
    }
    return new String(output);
}

Running:

public static void main(String[] args) {
    String key = "Zvzpv8/PXbezPCZpxzQKzL/FeoPw68jIb+NONX/LIi8=";
    String data = "example";
    System.out.println(Cpt.decrypt(Cpt.crypt(data, key), key));
}

Output:

example

PHP...

function getEncrypt($sStr, $sKey) {
    return base64_encode(
        mcrypt_encrypt(
            MCRYPT_RIJNDAEL_256, 
            $sKey,
            $sStr,
            MCRYPT_MODE_ECB
        )
    );
}

function getDecrypt($sStr, $sKey) {
    return mcrypt_decrypt(
        MCRYPT_RIJNDAEL_256, 
        $sKey, 
        base64_decode($sStr), 
        MCRYPT_MODE_ECB
    );
}

Running:

$crypt = getDecrypt(getEncrypt($str, $key), $key);
echo "<p>Crypt: $crypt</p>";

Output:

Crypt: example�������������������������

Using PHP to crypt "example" with key "Zvzpv8/PXbezPCZpxzQKzL/FeoPw68jIb+NONX/LIi8=" I get "YTYhgp4zC+w5IsViTR5PUkHMX4i7JzvA6NJT1FqhoGY=". Using Java to crypt the same thing with the same key I get "+tdAZqTE7WAVPXhB3Tp5+g==".

I'm encoding and decoding to base64 in the right order and I tested base64 encode and decode compatibility between Java and PHP and it's working.

Accepted Answer

BUG#1

MCRYPT_RIJNDAEL_256 is not AES. The 256 in that constant refers to the blocksize, not the keysize. Use MCRYPT_RIJNDAEL_128 to get the same algorithm as AES. The keysize is set just by the number of bytes in the key argument you supply. So supply 32 bytes and you get AES with a 256-bit key.

BUG#2

These two lines are never correct in Java and indicate a fundamental misunderstanding of the nature of the arbitrary binary data produced by cryptographic transforms:

output = cipher.doFinal(Base64.decodeBase64(input));
return new String(output);

There is nothing wrong with transmitting and storing byte[] directly, but if you must use only printable strings then you should base64 encode/decode to do so. As you are already using base64 extensively that would seem like the way to go. I would guess that the correct two lines would be:

output = cipher.doFinal(Base64.decodeBase64(input));
return new String(Base64.encodeBase64(output), "UTF-8");

EDIT:

Just kidding about bug #2. Really, I was wrong, I didn't notice it was the decrypt direction. Of course, if you know the decrypted byte[] is a valid string then it is perfectly correct to do what your code does.

Written by GregS
This page was build to provide you fast access to the question and the direct accepted answer.
The content is written by members of the stackoverflow.com community.
It is licensed under cc-wiki