找回密码
 立即注册
  • QQ空间
  • 回复
  • 收藏

深入浅出AES算法

admin 2019-9-16 06:04 99人围观 C++相关

AES算法


高级加密标准(Advanced Encryption Standard,AES)是美帝2001年发布的块加密算法,AES是属于块加密算法框架中的一个组件,所以理解AES的关键是搞清楚块加密算法。(块加密算法是一个“框”,AES只是“框”中的一个东西)

块加密算法工作原理


块加密算法也叫分组密码工作模式(block mode of operation)它会把明文按等长的块(Block)分组然后利用某种加密算法进行加密——AES就属于“某种加密算法”中的一种。用一幅图表示二者关系:



块加密算法有三个关键部分


  • 填充方式,负责把明文切分成一块一块的。块加密要求数据一定要符合块大小,以AES为例它规定每个数据块的大小是128个bit位(16字节),如果数据不足16字节那么必须**填充**到16字节。填充的数据是字节长度,比如一个5字节的块需要填充到16个字节,那么剩下的9个字节就全部写上09 09 09……。 PKCS5Padding和PKCS7Padding是分别出在不同规范的两个标准,PKCS5规定了块大小是8字节;PKCS7没有限制。由于AES已经限制了块的大小,所以它们两个在AES里面其实没有什么区别。所以在Java里面只提供了AES+PKC5Padding(AES+PKCS7Padding,这个说法不对,AES已经限制了块大小)。

  • 加密算法,负责对每一块的明文进行加密。对算法输入明文和密钥,算法输出加密后的密文块,常见的算法是AES、DES。

  • 工作方式,块加密非常灵活利用不同的工作模式可以实现**并行、密文可变(每次加密得到的密文都不一样)、容错**

块加密算法的五种工作方式


按照块加密算法的不同工作模式常见的有5种(为了简化问题我只贴加密过程):

  • 电子密码本(ECB,Electronic codebook)



Key是密钥,Plaintext是明文,中间的Block Cipher Encryption是加密算法(比如AES就是其中一种)。密钥和明文作为输入经过加密之后得到密文——Ciphertext。ECB工作模式非常简单,可以并行处理;一个线程负责把数据切分成N块后由N个线程同时进行加密。它的缺点是同样的密钥每次执行加密出来的数据都是相同的。正常人看——比如我,这太正常了,但是“密码专家”们认为这太弱鸡了(囧)。所以他们设计了一种特别的算法,通过一个叫“初始向量(IV,Initialization Vector)”的变量让每次进行加密得到的密文都不一样(即便密钥相同)。剩下的4种块工作模式都属于这种牛B的类型。


  • 密码块链接(CBC,Cipher-block chaining)



这里的输入多了一个叫Initialization Vector(IV)的变量;明文和IV异或之后通过作为加密算法的一个变量输入,密钥作为另一个变量输入。CBC加密算法是一个串行算法,第二块的加密依赖于第一块密文作为IV。所以计算它的时候只能按部就班一块一块的计算。


  • 密文反馈(CFB,Cipher feedback)



之前的块加密都没有解决容错问题——如果我一个数据块坏掉了那么能不能解密出其余的数据块。于是就有了CFB工作模式,注意观察上图,解密的时候如果第一个密文块损坏那么可以无视这块内容,直接用第二个密文作为输入对第三个密文块进行解密。


  • 输出反馈模式(OFB,Output feedback)



CBC虽然狂屌炸(每次都能算出不同的密文)但是不能并行,对于“时间就是金钱”的计算机来说是无法容忍的。于是就有了第一次改进——OFB。注意IV和密钥经过加密后这里是可以并行的,其中一个线程用于和明文的异或;一个线程可以立马计算“下次”加密。


  • 计数器模式(CTR,Counter mode)



OFB算法的并行度太低,仅仅实现一部分并行,于是就有了第二次改进——CTR算法,同时保证了并行度和密文可变性。CTR算法中的IV变成了两部分,第一个是Nonce可以是一个随机序列,第二部分是计数器(Countter),是一个递增的数字。于是加密的时候通过组合Nonce和计算器就可以对得到有规律但是不相同的(每次密文都不同的关键是IV的可变)“IV”。

总结


从三个维度理解五种工作模式——密文是否固定、是否可以并行、有没有容错

  • ECB密文固定,全并行

  • CBC密文可变,不可并行

  • CFB密文容错,密文可变,不可并行

  • OFB密文可变,部分并行

  • CTR密文可变,全并行

需要注意的是除非数据量特别大否则我们不必在乎是否并行;容错在小数据量的时候也凸显不出效果,所以CBC一般是最好的选择。

如何跨语言


很多朋友都碰到一个语言写的AES加密在另个一语言解密不了的问题,究其原因是由于根本没有理解AES的工作模式(可能就是Google了一下AES加密,然后代码贴上收工)。所以我觉得跨语言的第一步不是找到一种能在所有语言通用的工作模式——所有工作模式每个语言几乎都支持;而是搞清楚你加密出来的数据是那种工作模式,有没有用到IV?IV是通过什么方式传递给对方的?比如下面的Java代码:



我使用了CBC加密模式,这种模式涉及到IV,我们可以用一个固定的IV(比如用key作为IV)——但是意味着没有了CBC的好处,密文可变。所以我用一个随机16字节作为IV,返回的时候把它作为第一个数据块;解密的时候只要取出第一个数据块作为IV,然后再对余下的数据进行解密。



如果我们不指定IV参数(init函数的第三个参数),那么iv就是一个随机数。Java是不会主动把IV附加到密文上,所以这种加密出来的数据是谁也没有办法解出来的。

欢迎关注公众账号了解更多信息“写程序的康德——思考、批判、理性”




----------------------------------------------------------------------------------------------------------------------
我们尊重原创,也注重分享,文章来源于微信公众号:写程序的康德,建议关注公众号查看原文。如若侵权请联系qter@qter.org。
----------------------------------------------------------------------------------------------------------------------

鲜花

握手

雷人

路过

鸡蛋

yafeilinux和他的朋友们微信公众号二维码

微信公众号

专注于Qt嵌入式Linux开发等。扫一扫立即关注。

Qt开源社区官方QQ群二维码

QQ交流群

欢迎加入QQ群大家庭,一起讨论学习!

我有话说......