AES Interop Between PHP and Java (Part 1)

… Life is never easy, learning takes time. Hope this will help someone out there …

The Problem: I want to encrypt a message in PHP using AES and then take it to a Java program to decrypt it.

Without all the knowledge about AES, Key, CBC, ECB, etc, etc… I will present a simple solution. Keep in mind, these are bits and pieces, so that I wouldn’t take all the fun out of you. I will just show you how to encrypt and decrypt and you can implement other things in between so that you can also have the fun.

The Solution:

  1. We are using mcrypt with PHP. The encryption program in PHP:
    001	<?php
    002	  $cipher     = "rijndael-128";
    003	  $mode       = "cbc";
    004	  $plain_text = "Hello World";
    005	  $secret_key = "01234567890abcde";
    006	  $iv         = "fedcba9876543210";
    007
    008	  td = mcrypt_module_open($cipher, "", $mode, $iv);
    009	  mcrypt_generic_init($td, $secret_key, $iv);
    010	  $cyper_text = mcrypt_generic($td, $plain_text);
    011	  echo bin2hex($cyper_text);
    012	  mcrypt_generic_deinit($td);
    013	  mcrypt_module_close($td);
    014	?>
  2. The output from the above program should be “ac5c3404f57a5061f36a694eb5d56214″
  3. We just take the output and decrypt it over in the following Java program:
    001	import javax.crypto.spec.IvParameterSpec;
    002	import javax.crypto.Cipher;
    003	import java.security.MessageDigest;
    004	import java.security.NoSuchAlgorithmException;
    005	import java.lang.Exception;
    006	import javax.crypto.spec.SecretKeySpec;
    007	import javax.crypto.SecretKey;
    008	import java.io.IOException;
    009
    010	public class tester {
    011	  public static byte[] hexToBytes(String str) {
    012	    if (str==null) {
    013	      return null;
    014	    } else if (str.length() < 2) {
    015	      return null;
    016	    } else {
    017	      int len = str.length() / 2;
    018	      byte[] buffer = new byte[len];
    019	      for (int i=0; i<len; i++) {
    020	        buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16);
    021	      }
    022	      return buffer;
    023	    }
    024	  }
    025
    026	  public static void main(String [] args) throws Exception {
    027	    Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
    028	    SecretKeySpec keySpec = new SecretKeySpec("01234567890abcde".getBytes(), "AES");
    029	    IvParameterSpec ivSpec = new IvParameterSpec("fedcba9876543210".getBytes());
    030	    cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
    031	    byte[] outText = cipher.doFinal(hexToBytes("ac5c3404f57a5061f36a694eb5d56214"));
    032	    System.out.println(new String(outText).trim());
    033	  }
    034	}
  4. The output from the Java program should be “Hello World”. Take note that on line 31, we put in the output from PHP.

