我试图加密通过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
));
函数返回(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
));
现在一切正常。
答案 0 :(得分:0)
在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。