使用 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 中展示的那样。
我正在尝试加密通过 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
).
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 中展示的那样。