添加 MCrypt 的 AES-CBC 加密后数据未保存到数据库或未正确解密
Posted
技术标签:
【中文标题】添加 MCrypt 的 AES-CBC 加密后数据未保存到数据库或未正确解密【英文标题】:Data is not saved into database or not properly decrypted after adding MCrypt's AES-CBC encryption 【发布时间】:2015-08-06 02:09:00 【问题描述】:我编写的加密脚本有问题。我有数百个输入,因此我使用桶排序算法作为“脚本内”数据库,以避免处理数百个 mysql 列的麻烦,更不用说它节省了代码空间。数据存储在 SQL 数据库的一列中。条目由'
分隔,该条目中的变量由>
分隔。这就是为什么我用字符串替换加密的最终结果......以避免产生额外的分隔符。
加密:
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM);
$key = pack("H*", "**64CharacterStringHere**");
$value = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $value, MCRYPT_MODE_CBC, $iv);
$value = $iv . $value;
$value = str_replace (">", "9Y6SnNmOBl", $value);
$value = str_replace ("'", "SxsNEpBe18", $value);
解密:
$value = str_replace ("9Y6SnNmOBl", ">", $value);
$value = str_replace ("SxsNEpBe18", "'", $value);
$iv = substr($value, 0, 16);
$value = substr($value, 16);
$key = pack("H*", "**64CharacterStringHere**");
$value = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $value, MCRYPT_MODE_CBC, $iv);
如果我在我的代码中省略了这个 sn-p,它就可以完美运行。数据正常显示和保存。但是,如果我添加此代码,有时数据根本不会被保存,并且如果它至少有一个变量由于某种原因没有被解密,即使我 100% 确定该函数正在每个变量上运行,因为该函数不仅仅是加密和解密。
我完全不知道为什么会这样。
MySQL 查询:
$new_accountant = "'" . $var_1 . ">" . $var_2;
$new_string = $string . $new_accountant;
$new_entry_query = 'UPDATE phone_tree SET string="' . $new_string . '" WHERE id="' . $userid . '";';
mysql_query($new_entry_query);
在上面的脚本中,$string
由 MySQL 查询定义,该查询获取包含迄今为止所有数据的列的当前值。
我现在正在搞砸它。它根本没有保存大约一半的时间,当它被保存时,变量在大约一半的时间内没有被正确解密。
我怀疑这与我存储 IV 的方式有关……这与变量有关,但我不知道我在做什么是一个问题。
【问题讨论】:
这个代码看起来不错,除了可能错误的方式来划分不应该产生你描述的失败率的东西。我认为您还应该围绕加密部分提供一部分 mysql 代码。也许有一些线索。 我包含了我在编辑数据时运行的 MySQL 查询的 sn-p。 @ArtjomB。您所说的“可能是错误的分隔方式”是指由于加密字符串是二进制字符串替换 ASCII 字符将不起作用吗?有什么选择?我必须删除任何额外的分隔符。 php.net/str_replace, "注意:这个函数是二进制安全的。" @Allenph 采用以下可能的 IV+密文:as>9Y6SnNmOBlgfdalisduffliasufdn
。然后您将替换导致as9Y6SnNmOBl9Y6SnNmOBlgfdalisduffliasufdn
的分隔符。在解密之前,您将替换分隔符并获得:as>>gfdalisduffliasufdn
,这不是您开始使用的密文。
【参考方案1】:
在我看来,您的 MySQL string
列是使用 varchar(nnn)
数据类型定义的。对吗?
如果是这样,我建议您在将加密材料存储到 MySQL 之前对其进行 base-64 编码,然后再对其进行 base-64 解码?这是加密信息传输和存储的常见做法。它使您的材料字符串安全。 MySQL 可能会攻击您的二进制数据。
base-64 字符集(由 php 中实现的 base-64 的 MIME 版本使用)仅包含 7 位 ASCII 字符。它包括数字、大小写字母和字符+
/
=
。这很好,因为您选择的分隔符 (>
'
) 不会出现在编码文本中,因此您可以摆脱符号填充 str_replace ("9Y6SnNmOBl", ">", $value)
代码。
在编码时执行此操作,并跳过符号填充。
$value = base64_encode($iv . $value);
在解码时执行此操作,并跳过符号 unstuffing。
$value = base64_decode($value);
$iv = substr($value, 0, 16);
$value = substr($value, 16);
这会使您的加密数据比其他情况大 1.3 倍。在现代大容量存储价格中,这并不算多,而且为简单而付出的合理价格。如果存在无法克服的成本障碍,您可以研究 MySQL 中的压缩行格式。
【讨论】:
美丽。它有效,但我仍然有点不确定发生了什么。如果我理解正确。该列确实是 VarChar。我的分隔符不会出现在字符串中,因为这些字符不是由 MCrypt 生成的?如果我正确理解另一部分,PHP 只使用 7 位字符,当我上传到数据库时,MySQL 会尝试从这些 7 位字符创建 8 位字符?varchar()
列具有隐含的字符集。我不知道您使用哪一个来存储您的数据。但是,允许 MySQL 更改不属于该字符集的文本字符串中的数据。您正在处理二进制数据。您也可能成功地将 varbinary()
数据类型与您之前的策略一起使用。不过,符号填充仍然是一个令人讨厌的 hack。
是的。现在我有一个问题,当数据显示在输入中以进行编辑时,它会被未知的二进制字符填充。以上是关于添加 MCrypt 的 AES-CBC 加密后数据未保存到数据库或未正确解密的主要内容,如果未能解决你的问题,请参考以下文章
AES (aes-cbc-128, aes-cbc-192, aes-cbc-256) 使用 openssl C 加密/解密