JavaScript加密和PHP解密
我正在使用JavaScript加密用户密码,如下所示:
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(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函数使用一种简单的AES加密方法正确解密吗?我确定我的mcrypt_decrypt()方法中的密码,mcrypt模式和IV参数做错了。谢谢,如果你知道。
回答:
问题在于,在CryptoJS代码中,密码用于导出密钥,而IV用于AES加密,但是mcrypt仅使用密钥进行加密/解密。此信息需要传递给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)
);
}
盐是在CryptoJS加密期间生成的,需要与密文一起发送到php。在调用evpKDF
盐之前,必须先将其从十六进制转换为二进制字符串。
$keyAndIV = evpKDF("Secret Passphrase", hex2bin($saltHex));$decryptPassword = mcrypt_decrypt(MCRYPT_RIJNDAEL_128,
$keyAndIV["key"],
hex2bin($cipherTextHex),
MCRYPT_MODE_CBC,
$keyAndIV["iv"]);
如果仅将encryptedPassword.toString()
其发送到服务器,则有必要在使用前将盐和实际密文分开。该格式是与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 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解密 的全部内容, 来源链接: utcz.com/qa/435173.html