Search code examples
javaphpaes

AES-Rijndael 128 encryption in Java from PHP


I have a piece of code in PHP

    function encrypt($data){
$data = "{\"userId\":11,\"email\":\"ssss.bansa11l1989@gmail.com\",\"firstName\":\"Ankit\",\"lastName\":\"Bansal\",\"displayName\":\"banank1989\",\"visitorId\":\"1222222234455\"}";

            $td = mcrypt_module_open('rijndael-128', '', 'cbc', $this->iv);

            mcrypt_generic_init($td, $this->key, $this->iv);
            $encrypted = mcrypt_generic($td, $data);

            mcrypt_generic_deinit($td);
            mcrypt_module_close($td);

            return bin2hex($encrypted);
        }

Now when I am trying to write the same code in java, it is giving me the different output

public String encrypt(String value) {
        try {

            value="{\"userId\":11,\"email\":\"ssss.bansa11l1989@gmail.com\",\"firstName\":\"Ankit\",\"lastName\":\"Bansal\",\"displayName\":\"banank1989\",\"visitorId\":\"1222222234455\"}";
            String initVector = "fedcba9876111111";
            String key = "012345678911111";
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");

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

            byte[] encrypted = cipher.doFinal(value.getBytes());
            return new String(Base64.encodeBase64(encrypted));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

Now the issue is both code are giving me the different result for the same provided JSON.

I cant change the PHP code, so I have to change JAVA code.


Solution

  • The Java and the PHP-code differ:

    • In the PHP-code Zero-Byte-Padding is used, because this is mcrypt's default padding (see here). In contrast, in the Java-code PKCS7-Padding (in Java also called PKCS5) is used. To use Zero-Byte-Padding in the Java-code, first, deactivate PKCS7 padding by replacing AES/CBC/PKCS5PADDING with AES/CBC/NoPadding. Second, implement manually Zero-Byte-Padding, i.e. add n 0-values (with 0 <= n < 16) to the message's byte-sequence until the length corresponds to an integer multiple of the blocksize (16 Byte).
    • In the PHP-code the encrypted data are returned as hex-string. In contrast, in the Java-code the encrypted data are returned Base64-encoded. To change the latter you have to convert the encrypted data into a hex-string, see e.g. How to convert a byte array to a hex string in Java?.

    With these changes, Java- and PHP-code will produce the same result if the same key and the same IV are used (btw the key in the Java-code has a length of 15 byte which results in an InvalidKeyException (Invalid AES key length: 15 bytes)).

    Note mcrypt is deprecated and Zero-Byte-Padding isn't reliable. If you have the choice to change the padding, PKCS7 is preferable.