23 Responses to “AES Interop Between PHP and Java (Part 1)”

  1. Amit Agarwal Says:

    Hi..

    Is it possible to do other way round ? encypting in Java and decrypting in PHP ?

    Thanks

  2. Marc Liyanage Says:

    Hey thanks a lot, exactly what I needed, exactly when I needed it :-)
    I really wish mcrypt had PKCS#5 padding…

  3. linus Says:

    Marc: Thanks, I wish mcrypt has PKCS5 padding too. I think someone wrote a function for it. Check out http://www.php.net/mcrypt (comment from duerra_NOT_THIS_ at pushitlive dot net).

    Amit: I have been away for a long Chinese New Year holidays and finally get around to do a post of what you are looking for, encrypting in Java and decrypting in PHP. Check out my new post at http://www.propaso.com/blog/2007/03/12/aes-interop-between-php-and-java-part-2-working-the-other-way-around/

  4. robi Says:

    i tried to encrypt with very long text
    but the result is error
    it said that the string is too long
    can u help me???

  5. robi Says:

    sorry with the 1st post
    i mean decrypt not encrypt

  6. linus Says:

    I assume that you are encrypting with PHP and decrypting with Java. Could you give an idea of how long is your string (in term of number of characters)??

  7. robi Says:

    yo’re right i’m encrypting with php and decrypt with java..
    i copy the hexadesimal string from encrypted file
    the string long is 507808 character

  8. robi Says:

    this is the string
    1a3d8846133fc5……1ebcd6f2544c777c1779

  9. Fun Things in Life » Blog Archive » AES Interop Between PHP and Java (Part 3) Says:

    […] Problem: Part 1 and Part 2 has been quite interesting. I was thinking of what to do next and Robi Ilham asked me to […]

  10. Fun Things in Life » Blog Archive » AES Interop Between PHP and Java (Part 2) Says:

    […] Problem: In a previous post, I show how to use AES in PHP to encrypt a message and decrypt it in Java. Then Amit asked if it […]

  11. Ken Beukelman Says:

    Should the final parameter in the call to mcrypt_module_open be “” (rather than $iv)?

  12. linus Says:

    In Java, we set the initial vector to

    IvParameterSpec ivSpec = new IvParameterSpec(”fedcba9876543210″.getBytes());

    for decryption, so the initial vector in PHP for encryption should be the corresponding

    mcrypt_generic_init($td, $secret_key, $iv);

    where $iv is set to “fedcba9876543210″

  13. Joel Nylund Says:

    Hi, im trying to encrypt using php and decript using ruby. Im having trouble getting ruby to do the same and I think its either a padding or a encoding issue. I took your example and the php part works fine, my ruby example is here:

    1. secret = “01234567890abcde”
    2. otherCval = “Hello World”
    3. c3 = OpenSSL::Cipher::Cipher.new(”aes-128-cbc”)
    4. c3.key = key3 = Digest::SHA1.hexdigest(secret).unpack(’a2′*16).map{|x| x.hex}.pack(’c'*16)
    5. c3.iv = “fedcba9876543210″
    6. c3.decrypt
    7. hexval = “ac5c3404f57a5061f36a694eb5d56214″
    8. regval = hexval.unpack(’a2′*16).map{|x| x.hex}.pack(’c'*16) %>
    9. regval =
    10. d = c3.update(regval)
    11. d

  14. m clayton Says:

    How can I store my key in a password protected file for later use?
    M

  15. Abdul Hameed Says:

    Hi,
    Can someone help me. I have been trying to do this and it is almost a week now. I am stuck in the final.

    Actually the php team has written the encryption and decryption program and it needs to be converted to java. This means that the php server will send some encrypted info and the key to java server and java should decrypt it and vice versa.
    The php version of encryption is:
    ———————————————
    function encrypt($val, $key)
    {
    $key = hex2bin($key);
    $td = mcrypt_module_open (’xtea’, ”, ‘ecb’, ”);
    mcrypt_generic_init ($td, $key, “00000000″);
    $encrypted_data = mcrypt_generic ($td, $val);
    mcrypt_generic_deinit ($td);
    mcrypt_module_close ($td);
    return bin2hex($encrypted_data);
    }
    ————————————————–
    and the java equivalent that i wrote was :
    public static void main(String[] args) throws Exception
    {
    String key = “01234567890abcde01234567890abcde”;
    String data = “Hello World”;
    byte[] byteValKey = hexToBytes(key);

    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    SecretKeySpec keyspec = new SecretKeySpec(byteValKey, “XTEA”);
    Cipher cipher1 = Cipher.getInstance(”XTEA/ECB/PKCS5Padding”,”BC”);

    cipher1.init(Cipher.ENCRYPT_MODE, keyspec);
    byte[] encrypted = cipher1.doFinal(data.getBytes());

    System.out.println(”Encrypted: ” + bytesToHex(encrypted));
    }
    ————————————————————
    the decryption program for php is:
    function decrypt($crypt, $key)
    {
    $key = hex2bin($key);
    $crypt = hex2bin($crypt);
    $td = mcrypt_module_open (’xtea’, ”, ‘ecb’, ”);
    mcrypt_generic_init ($td, $key, “00000000″);
    $decrypted_data = mdecrypt_generic ($td, $crypt);
    mcrypt_generic_deinit ($td);
    mcrypt_module_close ($td);
    return rtrim($decrypted_data);
    }
    ——————————————————–
    when i tried to encrypt a string say “Hello World” and get the result and feed this result in the php decrypt program, then i see “Hello World” + some special characters at the end. I do not know how those special characters appear. I think i have give the wrong padding or i really dont know where i am wrong. Also i am yet to write the equivalent decrypt function in java. Can anyone please help.

    Thanks so much

  16. linus Says:

    Let me quote from php.net manual (by duerra_NOT_THIS_ at pushitlive dot net):

    < ?

    function encrypt_something($input)
    {
    $size = mcrypt_get_block_size('des', 'ecb');
    $input = pkcs5_pad($input, $size);

    $key = 'YOUR SECRET KEY HERE';
    $td = mcrypt_module_open('des', '', 'ecb', '');
    $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
    mcrypt_generic_init($td, $key, $iv);
    $data = mcrypt_generic($td, $input);
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    $data = base64_encode($data);
    return $data;
    }

    function pkcs5_pad ($text, $blocksize)
    {
    $pad = $blocksize - (strlen($text) % $blocksize);
    return $text . str_repeat(chr($pad), $pad);
    }

    function pkcs5_unpad($text)
    {
    $pad = ord($text{strlen($text)-1});
    if ($pad > strlen($text)) return false;
    if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false;
    return substr($text, 0, -1 * $pad);
    }
    ?>

  17. Pravin Kamble Says:

    I have a requirement of same encryption in Java and PHP both.Since I am entering data like user id i.e email id from Java client and Vaildating it from PHP client when user try to login.
    I need the same encryption from both Java and PHP.I have the following code in PHP and Java giving me 2 different output for same input string.
    Any help is appreciated.
    Following are the Encryption code in JAVA and PHP

    public static String encryptString(String plaintext) {
    // String plaintext = padString(”password insurent”,’ ‘,16);
    String padedtext = padString(plaintext, ‘ ‘, 16);
    String key = “17293045806insur”;
    String iv = “fedcba9876543210″;

    SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), “AES”);
    IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
    Cipher cipher;
    byte[] encrypted = null;
    try {
    cipher = Cipher.getInstance(”AES/CBC/NoPadding”);
    cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
    encrypted = cipher.doFinal(padedtext.getBytes());
    } catch (NoSuchAlgorithmException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (NoSuchPaddingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (InvalidKeyException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (InvalidAlgorithmParameterException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (BadPaddingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    System.out.println(”Encrypted: ” + bytesToHex(encrypted));
    return bytesToHex(encrypted);

    }
    from java
    input=”pkamble@insurent.com”
    output =d02b17d1f918d4d0c38f1f19094d2e0e998e45fa62df7bd3942d1add3caa29e3

    from php for input=”pkamble@insurent.com”
    output =d02b17d1f918d4d0c38f1f19094d2e0e988cd26028732c56fd2cf875989b3d4d
    PHP Code

  18. linus Says:

    Hi Pravin,

    Sorry can you post your PHP code again?

  19. Sandhya Ashokan Says:

    Hi Pravin,

    We have used the php and java encryption and decryption code that was explained in the blog. It seems quite helpful.

    We are able to do the encryption/decryption in all below 4 cases. Viz
    1. File encrypted in php and decrypted in php on the same machine - Works
    2. File encrypted in Java and decrypted in Java on the same machine - Works
    3. File encrypted in php and decrypted in Java on the same machine - Works
    4. File encrypted in Java and decrypted in php on the same machine - Works

    However, when we download the encrypted file using an ftpclient or java FTPClient library, the downloaded file becomes corrupt and the decryption fails.

    The server used was windows 2003 and ftpclient is filezilla.

    Can you help us with this one. Is there any solution as to not corrupt the encrypted file using any ftpclient.

    When Decrypting the downloaded file, only a few characters get decrypted, and all other character become Junk.

    Can you please help us.

    Thanks
    Sandhya

  20. linus Says:

    Hi Sandhya,

    What you explained, does not make sense. If you can encrypt a file, copy it via a flash drive to another machine and decrypt it. You basically can ftp and download it.

    Please double check your keys, etc.

  21. catherine Says:

    Hi linus.. im a starter on cryptography programming. currently im doing an a simple encryption software that work like an article you posted above. the problem is, how to make the length of the cipher text become shorter, maybe 8 character? in other side, the java also able to decrypt it. which part should i add or modify? thanks..

  22. linus Says:

    Hi Catherine,

    If I haven’t returned all the knowledge my lecturer taught me during collage days, for encryption, cypher text increase with the amount of plain text that you have. This is not the same as hashes like MD5, SHA, etc., which only product a specific length of digest.

  23. catherine Says:

    i see.. anyway that’s not a problem.. :)
    currently i am facing a problem which when i use a decryption on j2me sdk. some errors are shown up on SecretKeySpec, IvParameterSpec with the cannot find symbol warning. i have import the correct package. im really stuck on this now. please help me… this is my final year project and the submission date gonna be next week.. thanks alot…

Leave a Reply