【问题标题】:Encrypting in CryptoJS and decrypting in mCrypt not working properly在 CryptoJS 中加密和在 mCrypt 中解密无法正常工作
【发布时间】:2023-03-16 10:53:01
【问题描述】:

在过去的 2 天里,我一直在努力解决我最初认为实施起来轻而易举的事情。

我需要一种非常简单且不安全的方法来通过 AJAX 发送密码并在服务器端解密

我正在使用来自 CryptoJS 的 AES:

JS 加密

    msg = "message";
    var key = CryptoJS.enc.Hex.parse('000102030405060708090a0b0c0d0e0f');
    var iv  = CryptoJS.enc.Hex.parse('101112131415161718191a1b1c1d1e1f');
    var encrypted = CryptoJS.AES.encrypt(msg, key, { iv: iv });

    var data_base64 = encrypted.ciphertext.toString(CryptoJS.enc.Base64); 
    var iv_base64   = encrypted.iv.toString(CryptoJS.enc.Base64);       
    var key_base64  = encrypted.key.toString(CryptoJS.enc.Base64);

    console.log(data_base64,iv_base64,key_base64) //If I use these keys in the PHP decryption it works

    return encrypted.toString();

...和使用mCrypt进行PHP解密

$encrypted = "f82126a59b76d86946a013d9f575d0d4"; //this is what the JS function above returned.
$key = "000102030405060708090a0b0c0d0e0f"; //same key as in JS function
$iv = "101112131415161718191a1b1c1d1e1f"; //same IV as in JS function

$plaintext = rtrim( mcrypt_decrypt( MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_CBC, $iv ), "\t\0 " );

echo "Original string : " . $encrypted . "<br />\n"; 
echo "Decrypted string : " . $plaintext . "<br />\n";

由于我使用相同的 IVkey 进行加密,我希望这可以很好地解密。但是我似乎遗漏了一些东西,因为我仍然在 plaintext. 看到胡言乱语

编辑:

看来 AES 的全部目的是 keys 和 我必须使用的IV 由 CryptoJS 输出(参见 console.log 中的 JS函数)。如果我使用这些功能似乎运行得很好。 但我实际上不希望这样,因为这些键是动态的 因此,每次我运行它们更改的 JS 函数时都会生成。 我只是 在客户端和服务器之间需要一个共享的私钥,用于 加密/解密并且是静态的。就这么简单。

【问题讨论】:

    标签: javascript php encryption cryptojs


    【解决方案1】:

    您的密钥是 128 位的($key 的长度是 32 个十六进制字符,即 16 字节或 128 位)。但是,在您的 mcrypt_decrypt() 调用中,您告诉 PHP 使用带有 256 位密钥的 MCRYPT_RIJNDAEL_256。尝试改用MCRYPT_RIJNDAEL_128。通常密码应该适应传递密钥的长度,但可能是 PHP 用空字节填充密钥以使用 256 位加密。

    其次,在 PHP 中 mcrypt_decrypt 设置为使用 CBC 模式(请参阅MCRYPT_MODE_CBC)。您没有指定 CryptoJS 应该使用哪种模式。幸运的是,根据 CryptoJS 的文档,CBC 模式是默认使用的模式;但是,由于您正在编写可移植代码,因此您应该考虑将其明确化。

    编辑

    如果它告诉您密钥太长,那是因为您没有打包它们。你给 PHP 一个长 32 字节(256 位)的十六进制编码字符串,这不是你的关键!要获取二进制数据你需要做的:

    $key = pack('H*', "000102030405060708090a0b0c0d0e0f");
    $iv = pack('H*', "101112131415161718191a1b1c1d1e1f");
    

    pack('H*', $str); 函数将十六进制表示转换为二进制字符串。

    【讨论】:

    • err 我不确定:当我在 mCrypt 中使用 128 位模式时,我得到这个:Warning: mcrypt_decrypt(): The IV parameter must be as long as the blocksize in C:\wamp\www\index2.php on line 10。我认为我在 PHP 中使用的密钥应该是 CryptoJS 输出密钥,而不是静态密钥。但是,我想使用仅在客户端/服务器之间共享的静态密钥进行加密和解密。我现在正在编辑我的问题。
    • @NicholasKyriakides 我已经更新了我的答案。让我知道现在是否可以解决您的问题。 (仍然是 128 位模式)
    • 不,我认为关键是我使用的密钥/IV 只是初始化加密。解密所需的密钥和 IV 是使用密码即时生成的。您更新的代码虽然不再生成有关块大小的错误,但 plaintext 仍然是胡言乱语。查看我编辑的问题
    • 你可以尝试直接在 CryptoJS 上调用 CBC 模式吗?显然 AES 类是派生另一个密钥的更高级别的类。
    • 或者,更好的是,使用 SJCL:github.com/bitwiseshiftleft/sjcl(使用 sjcl.cipher 而不是高级别的 sjcl.encrypt )
    【解决方案2】:

    MCRYPT_RIJNDAEL_256 与 AES 不同。 256 与密码的块大小有关,而不是密钥大小。

    快速历史课 - AES 是一场竞赛,最终由名为 Rijndael 的算法赢得。 Rinjdael 是为多种块大小(128、160、192、224 和 256 位)定义的密码。但是,对于 AES,仅选择了 128 位块大小。

    当您使用需要 IV 的模式(如 CBC 模式)时,块大小定义了 IV 的大小。因此,对于 AES,无论密钥大小如何,您总是需要一个 128 位 IV。支持的密钥大小为 128、192 或 256 位。

    在 PHP 中,可以使用密码 MCRYPT_RIJNDAEL_128 来使用 AES。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多