3

I am using the below php code for encryption:


$enc_request = base64_encode( mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->_app_key, json_encode($request_params), MCRYPT_MODE_ECB) ); 

Now trying to encrypt the in android and getting the different encrypted string. Below is the android code:


public void enc(){ byte[] rawKey = getRawKey("my_key".getBytes()); SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal("my_message".getBytes()); String result=Base64.encodeToString(encrypted, Base64.DEFAULT); } private static byte[] getRawKey(byte[] seed) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); sr.setSeed(seed); kgen.init(256, sr); SecretKey skey = kgen.generateKey(); byte[] raw = skey.getEncoded(); return raw; } 

Could any one help me, where I am wrong? And get same correct encrypted string in android too.

10
  • Place of "Cipher cipher = Cipher.getInstance("AES")" this I've also tried to "AES/ECB/PKCS7Padding" for algo. Commented Aug 7, 2013 at 10:58
  • stackoverflow.com/questions/17079579/aes-algo-decryption-issue/…. check this if it helps Commented Aug 7, 2013 at 10:59
  • Hi Raghu, I don't have iv, so I remove the iv parameter form init() but still getting different encrypted string. I can't understand the where could could I used iv although I have only a secret key/salt. to encrypt as in php code. please review. Commented Aug 7, 2013 at 11:26
  • 1
    Learn about block modes of encryption, padding modes and the actual AES algorithm. Currently you are not even using AES in PHP, and you are using a flawed key derivation mechanism in Android. Except using ECB mode encryption in Java, everything else is wrong. Commented Aug 7, 2013 at 17:47
  • 1
    @Pankaj I will try and implement a compatibility method in Java, but to do that I would have to repeat the mistakes PHP makes, and I would not really want those to spread around. It's much better to write a wrapper library around mcrypt_encrypt() that removes the mistakes that were made... Commented Aug 9, 2013 at 13:01

1 Answer 1

4

I've created a main method in Java using Bouncy Castle to show the inner workings of mcrypt_encrypt() used in your code sample.

This is mainly to show other developers that PHP's mcrypt_encrypt() is a very dangerous method to use. It won't fail much, but that is because it rather continues where it should have stopped long ago. For instance, it adds or removes values from the key. It emits a warning when it does do this, but it won't directly show in the code.

public static void main(String[] args) throws DataLengthException, IllegalStateException, InvalidCipherTextException { // just some constants boolean ENCRYPT = true; boolean DECRYPT = false; // the key is either in binary in PHP or a string (dynamic isn't it?), lets assume ASCII byte[] givenKey = args[0].getBytes(Charset.forName("ASCII")); // determine the key size dynamically, somebody thought this was a good idea... // NOTE: PHP will emit a warning if the key size is larger, but will simply use the // largest key size otherwise final int keysize; if (givenKey.length <= 128 / Byte.SIZE) { keysize = 128; } else if (givenKey.length <= 192 / Byte.SIZE) { keysize = 192; } else { keysize = 256; } // create a 256 bit key by adding zero bytes to the decoded key byte[] keyData = new byte[keysize / Byte.SIZE]; System.arraycopy(givenKey, 0, keyData, 0, Math.min(givenKey.length, keyData.length)); KeyParameter key = new KeyParameter(keyData); // create a Rijndael cipher with 256 bit block size, this is not AES BlockCipher rijndael = new RijndaelEngine(256); // use a padding method that only works on data that cannot end with zero valued bytes ZeroBytePadding c = new ZeroBytePadding(); // use ECB mode encryption, which should never be used PaddedBufferedBlockCipher pbbc = new PaddedBufferedBlockCipher(rijndael, c); // initialize the cipher using the key (no need for an IV, this is ECB) pbbc.init(ENCRYPT, key); // create a plain text byte array byte[] plaintext = args[1].getBytes(Charset.forName("UTF8")); // create a buffer for the ciphertext byte[] ciphertext = new byte[pbbc.getOutputSize(plaintext.length)]; int offset = 0; offset += pbbc.processBytes(plaintext, 0, plaintext.length, ciphertext, offset); offset += pbbc.doFinal(ciphertext, offset); // show the ciphertext System.out.println(new String(Hex.encode(ciphertext), Charset.forName("ASCII"))); // reverse the encryption pbbc.init(DECRYPT, key); byte[] decrypted = new byte[pbbc.getOutputSize(ciphertext.length)]; offset = 0; offset += pbbc.processBytes(ciphertext, 0, ciphertext.length, decrypted, offset); offset += pbbc.doFinal(decrypted, offset); // this will probably print out correctly, but it isn't actually correct System.out.println(new String(decrypted, Charset.forName("UTF8"))); // check out the zero's at the end System.out.println(new String(Hex.encode(decrypted), Charset.forName("UTF8"))); // so lets make it a bit shorter... the PHP way // note that in PHP, the string may *not* contain a null terminator // add it yourself before printing the string System.out.println(new String(decrypted, Charset.forName("UTF8")).replaceAll("\\x00+$", "")); } 

Warning: the above code contains ZeroBytePadding. I later discovered that there is a difference between Bouncy Castle and PHP in this respect: Bouncy Castle expects that you always have to pad, while PHP doesn't. So Bouncy adds 1..n bytes while PHP adds 0..(n-1) bytes, where n is the block size (32 bytes for Rijndael-256/256). So you may have to do the padding/unpadding yourself; be sure to test the edge cases!

Sign up to request clarification or add additional context in comments.

6 Comments

It's working fine for key length 16 or less, but once I use the key of length more than 16, it's showing misleading strings. Is I need to look at KeyParameter or suggest what else? I tried what I'ld. Thanks
It may be that it is cutting it to 128 bit instead of upgrading the key. I programmed this out of the top of my head, I'll check.
Ah, very simple, it was a typo for the compare <= 128 was used instead of <= 192. Got confused, looked it up in source and my initial implementation was otherwise fine. PHP's implementation is way too permissive of course.
uhh, now it just fun...!! Thanks owlstead for every things that I learn from you...!!
This is the only example that works. Thank you very much.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.