JavaScript encryption and decryption using PHP

I encrypt my user password in JavaScript as follows:

var encryptedPassword = CryptoJS.AES.encrypt(password, "Secret Passphrase"); 

It works fine, but now I'm trying to decrypt PHP on the server side as follows:

  $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND); $decryptPassword = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, "Secret Passphrase", base64_decode($password), MCRYPT_MODE_CBC, $iv); 

it doesn't work at all, the decrypted password string looks very strange:

  string(64) "> OX2MS  λŒ—v <$ Κ•  i Μ„  _  P   \ Υ―= _6( m    ,4WT7  a" 

Here is the current state of my code in JavaScript after helpful comments:

  var encryptedPassword = CryptoJS.AES.encrypt(password, "Secret Passphrase"); var ivHex = encryptedPassword.iv.toString(); var ivSize = encryptedPassword.algorithm.ivSize; // same as blockSize var keySize = encryptedPassword.algorithm.keySize; var keyHex = encryptedPassword.key.toString(); var saltHex = encryptedPassword.salt.toString(); // must be sent var openSslFormattedCipherTextString = encryptedPassword.toString(); // not used var cipherTextHex = encryptedPassword.ciphertext.toString(); // must be sent 

I send saltHex and CipherTextHex to a PHP server, and I use mcrypt_decrypt () as follows:

  $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), $saltHex); $decryptPassword = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, "Secret Passphrase", base64_decode($cipherTextHex), MCRYPT_MODE_CBC, $iv); 

It still does not work with this updated code.

Can someone help me correctly decrypt PHP mcrypt_decrypt () function for a simple AES encryption method? I am sure that I am doing something wrong with encryption, mcrypt mode and IV parameters inside my mcrypt_decrypt () method. Thank you if you know.

+1
javascript php encryption mcrypt cryptojs
source share
2 answers

The problem is that the CryptoJS code uses a password to get the key and IV, which will be used to encrypt AES, but mcrypt uses only the key for encryption / decryption. This information must be passed to php. Since you do not want to pass the password, you must output the key and IV in the same way in php.

The following code displays the key and IV from the password and salt. It is modeled after the code in my answer here (for more information).

 function evpKDF($password, $salt, $keySize = 8, $ivSize = 4, $iterations = 1, $hashAlgorithm = "md5") { $targetKeySize = $keySize + $ivSize; $derivedBytes = ""; $numberOfDerivedWords = 0; $block = NULL; $hasher = hash_init($hashAlgorithm); while ($numberOfDerivedWords < $targetKeySize) { if ($block != NULL) { hash_update($hasher, $block); } hash_update($hasher, $password); hash_update($hasher, $salt); $block = hash_final($hasher, TRUE); $hasher = hash_init($hashAlgorithm); // Iterations for ($i = 1; $i < $iterations; $i++) { hash_update($hasher, $block); $block = hash_final($hasher, TRUE); $hasher = hash_init($hashAlgorithm); } $derivedBytes .= substr($block, 0, min(strlen($block), ($targetKeySize - $numberOfDerivedWords) * 4)); $numberOfDerivedWords += strlen($block)/4; } return array( "key" => substr($derivedBytes, 0, $keySize * 4), "iv" => substr($derivedBytes, $keySize * 4, $ivSize * 4) ); } 

The salt is generated during encryption in CryptoJS and should be sent to php with encrypted text. Before calling evpKDF salt must be converted to a binary string from hex.

 $keyAndIV = evpKDF("Secret Passphrase", hex2bin($saltHex)); $decryptPassword = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $keyAndIV["key"], hex2bin($cipherTextHex), MCRYPT_MODE_CBC, $keyAndIV["iv"]); 

If only encryptedPassword.toString() was sent to the server, then before using it is necessary to separate the salt and the actual encrypted text. The format is a proprietary format compatible with OpenSSL, with the first 8 bytes being β€œSalted__”, the next 8 bytes being random salt and the rest being actual encrypted text. All together encoded by Base64.

 function decrypt($ciphertext, $password) { $ciphertext = base64_decode($ciphertext); if (substr($ciphertext, 0, 8) != "Salted__") { return false; } $salt = substr($ciphertext, 8, 8); $keyAndIV = evpKDF($password, $salt); $decryptPassword = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $keyAndIV["key"], substr($ciphertext, 16), MCRYPT_MODE_CBC, $keyAndIV["iv"]); // unpad (PKCS#7) return substr($decryptPassword, 0, strlen($decryptPassword) - ord($decryptPassword[strlen($decryptPassword)-1])); } 

The same thing can be done with the OpenSSL extension instead of Mcrypt:

 function decrypt($ciphertext, $password) { $ciphertext = base64_decode($ciphertext); if (substr($ciphertext, 0, 8) != "Salted__") { return false; } $salt = substr($ciphertext, 8, 8); $keyAndIV = evpKDF($password, $salt); $decryptPassword = openssl_decrypt( substr($ciphertext, 16), "aes-256-cbc", $keyAndIV["key"], OPENSSL_RAW_DATA, // base64 was already decoded $keyAndIV["iv"]); return $decryptPassword; } 
+7
source share

You cannot decrypt with a random initialization vector - you need to use the same IV for which the data was encrypted. In addition, IIRC, AES by default has an 8-bit representation of encrypted data that will need to be carefully processed when transmitting over HTTP.

0
source share

All Articles