base256研究

返回
Author Avatar
钢翼
2021-06-17
编程
195

需求:

数据库某些字段需要加密存储,但同时又希望该字段支持like查询。

思考:

1、base64

可能你一开始会想到用base64实现字段加密不可读。

这里我们需要了解base64的原理。

base64其实就是10个数字+26个大写字母+26个小写字母+2个特殊字符(+/)的64进制,64是2的6次方,所以它的一个字符等于6bit。

但是它又不完全是纯64进制。因为它规定了它最小存储是4位字符(24bit),且字符长度永远是4的倍数。

以utf-8编码为例,一般数字和字母只需要8bit,拉丁字母需要16bit,中文需要24bit,一个字符串不可能永远是24bit的整数倍。所以base64需要补位,当长度达不到4的整数倍会在结尾补=号,直到位数满足要求。

由上面可知,base64并不能满足我们的like查询需求,因为他一个字符是6bit。除非你原字符串都是汉字(每个汉字都是24bit),不然只要中间有数字或拉丁字母这种无法被6bit整除的字符,你后面的字符都会被打散。导致无法通过like匹配。更何况还有补位=号的存在。

综上所述,base64并不是这个需求的解决方案。

2、16进制

既然base64不行,那我们用16进制不就好了。让我们尝试一下。

16进制也就是用10个数字+6个字母(abcdef)组成的字符串。16是2的4次方,所以他的一个字符等于4bit

数字和字母只需要8bit(2位十六进制),拉丁字母需要16bit(4位十六进制),中文需要24bit(6位十六进制)。

粗看好像用like可以查询。但是你有没有发现连最小的一个字符都需要2个十六进制字符才能表示,加密字符串长度变得很长。

你只要奇偶错开下,就会发现大问题。

比如下面的例子,如果你用CS加密后去like查询,一定会查出456的字符串。这样查出来的数据又有什么意义。

  • 456 -> 343536
  • CS -> 4353

3、 Base256

这个是我能想得到的目前最佳的一种方案。

用256个字符(数字+字母+特殊字符+拉丁字母等)来加密字符串。256是2的8次方,所以它的一个字符等于8bit。

数字和字母只需要8bit(1位256进制),拉丁字母需要16bit(2位256进制),中文需要24bit(3位256进制)。

由于每个字符都能被8bit完美整除,也就支持like查询。

接着我们看下会不会像16进制查询混乱的问题。理论上存在可能。

但是由于utf-8的编码规则:如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。

应该可以规避掉很多查询混乱的情况,目前我还没发现有查询混乱的情况。

再思考

既然选择了base256进行加密,那安全性怎样呢?

base256加密是我习惯的叫法,本质还是编码,只要知晓了编码表,解码都是很简单。即使编码表没有外泄,通过明文密文对比,推导出编码表也是可行的。

为了能直接like查询,我们不可能对其进行置换加密。能采取的加密无非是偏移量加密,但是偏移量加密本质也就是打乱编码表,还是可以通过明文密文对比破解。

应对数据库加密的话我感觉还是足够的,你字段既然加密了,应用肯定也是需要登录才能查看该字段的信息。所以至少你得数据库和应用同时被入侵,才可能破解。

注:如果是用户密码字段在数据库不建议使用以上这些无损加密方法。而是应该采用有损加密,使得入侵者无法倒推密码。用户在一个网站的密码泄露,很可能意味着他/她全网的密码泄露。密码字段还是建议加盐md5存储。

其他方案

https://blog.csdn.net/u012516914/article/details/114422156

https://open.taobao.com/docV3.htm?docId=106213&docType=1

如果觉得base256不够好,也可以参考上面链接,业内流行的做法,不过他为了支持like,是分词加密后拼到一起的。加密后的密文长度可能是你难以承受的。