加密JavaScript和解密PHP [英] Encryption in JavaScript and decryption with PHP

查看:120
本文介绍了加密JavaScript和解密PHP的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  var encryptedPassword = CryptoJS.AES.encrypt(password, 密码密码); 

它工作正常,但现在我正在尝试在服务器端的PHP中解密,如下所示: / p>

  $ 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; //与blockSize相同
var keySize = encryptedPassword.algorithm .keySize;
var keyHex = encryptedPassword.key.toString();
var saltHex = encryptedPassword.salt.toString(); //必须发送
var openSslFormattedCipherTextString = encryptedPassword.toString() ; //未使用
var cipherTextHex = encryptedPassword.ciphertext.toString(); //必须发送

我将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加密方法的PHP函数?我确定我的mcrypt_decrypt()方法中的密码,mcrypt模式和IV参数出错了。谢谢,如果你知道。

解决方案

问题是在CryptoJS代码中使用密码来导出密钥,而IV用于AES加密,但mcrypt仅使用密钥进行加密/解密。这些信息需要传递给php。因为你不想传输密码,你必须以相同的方式在php中导出密钥和IV。



以下代码导出密钥和IV密码和盐。在我的答案此处(有关更多信息)的代码之后建模。

 函数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);

//迭代
($ 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;
}

返回数组(
key=> substr($ derivedBytes,0,$ keySize * 4),
iv=> substr ($ derivedBytes,$ keySize * 4,$ ivSize * 4)
);
}

盐在CryptoJS的加密过程中生成,需要发送到php密文。在调用 evpKDF 之前,必须将salt转换为十六进制的二进制字符串。

  $ 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编码的。

 函数解密($ ciphertext,$ password){
$ ciphertext = base64_decode $密文);
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 ]); ($ decryptPassword),$
}

OpenSSL扩展代替Mcrypt可以实现相同的功能:

 函数解密($ 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已解码
$ keyAndIV [iv]);

return $ decryptPassword;
}


I'm encrypting my user password in JavaScript like this:

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

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"

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

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.

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.

解决方案

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.

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

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


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

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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