【问题标题】:AES encryption/decryption in javascript using CryptoJS使用 CryptoJS 的 javascript 中的 AES 加密/解密
【发布时间】:2014-02-15 23:06:39
【问题描述】:

我正在尝试使用共享密钥在 javascript 和 php 之间发送 AES 加密消息。在 Javascript 中,我使用的是 CryptoJS 库。在 php 中,我使用的是 mycrypt。我正在尝试在 javascript 中构造一条加密消息,然后使用共享密钥在 php 中对其进行解密。我可以用 Javascript 加密和解密消息。我可以在 php 中加密和解密相同的消息 - 但两者之间的加密方式不同。

Javascript

var encrypted = CryptoJS.AES.encrypt("Message", "Secret Passphrase");
alert(encrypted);

给予

U2FsdGVkX18+k3pba4l4MbGZfmDjMc1yQ6uj1fg+BGo=

在php中

<?php
$Pass = "Secret Passphrase";
$Clear = "Message";

$crypted = fnEncrypt($Clear, $Pass);
echo "Encrypted: ".$crypted."</br>";

$newClear = fnDecrypt($crypted, $Pass);
echo "Decrypted: ".$newClear."</br>";

function fnEncrypt($sValue, $sSecretKey) {
return rtrim(
        base64_encode(
                mcrypt_encrypt(
                        MCRYPT_RIJNDAEL_256,
                        $sSecretKey, $sValue,
                        MCRYPT_MODE_ECB,
                        mcrypt_create_iv(
                                mcrypt_get_iv_size(
                                        MCRYPT_RIJNDAEL_256,
                                        MCRYPT_MODE_ECB
                                ),
                                MCRYPT_RAND
                        )
                )
        ),"\0"
);
}

function fnDecrypt($sValue, $sSecretKey) {
return rtrim(
        mcrypt_decrypt(
                MCRYPT_RIJNDAEL_256,
                $sSecretKey,
                base64_decode($sValue),
                MCRYPT_MODE_ECB,
                mcrypt_create_iv(
                        mcrypt_get_iv_size(
                                MCRYPT_RIJNDAEL_256,
                                MCRYPT_MODE_ECB
                        ),
                        MCRYPT_RAND
                )
        ),"\0"
);
}

输出是

加密:iqJ0R5ahRP7GpWKtW7+OBSCGnudDr99VbJC36OQlmgE=

解密:消息

我的问题是,为什么这些不一样?

【问题讨论】:

  • php 是 ascii 而 js 是 unicode,所以即使字符串看起来它们具有相同的二进制模式,但它们没有,并且当您将这些位混淆时,差异变得明显。 php可以做unicode了吗?
  • php 基本上对 unicode 保持沉默。字符串只是字符的“字符串”(哈哈)。这些字符是 1byte-per-char ascii 还是像 utf16 或 utf8 这样的多字节不是 PHP 的工作要弄清楚。

标签: javascript php security encryption cryptography


【解决方案1】:

如果它们是相同的,那将是一场密码学的灾难......

但是:使用您使用 PHP 加密的方式(使用 EBC 模式),您将始终获得相同的结果。您可以通过查看http://en.wikipedia.org/wiki/Cipher_block_chaining#Electronic_codebook_.28ECB.29 的 tux pciture 来了解为什么这是一个问题

CryptoJS 似乎使用 CBC 作为默认分组密码模式(至少他们在 https://code.google.com/p/crypto-js/#Block_Modes_and_Padding 中是这样说的),它有一个随机的初始向量。这比 CBC 好。

如果您使用相同的密码、相同的分组密码模式(例如 CBC)以及相同的密钥和 IV——当然还有相同的明文——结果应该是相同的——cmets 表明也可能存在 unicode问题。

另外,MCRYPT_RIJNDAEL_256 不是 AES。 AES 的 BLOCK 大小为 16 字节 - AES-128 的 KEY 大小为 16 字节,AES-256 的 KEY 大小为 32 字节。 MCRYPT_RIJNDAEL_256 的 BLOCK 大小为 32 字节 - 这是一个很大的区别。

最后一点:仅加密数据是不够的!您还必须通过使用 HMAC 或使用经过身份验证的分组密码模式(如 GCM)对其进行身份验证 - 如果您不这样做,您可能至少会受到填充 oracle 攻击:http://en.wikipedia.org/wiki/Padding_oracle_attack

【讨论】:

  • 优秀的参考资料,对我的学习曲线很有帮助。我决定使用 GibberishAES,它同时具有 javascript 和 php 库,可以很好地协调。
猜你喜欢
  • 2012-08-01
  • 1970-01-01
  • 2014-12-24
  • 2014-08-17
  • 2021-12-20
  • 2019-08-13
  • 1970-01-01
  • 2016-02-19
  • 1970-01-01
相关资源
最近更新 更多