Encrypt with PHP – Decrypt with Java


For security reason, I wanted to encrypt the data transferred between PHP web services and a Java application. But the problem was to encrypt the data with PHP in a way that it is possible to decrypt it using Java.

It obviously exists a lot of ways of doing this. But here is the way I choose:

  • Use a secret key and an initialisation vector for the encryption and decryption
  • Use the mcrypt PHP module for the encryption
  • Use the javax.crypto Java package for the decryption

Please find below the PHP code for the encryption:

function encrypt($message, $initialVector, $secretKey) {
    return base64_encode(
        mcrypt_encrypt( 
            MCRYPT_RIJNDAEL_128,
            md5($secretKey),
            $message,  
            MCRYPT_MODE_CFB,
            $initialVector
        )
    );
}

And please see below the Java code for the decryption:

public static String md5(String input) throws NoSuchAlgorithmException {
    MessageDigest md = MessageDigest.getInstance("MD5");
    byte[] messageDigest = md.digest(input.getBytes());
    BigInteger number = new BigInteger(1, messageDigest);
    return number.toString(16);
}

public String decrypt(String encryptedData, String initialVectorString, String secretKey) {
    String decryptedData = null;
    try {
        SecretKeySpec skeySpec = new SecretKeySpec(md5(secretKey).getBytes(), "AES");
        IvParameterSpec initialVector = new IvParameterSpec(initialVectorString.getBytes());
        Cipher cipher = Cipher.getInstance("AES/CFB8/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, initialVector);
        byte[] encryptedByteArray = (new org.apache.commons.codec.binary.Base64()).decode(encryptedData.getBytes());
        byte[] decryptedByteArray = cipher.doFinal(encryptedByteArray);
        decryptedData = new String(decryptedByteArray, "UTF8");
    } catch (Exception e) {
        LOGGER.debug("Problem decrypting the data", e);
    }
    return decryptedData;
}

EDIT: The line number.toString(16) of the md5 method needs to be replaced by String.format("%032x", number). See this article for more details.

, , , , ,


  1. #1 by Chan Min Yan on 11 Nov 2010 - 02:54

    Hi there,

    I am using the following php function for the encryption:

    function encrypt($content)
    {
    global $mcrypt_cipher;
    global $mcrypt_mode;

    $key = substr(sha1($this->_key), 0, mcrypt_get_key_size($mcrypt_cipher, $mcrypt_mode));

    //create IV
    $iv_size = mcrypt_get_iv_size($mcrypt_cipher, $mcrypt_mode);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

    //concatenate the IV with the encrypted data
    $encrypted_content = $iv . mcrypt_encrypt($mcrypt_cipher, $key, $content, $mcrypt_mode, $iv );

    //encode data
    $encrypted_content_encoded = base64_encode($encrypted_content);

    return $encrypted_content_encoded;
    }

    Is it possible to have java decryption performance on data encrypted by the above method? Or do I need to do some modifications to the encryption method?

    Thank you so much for the advise.

  2. #2 by smoreau on 11 Nov 2010 - 12:36

    Hi,

    I had the same problem than you. I was using the same kind of complicated encryption code and I tried to get Java to decrypt the result.
    But after spending a few frustrating hours on the problem, I decided to simply use another (easier) encryption method.

    In other words, it is probably possible to decrypt the data encrypted with your method using Java. But the question really is: do you have the time to find the solution? ;)

  3. #3 by Isana on 25 Nov 2010 - 14:08

    Hello,

    We’re trying to use the PHP and JAVA functions you’ve suggested, but your guide is missing some information:

    1) How are the $initialVector and $secretKey variables created?
    2) Is the $initialVector a fixed constant or does it change in each function call.
    3) Should the above variables be the same on the Java implementation as well?

    Thanks in advance for your help,
    Isana.

  4. #4 by smoreau on 25 Nov 2010 - 15:21

    Hi Isana,

    You are right, this guide is missing some information about the two variables $initialVector and $secretKey. Sorry about it!

    These variables are actually constant. Their values have been set during the development phase and they never changed.
    For example, in my application, the $initialVector variable is a 16 characters string and the $secretKey is a sentence of about 100 characters. But it doesn’t matter, you can obviously put anything you want.

    Why did I introduce these two variables? It was to make sure that the data won’t be readable by a non-trusted person.

    So to answer your questions:
    1) They are manually created during the development phase
    2) Both variables are fixed constant
    3) Yes

  5. #5 by Chan Min Yan on 01 Dec 2010 - 18:23

    Hi Smoreau,

    May I ask some questions:

    I am doing php encryption and java decryption:

    For my php encryption:
    My Secret Key is a 16-byte long string constant, plain and simple here.

    My IV (InitialVector) is a 32-byte long string created using mcrypt_create_iv($iv_size, MCRYPT_RAND), where $iv_size is 32, and MCRYPT_RAND is the system random number generator.

    It is then prepended to the encrypted string, and the resultant string is then Base64 encoded.

    My Java Decryption Process:

    – The Base64 Decoding – No Issue with this.
    – The IV String – This is where I am stuck:
    The IV size of 32 bytes is giving this error below:
    java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long
    Question: Do you have any idea why I’m getting this? Is there a way to work around this issue?

    Thank you so much for reading my message, would really appreciate any suggestions or feedback. :-)

    Live Long and Prosper
    MY

  6. #6 by Vikas on 02 Dec 2010 - 02:46

    Thanks for the code , was helpful.

  7. #7 by smoreau on 02 Dec 2010 - 11:26

    Hi Chan Min Yan,

    AES has a 128-bit (i.e. 16-bytes) block size and it mandates an IV size equal to the block size.
    Which means that you need to use an IV size of 16 bytes instead of 32 bytes.

    Hope it helps.

  8. #8 by Chan Min Yan on 02 Dec 2010 - 11:53

    Hi Smoreau,

    Thank you for the prompt response.

    I am using AES 256-bit encryption. That should mean the block size should be 32-bytes, right? This is why it puzzles me why 32 bytes did not work for us.

    Live Long and Prosper
    MY

  9. #9 by smoreau on 02 Dec 2010 - 12:10

    Hi Chan Min Yan,

    Please have a look at the following article on Wikipedia: http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
    In the introduction section, you would read:
    “The standard comprises three block ciphers, AES-128, AES-192 and AES-256, adopted from a larger collection originally published as Rijndael. Each of these ciphers has a 128-bit block size, with key sizes of 128, 192 and 256 bits, respectively.”

    So it seems that even AES 256-bit is using a 128-bit (16 bytes) block size. :)

  10. #10 by Chan Min Yan on 02 Dec 2010 - 13:46

    Hi Smoreau,

    Thanks for pointing that out to me. :-)

    Apparently the 32-byte IV size did not give any error/exception for our PHP code. I wonder why. Perhaps PHP is less stricter compared to Java in respect to this particular instance of AES implementation?

  11. #11 by smoreau on 02 Dec 2010 - 16:45

    Hi Chan Min Yan,

    To be honest, I am not sure why PHP lets you use a 32-byte IV size. :(
    Did you anyway get your code working with an IV size of 16 bytes?

    Cheers.

  12. #12 by Chan Min Yan on 13 Dec 2010 - 18:38

    Hi Smoreau,

    The problem, as expected, was resolved after the IV size is changed to 16-byte. Thank you so much for your patient assistance. ^_^

    Live Long and Prosper
    MY

  13. #13 by alpha on 20 Jun 2011 - 22:00

    hello all,
    my lecturer had asked me to encrypt the message using php codes i.e to design a website so that some one must be able to send message and appear to DB as an encrypted message using such encrypted method. I don’t know how to do or where to put encryption codes in my html codes! someone with idea may help me. i wonder if i will use simplest encryption method.
    Thank you.

  14. #14 by smoreau on 20 Jun 2011 - 22:11

    You could simply use the two base64 PHP functions:
    Encode: base64_encode
    Decode: base64_decode

    Encode the message before you insert it into the database and decode it when you retrieve the message from the database.

  15. #15 by manish pandey on 23 Aug 2011 - 14:25

    Hi Smoreau,

    I ran your peice of code written above to decrypt in Java using Key=”0123456789123456″
    IV=”0123456789123456″
    with the encryptted text but i see that it gives an error that Illegal Key Size while initializing the Cipher.

  16. #16 by manish pandey on 23 Aug 2011 - 14:28

    In fact, I am not able to figure out what to give as the key,Could you please give me sample Key,Input,IV to be used so that encryption/decryption works well for your code?

  17. #17 by smoreau on 23 Aug 2011 - 15:12

    Hi Manish,

    I tested my code with your secret key and your initial vector and it works perfectly fine with me.
    Here is what I did:
    1/ Encrypt with PHP the text “This is a test message.” using “0123456789123456” as secret key and IV. The PHP function returns the following encrypted text: “DRFnYZgsAw1KOw0nYqTOpq9R+H+JJww=”
    2/ Decrypt with Java the encrypted text “DRFnYZgsAw1KOw0nYqTOpq9R+H+JJww=” using “0123456789123456” as secret key and IV. The Java method returns as expected the text “This is a test message.”

    I would suggest you double check your code. If you don’t see anything wrong, try to encrypt the text “This is a test message.” and check if you get the same encrypted text than me. If yes, it means you have a problem in your Java code. If no, it means the problem is in your PHP code.

    Hope it helps.

  18. #18 by iongion on 13 Oct 2011 - 17:20

    There is no charset UTF8, you probably mean UTF-8, but probably use that only when on php side you are sure you are using utf8 encoded strings.
    This example does not work.

  19. #19 by smoreau on 13 Oct 2011 - 20:49

    Hi Iongion,

    “UTF8″ and “UTF-8″ both work, even if “UTF8″ is actually not documented in the Javadoc.
    I am not sure to understand why it is not working for you, but I did some more testing with my code and it seems that it is also working without specifying a charset.

    I would suggest you to try without the charset parameter and see if it works better.

  20. #20 by ibrahima on 23 Jan 2012 - 11:27

    Thanks ! it resolves my problem

  21. #21 by baoengb on 26 Jan 2012 - 22:20

    Hi smoreau,

    Just guessing, I was wondering if I have the needed to decrypt via php, the result function would be:

    function decrypt($message, $initialVector, $secretKey) {
    $decoded = base64_decode($message);
    return mcrypt_decrypt(
    MCRYPT_RIJNDAEL_128,
    md5($secretKey),
    $decoded,
    MCRYPT_MODE_CFB,
    $initialVector
    );
    }

    Agree?, not even tested yet.

  22. #22 by baoengb on 27 Jan 2012 - 01:07

    The function is already tested, and it works, thanks smoreau.

  23. #23 by Joe on 02 Feb 2012 - 16:41

    Hi

    Thanks a lot!
    But i have a question:
    Can we use the RSA algorithm?

  24. #24 by smoreau on 03 Feb 2012 - 09:20

    I am pretty sure we can, but I never try.
    I can see plenty of PHP examples to encrypt using RSA and you can slightly modify my method to decrypt it in Java.
    Please share the code with us once you did it! ;)

  25. #25 by HommeDeJava on 03 Feb 2012 - 16:53

    Greetings,

    I’ve found your post very helpful!

    Just want to add a small contribution for the sake of the community.

    It could be handy to remember not to forget to encode the « encrypted » data with $encryptedDataUrlEncoded = urlencode($encryptedData); in order to add it as a parameter to an URL.

    Many thank’s again

  26. #26 by alex rider on 16 May 2012 - 16:43

    I have try the PHP version and It wotks fine,
    Unfortunately I found obstacle when trying the Java version.

    1. What Java clas should I import ?
    I am using java 711_003 with Netbean Ide

    2. Can I use your class on Commercial website ?
    What is your license ?

    3. How do you know which PHP-Java envryption methods that is Compatible for both language ?
    Did you found it Accidentally after spent years doing Trial-&-Error inside your Kinky
    Lab ? Tel us more

  27. #27 by smoreau on 17 May 2012 - 18:08

    Hi Alex,

    At the time I wrote this post, I was using Java 6. However, this code should also work on Java 7.
    Can you tell me more about the error you are getting?

    Yes, you can use this code in your Commercial website. Simply write my name and the link of my website in your code as a comment. :)

    I spent a lot of time searching for a way of encrypting and decrypting in two different languages. I wouldn’t say I found it accidentally, but I would lie if I say it was easy. ;)

  28. #28 by Masm Coder on 19 May 2012 - 05:33

    smoreau :
    Hi Alex,
    At the time I wrote this post, I was using Java 6. However, this code should also work on Java 7.
    Can you tell me more about the error you are getting?
    Yes, you can use this code in your Commercial website. Simply write my name and the link of my website in your code as a comment.
    I spent a lot of time searching for a way of encrypting and decrypting in two different languages. I wouldn’t say I found it accidentally, but I would lie if I say it was easy.

    Hi
    I think My Error has some thing todo with the Imported class.
    I think it would be Cool if you also post the complete code with the Import declaration.

  29. #29 by smoreau on 19 May 2012 - 23:36

    I think My Error has some thing todo with the Imported class.
    I think it would be Cool if you also post the complete code with the Import declaration.

    Hi Alex,

    Please try with the following import declarations:

    import java.math.BigInteger;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    

    You also need to include the library Commons Codec in order to get this code to work :
    http://commons.apache.org/codec/

    Finally, if you get a problem with the line starting by LOGGER.debug, please replace it by a System.err.println for the time being.

  30. #30 by kblee on 29 May 2012 - 15:19

    Perl + PHP + JAVA(Android) + C# + Objective C(iPhone) + Javascript = AES256 Complete!!

    link: http://www.imcore.net/encrypt-decrypt-aes256-c-objective-iphone-php-java-android-perl-javascript/

  31. #31 by leo on 22 Oct 2012 - 10:35

    It works ! You are so GOOD.

  32. #32 by Sakthi on 08 Nov 2012 - 08:10

    Excellent.. works like a charm for me..
    Thanks a lot smoreau..

  33. #33 by Satheesh on 12 Feb 2013 - 07:19

    Nice link.Excellent !!! It works superbly

  34. #34 by david on 21 Aug 2013 - 23:59

    Thank you for this encryption solution…works very well. I tried a few that did not go so well.

    Did you write the java side code for encryption by chance? I would like to send data back the other way as well encrypted.

    Thank you.

  35. #35 by smoreau on 22 Aug 2013 - 08:24

    Thanks David for your message.
    Have a look at the following article I wrote a few days ago:
    http://www.logikdev.com/2013/08/16/encrypt-and-decrypt-with-java/
    It should help you. :)

  36. #36 by david on 22 Aug 2013 - 12:16

    Thank you. Is this new code compatible with the existing code in this article in terms of the type of encryption, etc. ie: can the encrypt code in the new article be used with the php decrypt code in this article without changes?

    Thank you in advance.

  37. #37 by smoreau on 22 Aug 2013 - 23:05

    I am not sure to fully understand. There is no php decrypt code in this article, only php encrypt code.
    However, the code of the two articles might be compatible but I didn’t check. I kept the same logic though.

  38. #38 by kim liu on 13 Oct 2014 - 08:18

    Hi,smoreau
    I want to encrypt data with java Rijndael 256 CBC Nopadding ,like the following php function for the encryption:
    $ticket = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $aes_key, $ticket, MCRYPT_MODE_CBC, $IV);
    Do you know this versions?
    looking forward to your reply.

  39. #39 by smoreau on 17 Oct 2014 - 08:32

    No, I never tried that one.
    Please post the result of your investigation when you succeed.

(will not be published)