Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing JAVA with PHP for PKCS5 encryption

I have been tasked with replacing a legacy java system with something which runs PHP.

I am getting a little stuck on replacing the java cryptography with PHP code.

cipherAlgorythm = "PBEWithMD5AndDES";                           
cipherTransformation = "PBEWithMD5AndDES/CBC/PKCS5Padding";     
PBEParameterSpec ps = new javax.crypto.spec.PBEParameterSpec(salt, iterations);
SecretKeyFactory kf = SecretKeyFactory.getInstance(cipherAlgorythm);
SecretKey key = kf.generateSecret(new javax.crypto.spec.PBEKeySpec(password.toCharArray()));
Cipher encryptCipher = Cipher.getInstance(cipherTransformation);   
encryptCipher.init(Cipher.ENCRYPT_MODE, key, ps);
byte[] output = encryptCipher.doFinal("This is a test string".getBytes("UTF-8"));

Seems to be the guts of the Java

In PHP I am doing

$hashed_key = pbkdf2('md5', $this->key, $this->salt, $this->reps , <GUESS 1>, TRUE);
$output = mcrypt_encrypt(MCRYPT_DES, $hashed_key, "This is a test string", MCRYPT_MODE_CBC, <GUESS 2>);

pbkdf2 is from here.

So <GUESS 1> is the key size and <GUESS 2> is the IV. I have played around with these to no avail. Does anyone have suggestion for such values? As far as I can see the encryption itself should be portable but I am unsure about what is going on in some of the Java methods.

It looks like java is creating an IV somewhere, but I don't understand how or where.

RELATED

Decrypt ( with PHP ) a Java encryption ( PBEWithMD5AndDES )

like image 609
Jeremy French Avatar asked Dec 17 '13 16:12

Jeremy French


3 Answers

You may want to look at http://us3.php.net/manual/en/ref.mcrypt.php#69782, but basically he implemented a DIY padding solution:

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

That may be your best bet, but if you look at this comment, his suggestions on how to verify that each step is correct may be useful for you.

https://stackoverflow.com/a/10201034/67566

Ideally you should move away from DES and since this padding is going to be a problem in PHP, why not see if you can change the encryption algorithm to something less troublesome and more secure?

To help you can show this page: http://www.ietf.org/rfc/rfc4772.txt, where it is succinctly expressed that DES is susceptible to brute force attacks, so has been deprecated and replaced with AES.

like image 91
James Black Avatar answered Oct 01 '22 01:10

James Black


Both existing answers helped, but I'll post the complete solution here.

I have not seen it documented anywhere but after looking at implementations for this encryption scheme I found the key is the first 8 bytes of the encrypted hash and the IV is the last 8.

 public function get_key_and_iv($key, $salt, $reps) {
    $hash = $key . $salt;
    for ($i = 0; $i< $reps; $i++) {
      $hash = md5($hash, TRUE);
    }
    return str_split($hash,8);
  }

seems to do the trick. Which replaces pbkdf2 in my question, negates the need for <GUESS 1> and gives a value for <GUESS 2>

Then I got caught with the padding problem which James Black mentioned and managed to fix. So final code is

list($hashed_key, $iv) = get_key_and_iv($key, $salt, $reps);
// 8 is DES block size.
$pad = 8 - (strlen($plaintext) % 8);
$padded_string = $plaintext . str_repeat(chr($pad), $pad);
return mcrypt_encrypt(MCRYPT_DES, $hashed_key, $padded_string, MCRYPT_MODE_CBC, $iv);
like image 33
Jeremy French Avatar answered Oct 01 '22 02:10

Jeremy French


You can use hash_pbkdf2 PHP (5.5) function too instead of using PBKDF2 PHP libraries.

According to PHP docs the GUESS 1 is the length of the created derived key

length

The length of the output string. If raw_output is TRUE this corresponds to the byte-length of the derived key, if raw_output is FALSE this corresponds to twice the byte-length of the derived key (as every byte of the key is returned as two hexits).

If 0 is passed, the entire output of the supplied algorithm is used.

Maybe this post (what is an optimal Hash size in bytes?) result interesting for you.

GUESS 2 or IV is a random initialization vector used to create an unique salt to generate the hash.

You can create the IV with mycript_create_iv function.

Take a look at the complete sample in PHP.net

<?php
$password = "password";
$iterations = 1000;

// Generate a random IV using mcrypt_create_iv(),
// openssl_random_pseudo_bytes() or another suitable source of randomness
$salt = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);

$hash = hash_pbkdf2("sha256", $password, $salt, $iterations, 20);
echo $hash;
?>
like image 25
vzamanillo Avatar answered Oct 01 '22 02:10

vzamanillo