用PHP加密,用Javascript解密(cryptojs)

时间:2014-06-21 01:03:05

标签: javascript php encryption cryptojs

我在基本加密/解密方面遇到了麻烦。我一直在四处寻找一个有效的例子,但还没有找到一个有效的例子。

- 我将在php中进行加密,使用cryptoj解密以获得一小部分安全性

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js">
<?
$text = "this is the text here";
$key = "encryptionkey";

$msgEncrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND));
$msgBase64 = trim(base64_encode($msgEncrypted));

echo "<h2>PHP</h2>";
echo "<p>Encrypted:</p>";
echo $msgEncrypted;
echo "<p>Base64:</p>";
echo $msgBase64;
 ?>

<p>AES Decrypt</p>
<script> 
    var key = 'encryptionkey';
    var encrypted = "<?php echo $msgBase64 ?>";
    //tried  var base64decode = CryptoJS.enc.Base64.parse(encrypted); 
    var decrypted = CryptoJS.AES.decrypt(encrypted, key);
    console.log( decrypted.toString(CryptoJS.enc.Utf8) );
</script>

我错过了哪一步?

4 个答案:

答案 0 :(得分:51)

我需要相同的东西,我写了一个短库,适用于CryptoJS 3.x和PHP,支持openssl。希望这有帮助,在这里获取源代码和示例文件https://github.com/brainfoolong/cryptojs-aes-php

PHP Lib

/**
* Decrypt data from a CryptoJS json encoding string
*
* @param mixed $passphrase
* @param mixed $jsonString
* @return mixed
*/
function cryptoJsAesDecrypt($passphrase, $jsonString){
    $jsondata = json_decode($jsonString, true);
    $salt = hex2bin($jsondata["s"]);
    $ct = base64_decode($jsondata["ct"]);
    $iv  = hex2bin($jsondata["iv"]);
    $concatedPassphrase = $passphrase.$salt;
    $md5 = array();
    $md5[0] = md5($concatedPassphrase, true);
    $result = $md5[0];
    for ($i = 1; $i < 3; $i++) {
        $md5[$i] = md5($md5[$i - 1].$concatedPassphrase, true);
        $result .= $md5[$i];
    }
    $key = substr($result, 0, 32);
    $data = openssl_decrypt($ct, 'aes-256-cbc', $key, true, $iv);
    return json_decode($data, true);
}

/**
* Encrypt value to a cryptojs compatiable json encoding string
*
* @param mixed $passphrase
* @param mixed $value
* @return string
*/
function cryptoJsAesEncrypt($passphrase, $value){
    $salt = openssl_random_pseudo_bytes(8);
    $salted = '';
    $dx = '';
    while (strlen($salted) < 48) {
        $dx = md5($dx.$passphrase.$salt, true);
        $salted .= $dx;
    }
    $key = substr($salted, 0, 32);
    $iv  = substr($salted, 32,16);
    $encrypted_data = openssl_encrypt(json_encode($value), 'aes-256-cbc', $key, true, $iv);
    $data = array("ct" => base64_encode($encrypted_data), "iv" => bin2hex($iv), "s" => bin2hex($salt));
    return json_encode($data);
}

Javascript Lib

var CryptoJSAesJson = {
    stringify: function (cipherParams) {
        var j = {ct: cipherParams.ciphertext.toString(CryptoJS.enc.Base64)};
        if (cipherParams.iv) j.iv = cipherParams.iv.toString();
        if (cipherParams.salt) j.s = cipherParams.salt.toString();
        return JSON.stringify(j);
    },
    parse: function (jsonStr) {
        var j = JSON.parse(jsonStr);
        var cipherParams = CryptoJS.lib.CipherParams.create({ciphertext: CryptoJS.enc.Base64.parse(j.ct)});
        if (j.iv) cipherParams.iv = CryptoJS.enc.Hex.parse(j.iv)
        if (j.s) cipherParams.salt = CryptoJS.enc.Hex.parse(j.s)
        return cipherParams;
    }
}

示例Javascript

var encrypted = CryptoJS.AES.encrypt(JSON.stringify("value to encrypt"), "my passphrase", {format: CryptoJSAesJson}).toString();
var decrypted = JSON.parse(CryptoJS.AES.decrypt(encrypted, "my passphrase", {format: CryptoJSAesJson}).toString(CryptoJS.enc.Utf8));

示例PHP

