对称加密和Base64编码

http://blog.7rule.com/2018/03/09/crypto-base64.html

缘起

前阵子在用golang重构一段php逻辑,那段代码中用到了mcrypt_encrypt和base64_encode方法,大致如下:

看起来挺简单的php调用,使用golang重构时发现没那么简单。

无论是mcrypt_encrypt还是base64_encode,在golang中都无法很简单的用一个现成的方法调用,且看官方包文档时很多概念都搞不懂。

网上查看了一些资料,感觉理解的还不是很清楚,最终我从这两个方法的基本概念入手,简单学习了下,感觉清晰了很多,完成了重构。

本篇文章就是把这次学到的关于对称加密和base64编码的基本概念在这里做个简单的讲解,让大家能从基本原理中理解这两个方法的正确使用方式。

对称加密

简单说:使用相同密钥进行加密解密叫做对称加密。

带着的问题

加密和解密操作是如何实现的?

DES、AES是什么意思?AES-128、AES-256又是什么东西?如何选择?

加密模式是什么?多种加密模式应当如何选择?

初始向量是什么?

加密和解密的运算本质(XOR)

现代加解密运算都是计算机运算,也就是0和1的位运算,对称加密中,最重要的当属XOR运算。

XOR也叫做异或运算,规则如下:

如果是比特序列之间的XOR运算,只需要对其中每个对应的比特进行XOR运算即可,例:

这里就有了个有趣的地方:

即:

如果A是明文,B是密钥,那么 即实现了加密, 即实现了解密。

分组加密的概念

这里用一个最简单的示例来说明基本概念。

上面大家看到了,加密需要进行运算,这就需要运算双方的长度相同,也就是明文和密钥的长度是相同的。

但是,实际通常要加密的明文长度很长,密钥通常是相对固定的,那么如何做呢?

这就需要把明文按照密钥的长度进行分组,即分成多个,然后对每个分别和密钥进行迭代的运算,形成最终的密文,其中迭代的方式就称为。

上面描述的就是最简单的分组加密的概念,实际中的算法会复杂很多,这些等。

阶段小结

通过上面的解释,相信大家已经了解了对称加密的基本原理。

本质上就是一种的对称加密算法,但这种算法现在已经被认为是不安全的,所以后来又出现了,它对DES具备向下兼容性。

则是为了取代DES而生的,它通过公开精选,最终选定了一个叫做的分组密码算法。上面提到的,即是指密钥的长度。

模式

模式指的就是分组加密的迭代方式,主要有如下几种:

ECB

CBC

CFB

OFB

CTR

先给个结论:

绝对不要使用 ,这个模式是非常不安全的。

现在使用最多的,就是,这也是中在使用的模式。

ECB

ECB模式将明文分组加密之后的结果直接作为密文结果,如下图:

这个模式最大的问题,就是相同的明文分组会转换为相同的密文分组。因为只要观察一下密文,就可以知道明文中存在怎样的重复组合,并可以借此攻击。

举个例子,假如A要向B转账100元,数据由3个分组构成:

付款人A的账号

收款人B的账号

转账金额

ECB加密后的密文简单示例如下:

59 7D DE CC

DF 49 2A 1C

CD AF D5 9E

假如攻击者将1和2的内容进行调换,则变为:

DF 49 2A 1C

59 7D DE CC

CD AF D5 9E

这样一来,就变为了B向A转账100元。

ECB模式的一大漏洞,就是攻击者可以在不破解密文的情况下操纵明文。

CBC

CBC的全称是(密文分组链接),正如其名,密文分组会像链条一样相互连接起来。

CBC模式首先将明文分组与前一个密文分组进行XOR运算,然后再进行加密,就这样一直加密完所有分组。

这里出现了这个概念:当加密第一个明文分组时,由于不存在“前一个密文分组”,因此就需要一个长度为一个分组的比特序列来代替,这个比特序列就叫做初始化向量(IV),ECB中不需要。

CBC模式现在是使用最广泛的对称加密模式,TLS协议(https中使用)中即使用此模式。

使用golang重构php的mcrypt_encode

我们这里使用AES的CBC模式,这里会涉及到3个重要的值:、、。

密钥key

key的长度,可选,这是为了对应。

的复杂度最高,所以我们最好选择这个,这样就需要,有个最好的办法就是对自定义的key做md5得到的字符串值即可。

初始化向量iv

iv的长度,需要和分组大小相同,AES的分组大小是,即。我们这里可以对自定义的iv做md5后得到的字符串值取前16个字节即可。

明文data

明文会被自动分组,为了能让每个分组的长度固定,就需要先对明文进行数据填充,再进行分组加密操作。这里我们使用最常用的一种数据分组填充方式

AES代码:https://github.com/goinbox/crypto/blob/master/aes.go

PKCS5Padding代码:https://github.com/goinbox/crypto/blob/master/padding.go

Demo

是不是发现原本php一个方法做的事情,到了golang中需要做这么多的事。

很多高级语言都做了很多的封装,让大家不必了解过多的细节即可使用,但同时我们也失去了学习更多东西的机会。

现在大家可以再回过头看看之前自己用过的对称加密方法,对其中的参数是不是就理解了,再想想看是否之前有使用不当的地方,笔者就发现了之前一个重要的业务中使用了ECB模式,赶紧改了,呵呵。

Base64编码

再来说下Base64编码。

上面加密后的密文,通常会包含很多不可见字符,这样通常会对加密后的结果做一次编码的工作,这样就可以在各处使用了。

带着的问题

这里我遇到的一个问题,就是为什么要用Base64进行编码,我看还有Base32啊,为什么不用那个呢?

有了前面的经验,我认识到还是要去了解下Base64编码和Base32编码的本质是什么,才能判断。

详解

Base64编码使用64个字符来对任意数据进行编码,同理Base32编码会使用32个字符对任意数据进行编码。

Base64编码的64个字符为:

编码的过程,先将数据转成二进制形式,然后每计算十进制值,再在上面的对应表中转换为对应字符,最终得到一个字符串,示例:

最后的那些0,是需要进行补齐填充的bit。另外,标准Base64会使用来替代,这是因为不在索引表中,可以作为结束符存在。

小结

使用Base64编码后的数据长度会增加1/3,Base32因为要使用更少的字符,所以编码后的长度要增加3/5。

有此可见,Base64在某种程度上来说兼顾了字符集大小和编码后数据长度,所以它的应用场景也更加广泛。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180309G0RT0K00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券