3

I wanted to implement a simple yet secure way to send some information from a PHP script to a Java client. I already looked through several implementations on here, but none worked so far and I feel a frustrate now. The last one I used with a bit of editing is this one:

PHP:

function enc3($plaintext) {
$length = 16;
$key = openssl_random_pseudo_bytes($length);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,
 $plaintext, MCRYPT_MODE_CBC, $iv);
echo base64_encode($ciphertext);
echo "\n".base64_encode($iv);
echo "\n".base64_encode($key);
}
enc3("test");

Java:

public static byte[] decrypt(byte[] key, byte[] initVector, byte[] encryptedValue) {
 try {
 IvParameterSpec iv = new IvParameterSpec(initVector);
 SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
 Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING");
 cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
 byte[] original = cipher.doFinal(encryptedValue);
 return original;
 } catch (Exception ex) {
 Logger.getLogger(MainGUI.class.getName()).log(Level.SEVERE, null, ex);
 }
 return null;
}
...
byte[] encpryted = Base64.getDecoder().decode(rd.readLine());
byte[] iv = Base64.getDecoder().decode(rd.readLine());
byte[] key = Base64.getDecoder().decode(rd.readLine());
byte[] output = decrypt(key, iv, encpryted);

And I get a:

javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes

The key is just for debugging in there, of course, I would remove it when it's working, and store it in the client. Not sure what's the best way to do that, somehow, I thought of hiding it via combining it in a hidden way, the server too knows how to produce it. But I guess it would then be readable in memory, no?

Anonymous
87.5k15 gold badges163 silver badges181 bronze badges
asked Jan 10, 2017 at 6:25
3
  • If you are using PHP 7.1.0, mcrypt_encrypt() has been DEPRECATED. Commented Jan 10, 2017 at 6:35
  • No I don't use PHP7, it's PHP5.6.22-2 Commented Jan 10, 2017 at 6:36
  • Have you checked the length of encryptedValue? Commented Jan 10, 2017 at 7:33

1 Answer 1

3

AES is a block cipher and only works properly with blocks of 16 bytes. When your ciphertext length is not divisible by 16, it causes IllegalBlockSizeException afterwards.

You can easily implement PKCS5 padding for AES/CBC cipher in PHP, which is basically a standardized way how to pad your plaintext input to be an exact multiple of the block size:

function pkcs5_pad($text) {
 $size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
 $pad = $size - (strlen($text) % $size);
 return $text . str_repeat(chr($pad), $pad);
}

Then update your encryption function to use padding:

$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,
pkcs5_pad($plaintext), MCRYPT_MODE_CBC, $iv);

Java has already implemented support for PKCS5, just update AES cipher initialization:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
answered Jan 10, 2017 at 8:14
Sign up to request clarification or add additional context in comments.

4 Comments

It is working now, thank you! But I have another problem, I totally don't get how or why this happens. I encode something like this: "sha1,sha2", and split it in Java. The decoding works fine now, but split[1] doesn't have a length equal to split[0]. It has 15 following "invisible" chars, seems to be byte=0. If I split[1].toString() out it shows just "sha2", but if I make split1.length() it shows 19 instead of 4. Any idea where those bytes come from? It drove me crazy for hours because I didn't get why split[1].equal(sha2) didn't work, until I checked the length of split[1].
Ok it was just luck I guess, still getting javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes randomly, even with your trim implementation, any idea why or how to fix this? It's not happening always but just sometimes, even the encrypted text never changes.
@M.H. You are right, previous solution had issues, so decoded text had trailing hidden characters. I've updated my answer to use standardized way how to properly pad encrypted text.
Thank you, that now is working! So if I change it to PKCS5PADDING in Java, would that mean it will automatically fill/pad with zeros if not multiple of 16 and I encrypt in Java?

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.