$encrypted = cryptoJsAesEncrypt("my passphrase", "value to encrypt");
$decrypted = cryptoJsAesDecrypt("my passphrase", $encrypted);

答案 1 :(得分:13)

  

安全通知:此答案的代码容易受到选择密文攻击。请参阅this answer instead for secure encryption

这是一个使用PHP加密字符串并使用CryptoJS解密它的工作示例。

在PHP方面:

使用 MCRYPT_RIJNDAEL_128 (非256)与AES配对。 这里的128是块大小,而不是密钥大小。

也发送 IV 。你需要IV来解密。

$text = "this is the text here";
$key = "encryptionkey";

// Note: MCRYPT_RIJNDAEL_128 is compatible with AES (all key sizes)
$iv = random_bytes(16);

$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv);

echo "iv:".base64_encode($iv)."\n";
echo "ciphertext:".base64_encode($ciphertext)."\n";

以下是测试运行的示例输出:

iv:BMcOODpuQurUYGICmOqqbQ==
ciphertext:ZJAab8YtkRq5TL7uyIR7frM2b3krftJzn1pTqRTAda4=
  

重要:因为我们没有对我们的密文decryption becomes vulnerable to padding oracle attacks进行身份验证。另见:authenticated encryption in PHP

在CryptoJS方面:

您的密钥只有13个ASCII可打印字符,非常弱。 Mcrypt 填充使用 ZERO 字节的有效密钥大小的关键。

IV 转换为字阵列

我没有太多运气用密文作为单词数组进行解密,因此我将其保留为 Base64 格式。

CryptoJS = require("crypto-js")

// Mcrypt pads a short key with zero bytes
key = CryptoJS.enc.Utf8.parse('encryptionkey\u0000\u0000\u0000')

iv = CryptoJS.enc.Base64.parse('BMcOODpuQurUYGICmOqqbQ==')

// Keep the ciphertext in Base64 form
ciphertext = 'ZJAab8YtkRq5TL7uyIR7frM2b3krftJzn1pTqRTAda4='

/**
 * DANGER DANGER WILL ROBINSON!
 *
 * This example code doesn't demonstrate AUTHENTICATED ENCRYPTION
 * and is therefore vulnerable to chosen-ciphertext attacks.
 *
 * NEVER USE THIS CODE TO PROTECT SENSITIVE DATA!
 */

// Mcrypt uses ZERO padding
plaintext = CryptoJS.AES.decrypt(ciphertext, key, { iv: iv, padding: CryptoJS.pad.ZeroPadding })

// I ran this in nodejs
process.stdout.write(CryptoJS.enc.Utf8.stringify(plaintext))

答案 2 :(得分:3)

您正在使用两个试图容纳输入的库 - 严格来说 - 无效。 Rijndael要求密钥为16,24或32字节长的随机字节串。您提供13个字符的字符串。 PHP库的Mcrypt直接使用字符串(可能的utf8编码)作为二进制输入,zero pads it to the required 32 bytes用于MCRYPT_RIJNDAEL_256。另一方面,CryptoJS decides that you have entered something like a passphrase and instead uses a key derivation function to generate a 32 byte key

此外,使用的加密算法甚至不匹配。 Mcrypt使用原始Rijndael的一种很少实现的变体用于256位版本,而CryptoJS实现了Rijndael提议的广为人知的变体AES256。两者(MCRYPT_RIJNDAEL_128和AES128)的128位版本完全相同。

您将要面临的第三个问题是,Mcrypt还对加密数据使用了疯狂的填充方案。由于Rijndael是块密码,它只能加密16,24或32字节的块(取决于变量--AES总是使用16字节块)。因为这样的数据必须填补。 Mcrypt通过附加零来以非内射方式完成此操作。如果你只是编码字符串,这对你来说不会是一个问题,因为utf8编码的字符串永远不会包含零字节,所以你可以将它们剥离(CryptoJS even supports that natively)。

解决所有这些问题的最简单方法是避免必须自己实施任何加密(无论如何在没有广泛的主题知识的情况下强烈建议不要这样做)。您是否可以通过https传输敏感信息,这些信息将使用TLS(以前称为SSL)来加密和验证频道?

答案 3 :(得分:0)

不要太讲究编码,只需使用base64解码器

关于php代码:

$encrypt_val=base64_encode("value");

在js上:

var my_orignal_val = window.atob(passed_val);

这足以满足您的要求。