AES-CBC 加密的两种攻击方式

最重要的事是先了解加解密流程
encrypt.png

decrypt.png

作为一种流密码加密,每次进行encrypt操作的时候是有两个参数的,一个16字节的明文块(block)和上一个密文block,两者xor操作后再进行真正的加密算法。那么加密第一个明文block时没有上一个密文block怎么办呢,所以就有iv,作为第一个块的前一个快的密文来帮助加密,传输时一般用明文方式放在密文的前面,也做到了加密的随机化(只要iv不同,相同明文的密文会不同)。所以说加密的顺序是从左向右的。那么解密呢?从右向左还是从左向右?其实是无所谓的。因为传输时密文的组成通常是16字节的iv加上16字节整数倍的真正密文。针对于任何一个密文block,知道在他前面一个密文block就能成功解密(明文block=decrypt(密文block) xor 上一个密文block)。也就导致不能多线程加密,却可以多线程解密。
【Bit-flipping attack】在刚刚这个解密的过程中,看起来是没有问题的,但是其实存在着一个缺陷。从刚才原理上分析,每一个block的解密过程都是独立的。当我把任意两个连续密文block拿出来解密的时候,一定会解密出来第二个block的明文。比如说当我注册一个admin用户的时候,密文就是16字节iv+16字节密文,当我注册一个1234567890123456admin的时候密文是16字节iv+32字节密文。但是我单独把后32位密文拿出来解密,即把密文前16字节当作iv,解密出来也是admin。
继续思考解密过程,密文固定,密钥固定,decrypt(密文block)的时候得到中间值(intermediary value)也是固定的,为当前明文block xor 上一个密文block(解密第一个密文block前一个密文block则是iv)。假如明文已知,而上一个block密文是我们能控制的,就能计算得到中间值,然后就能构造出任意明文的密文。举例当我注册一个admix用户,得到admix的密文,为16字节iv+16字节密文。那么解密的时候,通过密文和密钥得到固定中间值,明文[5]=中间值[5]xor iv[5],得到x。然而iv是可控的,让iv[5] xor 明文[5]得到中间值[5],再让中间值[5] xor n 得到的值放入iv中的第5位(iv[5]=iv[5] ^ 'x' ^ 'n'),解密出来就是明文admin。如果需要更改的字符串在密文第二个block中的时候,改变的iv就位于密文第一个block之中。更改第一个密文block的内容仍然可以导致第二个block的明文字符更换,但是这样也导致第一个密文block和iv在一起解密的时候不能正常地解密。所以有一个定义说这种攻击是损坏密文字节来改变明文字节。不过也不太完全。当明文字节位于第一个密文block的时候,改变iv就不会损坏密文字节。
【padding oracle attack】ecb加解密是针对于块的,对于长度不到一到个快的明文,是需要填充的。通常来说填充标准是pkcs#7或pkcs#5。其填充算法是相同的,即差x个字符就填充x个x。如果一个块只有2个字符的明文,就会在这两个字符后填充14个0x14,如果刚好16个字符,会新增一个块填充16个0x16。所以任意密文解密的时候都是有padding的,如果padding不合法,解密算法就会出错,php函数返回null或者服务器返回500错误。如果我们通过控制iv来让服务器多次进行解密过程,并得到服务器解密是否成功的信息的话,就能通过padding是否合法来得到密文的中间值,进而解密明文或者构造密文。举例,当我加密admin过后得到16字节的iv,16字节的密文。这16字节的密文解密出来的中间值是固定的,等于iv xor 'admin\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11'。如果我更改iv为16个随机字符,解密过程是会出错的,因为解密出来是16个字符,而16个字符是不合法的,因为其不含有padding。如果我们爆破第iv第16个字节,至少有一个字符会让明文变得合法(第16字节明文为0x1或者第15字节明文=第16字节明文=0x2)。如果同时出现了这2种情况,我们就改变第15字节的iv,让明文15位解密出来不为0x2,再爆破之后得到了一个特殊的iv_speacial[16]使得明文为0x1。这个时候就得到中间值[16]=iv_speacial[16] xor 1。而明文[16]=中间值[16] xor 原iv[16],在不知道密钥的情况下就得到了明文。然后我们让iv[16]=中间值[16] xor 2,即让16位明文为0x2,类似地,通过爆破第15位字节iv,一定只会有一个字符使得明文[15]=0x2,让明文合法,让密文成功被解密。同样,这样就能得到中间值[15]... 得到16字节完整的中间值之后,这段密文的明文=中间值 xor 原iv。如果需要admin233的密文,只需要使iv=中间值 xor 'admin233\x08\x08\x08\x08\x08\x08\x08\x08',后面16个密文字节不变(这样才能让解密出来的中间值不变)即可。

添加新评论