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"]);
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; }