問題描述
我像這樣用 JavaScript 加密我的用戶密碼:
I'm encrypting my user password in JavaScript like this:
var encryptedPassword = CryptoJS.AES.encrypt(password, "Secret Passphrase");
它工作正常,但現在我正在嘗試在服務器端用 PHP 解密,如下所示:
It works fine but now I'm trying to decrypt in PHP on the server side like this:
$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 works at all, the decrypted password string looks very strange:
string(64) ">?OX2MS???v?<$????i????_??P?????=?_6(?m????,4WT7??a"
以下是在有用的注釋之后我的 JavaScript 代碼的當前狀態:
Here is the current state of my code in JavaScript after the 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
我正在向 PHP 服務器發送 saltHex 和 CipherTextHex,我正在使用 mcrypt_decrypt() 如下:
I am sending saltHex and CipherTextHex to the PHP server and I'm using mcrypt_decrypt() like this:
$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't work with this updated code.
有人可以幫助我使用 mcrypt_decrypt() PHP 函數正確解密一個簡單的 AES 加密方法嗎?我確定我的 mcrypt_decrypt() 方法中的密碼、mcrypt 模式和 IV 參數有問題.知道的話謝謝.
Can someone help me to decrypt properly with mcrypt_decrypt() PHP function for a simple AES encryption method ? I'm sure I am doing something wrong with the cipher, mcrypt mode and the IV parameters inside my mcrypt_decrypt() method. Thanks if you know.
推薦答案
問題是在 CryptoJS 代碼中,密碼用于派生密鑰和用于 AES 加密的 IV,但 mcrypt 僅使用密鑰來加密/解密.這個信息需要傳遞給php.既然不想傳密碼,就得用php中同樣的方法導出key和IV.
The problem is that in the CryptoJS code a password is used to derive the key and the IV to be used for AES encryption, but mcrypt only uses the key to encrypt/decrypt. This information needs to be passed to php. Since you don't want to transmit the password, you have to derive the key and IV in the same way in php.
以下代碼從密碼和鹽派生密鑰和 IV.它是根據我的回答此處中的代碼建模的(了解更多信息).
The following code derives the key and IV from a 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)
);
}
salt是CryptoJS加密時生成的,需要和密文一起發送給php.在調用 evpKDF
之前,鹽必須從十六進制轉換為二進制字符串.
The salt is generated during encryption in CryptoJS and needs to be sent to php with the ciphertext. Before invoking evpKDF
the salt has to 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"]);
<小時>
如果只有encryptedPassword.toString()
被發送到服務器,那么在使用之前需要將salt和實際密文分開.該格式是專有的 OpenSSL 兼容格式,前 8 個字節是Salted__",接下來的 8 個字節是隨機鹽,其余的是實際密文.所有的東西都是 Base64 編碼的.
If only encryptedPassword.toString()
was sent to the server, then it is necessary to split the salt and actual ciphertext before use. The format is a proprietary OpenSSL-compatible format with the first 8 bytes being "Salted__", the next 8 bytes being the random salt and the rest is the actual ciphertext. Everything together is Base64-encoded.
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 可以實現相同的目的:
The same can be achieved 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;
}
這篇關于JavaScript 加密和 PHP 解密的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!