使用 CryptoJS 进行 AES 加密,使用 CodeIgniter 进行解密

AES encryption with CryptoJS and decryption with CodeIgniter

我正在尝试加密通过 POST 请求发送到我的服务器(用 Codeigniter 3 编写)的用户名,所以我在客户端使用 CryptoJS 加密,如下所示:

var user = $('.user').val();
var key = "<? echo($key);?>"; //$key is created on the server side
var encUser = CryptoJS.AES.encrypt(user, key, {
    mode: CryptoJS.mode.CBC
}).toString();

我得到一个看起来不错的 64 个字符长的字符串,我将其发送到我的服务器。

在我的服务器上 (运行 CodeIgniter 3) 我正在使用 CI encryption 库并根据需要加载它,但是当我尝试解密字符串时所以:

$this->encryption->decrypt($this->input->post('encUser'), array(
    'cipher' => 'aes-128',
    'mode' => 'cbc',
    'hmac' => FALSE,
    'key' => $key
));

函数returns(bool)false,意思是出错了。

我做错了什么?

注意:不确定我需要用 iv 加密多少,因为 CI 库只使用字符串本身的前 16 个字符。

** 编辑 **

我正在 random_int polyfill 的帮助下创建我的 $kay(密码),这是我的功能:

private function random_str($length, $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
{
    $str = '';
    $max = mb_strlen($keyspace, '8bit') - 1;
    for ($i = 0; $i < $length; ++$i) {
        $str .= $keyspace[random_int(0, $max)];
    }
    return $str;
}

我正在调用random_str(32);

示例生成的密钥:1xB8oBQgXGPhcKoD0QkP1Uj4CRZ7Sy1c

** 更新 ** 感谢 Artjom.B 的回答(和聊天 :) )我们让它工作,使用他的回答的客户端代码并将服务器端代码修复为:

$user = $this->encryption->decrypt(base64_decode($this->input->post('encUser')), array(
        'cipher' => 'aes-256',
        'mode' => 'cbc',
        'hmac' => FALSE,
        'key' => $key
    ));

现在一切正常。

在 CryptoJS 中,如果 key 是一个字符串,那么它会假定 key 实际上是一个密码,生成一个随机盐,并从密码+盐中导出实际的密钥和 IV(这通过 EVP_BytesToKey).

以兼容 OpenSSL 的方式完成

CodeIgniter 的加密库不支持这种类型的密钥派生。您要么必须更改 CryptoJS 代码以传递经过解析的 WordArray:

var key = CryptoJS.enc.Hex.parse("<? echo(bin2hex($key));?>");
var iv = CryptoJS.lib.WordArray.random(128/8);
var encUser = CryptoJS.AES.encrypt(user, key, {
    iv: iv
}).ciphertext;
return iv.concat(encUser).toString(CryptoJS.enc.Base64);

由于 IV 写在密文前面,CodeIgniter 应该可以正确读取它,而不必明确指定。确保 key 被正确编码为 Hex 或 Base64,因为二进制编码在 JavaScript 中无法正常工作。此外,在 PHP 端,密文必须从 Base64 解码。

您也可以在 PHP 中实现 EVP_BytesToKey,正如我在 here 中展示的那样。