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

问题描述 投票:0回答:5

我在基本加密/解密方面遇到问题。我四处寻找工作示例,但还没有找到工作示例。

-我将在 php 中加密,用 cryptojs 解密以获得一小层安全

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

我错过了哪一步?

javascript php encryption cryptojs
5个回答
79
投票

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

Note 2023:具有命名空间和最新 PHP 版本支持的改进版本位于上面链接的 GitHub 存储库中。下面的代码是第一次迭代,不知何故已经过时了。

PHP 库

/**
* 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 库

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

16
投票

安全通知:此答案中的代码容易受到选择密文攻击。请参阅此答案以获取安全加密

这是一个使用 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=

重要:因为我们没有验证我们的密文,所以解密很容易受到填充预言机攻击。另请参阅:PHP 中的验证加密

在 CryptoJS 方面:

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

keyIV 转换为 单词数组

我用 ciphertext 作为单词数组解密的运气不佳,所以我将其保留为 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! <== Stop editing my answer or I will delete it.
 *
 * 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))

6
投票

不要太深入编码,只需使用base64解码器

关于 php 代码:

$encrypt_val=base64_encode("value");

在 js 上:

var my_orignal_val = window.atob(passed_val);

这足以满足您的要求。


4
投票

您正在使用两个库,它们试图容纳严格来说无效的输入。 Rijndael 需要 16、24 或 32 字节长的随机字节字符串的密钥。您提供 13 个字符的字符串。 PHP 库 Mcrypt 直接使用字符串(可能是 utf8 编码)作为二进制输入,并通过 零将其填充到 MCRYPT_RIJNDAEL_256

 所需的 32 字节
。另一方面,CryptoJS 判定您输入了密码之类的内容,而是使用密钥派生函数来生成 32 字节密钥

此外,所使用的加密算法甚至不匹配。 Mcrypt 在 256 位版本中使用了原始 Rijndael 的很少实现的变体,而 CryptoJS 则实现了 Rijndael 提案广为人知的 AES256 变体。不过,两者的 128 位版本(

MCRYPT_RIJNDAEL_128
和 AES128)是相同的。

您稍后将要面对的第三个问题是,Mcrypt 还对正在加密的数据使用了疯狂的填充方案。由于 Rijndael 是一种分组密码,因此它只能加密 16、24 或 32 字节的块(具体取决于变体 - AES 始终使用 16 字节块)。因此必须填充此类数据。 Mcrypt 通过仅附加零以非内射方式完成此操作。如果您只编码字符串,这对您来说不会是太大的问题,因为 utf8 编码的字符串永远不会包含零字节,因此您可以将它们剥离(CryptoJS 甚至原生支持这一点)。

解决所有这些问题的最简单方法是避免自己实现任何加密技术(无论如何,如果没有对该主题的广泛了解,强烈建议不要这样做)。您能否改为通过 https 传输您的敏感信息,而 https 将使用 TLS(以前称为 SSL)来加密和验证通道?


-2
投票

加密Javascript

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js" integrity="sha512-E8QSvWZ0eCLGk4km3hxSsNmGWbLtSCSUcewDQPQWZF6pEU8GlT8a5fF32wOl1i8ftdMhssTrF/OhyGWwonTcXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script>
        function encrypt(str) {
  var encoded = "";
  for (i=0; i<str.length;i++) {
    var a = str.charCodeAt(i);
    var b = a ^ 51;    // bitwise XOR with any number, e.g. 123
    encoded = encoded+String.fromCharCode(b);
  }
  return btoa(encoded);
}

PHP 解密

 function decrypt($encoded) {
$encoded =base64_decode($encoded);
  $decoded = "";
  for( $i = 0; $i < strlen($encoded); $i++ ) {
    $b = ord($encoded[$i]);
    $a = $b ^ 51;  // <-- must be same number used to encode the character
    $decoded .= chr($a);
  }
  return $decoded;
}

KEY -PHP 解密

function decrypt($passphrase, $enc_text)
    {
        $enc_text = json_decode($enc_text, true);
        try {
            $slam_ol = hex2bin($enc_text["slam_ltol"]);
            $iavmol  = hex2bin($enc_text["iavmol"]);
        } catch (Exception $e) {
            return null;
        }
        $ciphertext = base64_decode($enc_text["amtext"]);
        $iterations = 999;
        $key = hash_pbkdf2("sha512", $passphrase, $slam_ol, $iterations, 64);
        $decrypted = openssl_decrypt($ciphertext, 'aes-256-cbc', hex2bin($key), OPENSSL_RAW_DATA, $iavmol);
        return $decrypted;
    }

KEY -javascript 加密

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js" integrity="sha512-E8QSvWZ0eCLGk4km3hxSsNmGWbLtSCSUcewDQPQWZF6pEU8GlT8a5fF32wOl1i8ftdMhssTrF/OhyGWwonTcXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script>
        function encrypt(passphrase, plain_text) {
            var slam_ol = CryptoJS.lib.WordArray.random(256);
            var iv = CryptoJS.lib.WordArray.random(16);
            var key = CryptoJS.PBKDF2(passphrase, slam_ol, {
                hasher: CryptoJS.algo.SHA512,
                keySize: 64 / 8,
                iterations: 999
            });
            var encrypted = CryptoJS.AES.encrypt(plain_text, key, {
                iv: iv
            });
            var data = {
                amtext: CryptoJS.enc.Base64.stringify(encrypted.ciphertext),
                slam_ltol: CryptoJS.enc.Hex.stringify(slam_ol),
                iavmol: CryptoJS.enc.Hex.stringify(iv)
            }
            return JSON.stringify(data);
        }

© www.soinside.com 2019 - 2024. All rights reserved.