JavaScriptencryption和PHP解密

我正在用JavaScriptencryption我的用户密码,如下所示:

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

它工作正常,但现在我试图解密在服务器端PHP这样的:

  $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); 

它根本不起作用,解密的密码string看起来很奇怪:

  string(64) "> OX2MS  댗v <$ ʕ  i ̄  _  P   \ կ= _6( m    ,4WT7  a" 

以下是有用的评论之后,我的代码在JavaScript中的当前状态:

  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 

我发送saltHex和CipherTextHex到PHP服务器,我正在使用mcrypt_decrypt()像这样:

  $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); 

它仍然没有与这个更新的代码工作。

有人可以帮助我用mcrypt_decrypt()PHP函数正确解密一个简单的AESencryption方法吗? 我确信我在密码,mcrypt模式和我的mcrypt_decrypt()方法中的IV参数有问题。 谢谢,如果你知道。

问题是在CryptoJS代码中使用密码来导出用于AESencryption的密钥和IV,但是mcrypt只使用密钥来encryption/解密。 这个信息需要传递给php。 既然你不想传输密码,你必须在php中以相同的方式派生出密钥和IV。

下面的代码从密码和盐派生出密钥和IV。 它是在我的答案在这里的代码模拟(更多信息)。

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

salt是CryptoJSencryption期间生成的,需要用密文发送给php。 在调用evpKDF之前,盐必须从hex转换为二进制string。

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

如果只有encryptedPassword.toString()被发送到服务器,那么在使用之前有必要分割salt和实际的密文。 格式是专有的OpenSSL兼容格式,前8个字节是“Salted__”,接下来的8个字节是随机盐,其余的是实际的密文。 一切都是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])); } 

使用OpenSSL扩展而不是Mcrypt可以实现相同的function:

 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; } 

你不能用随机初始化vector解密 – 你需要使用与数据encryption相同的IV。 此外,IIRC,AES默认为encryption数据的8位表示,在通过HTTP传输时需要仔细处理。