RIJNDAEL encryption with Java
java, php, rijndael
Solution
It isn't documented well, but PHP's `MCRYPT_RIJNDAEL_128` with `MCRYPT_MODE_CFB` produces results consistent with Java's `AES/CFB8/NoPadding`.
So this line in PHP:
$encrypted = base64_encode( mcrypt_encrypt( MCRYPT_RIJNDAEL_128, $key, $cleartext, MCRYPT_MODE_CFB, $iv ) );
Matches up to this block in Java:
SecretKeySpec key = new SecretKeySpec(KEY.getBytes(), "AES");
IvParameterSpec iv = new IvParameterSpec(IV.getBytes());
Cipher cipher = Cipher.getInstance("AES/CFB8/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] output = cipher.doFinal(cleartext.getBytes());
String signature = Base64.encode(output);
Problem
I need to encode a cleartext in Java and php where the result must be the same. The following conditions are given: - algorithm: RIJNDAEL-128 - key: 1234567890123456 - mode: cfb - initialization vector: 1234567890123456 The following codes works and fulfils the first an the second requirement but it uses ECB as mode and therefore does not use an initalization vector: PHP: ``` <?php $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); $cleartext = 'abcdefghijklmnop'; $key128 = '1234567890123456'; $iv = '1234567890123456'; if (mcrypt_generic_init($cipher, $key128, $iv) != -1) //Parameter iv will be ignored in ECB mode { $cipherText = mcrypt_generic($cipher,$cleartext ); mcrypt_generic_deinit($cipher); printf(bin2hex($cipherText)); } ?> ``` Output is: fcad715bd73b5cb0488f840f3bad7889 JAVA: ``` public class AES { public static void main(String[] args) throws Exception { String cleartext = "abcdefghijklmnop"; String key = "1234567890123456"; SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(cleartext.getBytes()); System.out.println(asHex(encrypted)); } public static String asHex(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(); } } ``` Output is (the same as in the PHP version): fcad715bd73b5cb0488f840f3bad7889 So now in order to fulfill requirement 3 and 4 I changed the mode to MCRYPT_MODE_CFB in my PHP version so that the code looks like this: ``` <?php $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CFB, ''); $cleartext = 'abcdefghijklmnop'; $key128 = '1234567890123456'; $iv = '1234567890123456'; if (mcrypt_generic_init($cipher, $key128, $iv) != -1) //Parameter iv will be ignored in ECB mode { $cipherText = mcrypt_generic($cipher,$cleartext ); mcrypt_generic_deinit($cipher); printf(bin2hex($cipherText)); } ?> ``` This results in the following output: 14a53328feee801b3ee67b2fd627fea0 In the JAVA version I also adapted the mode and added the iv to the init function of my Cipher object. ``` public class AES { public static void main(String[] args) throws Exception { String cleartext = "abcdefghijklmnop"; String key = "1234567890123456"; SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES"); Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec("1234567890123456".getBytes())); byte[] encrypted = cipher.doFinal(cleartext.getBytes()); System.out.println(asHex(encrypted)); } public static String asHex(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(); } } ``` But here the output is 141eae68b93af782b284879a55b36f70 which is different to the PHP version. Does anybody have a clue what the difference betwenn the JAVA and the PHP version could be?