加入收藏 | 设为首页 | 会员中心 | 我要投稿 济南站长网 (https://www.0531zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 运营中心 > 建站资源 > 策划 > 正文

对称加密与攻击案例分析

发布时间:2019-06-13 06:24:06 所属栏目:策划 来源:有价值炮灰
导读:副标题#e# 本文主要介绍常见的对称加密算法和它们的原理,然后分析一些实际存在的密码学攻击案例,包括流加密密钥重用漏洞、ECB块重排攻击以及CBC的Padding Oracle攻击等。 一、对称加密 当今我们所使用的加密算法,大致可以分为两类,即对称加密与非对称加

再回想一下我们介绍CBC块加密时说过,在一个加密块(Block N)中翻转某一位,则会在解密后导致对应的下一个明文块(Block N+1)中相同的位进行翻转。由于这个特性,我们可以在不知道密钥的情况下,使用服务器来猜解出明文数据。

最后一字节

具体怎么做呢?再次仔细思考一下CBC模式的解密流程,若要解密一个块,则需要其本身的密文C2以及前一个块的密文C1,解密的流程如下:

cbc decrypt

在这种攻击场景下,我们(攻击者)可以控制输入密文块的内容,并且获取服务器的差异化返回,即是否填充错误。假设C2是最后一个块,那么通过变异C1,就可以猜解C2明文。猜解过程如下:

  • 将C1前15字节随机设置,第16字节设置为’x00’
  • 将修改后的密文块发送给服务器解密

由于我们修改了C1的最后一个字节,那么根据上文介绍,在解密后C2的明文P2最后一个字节也会进行改变,变成什么我们还不知道,但是我们知道:

  1. P2[15] = I2[15] xor C1[15] 

其中I2是解密算法如AES解密后的中间值,我们不关心具体解密算法,但总有这么个值。然后,根据服务器的返回我们知道有两种可能:

  • 返回填充不合法。此时P2[15]未知。
  • 返回填充合法。此时P2[15]肯定为0x01,因为只有这样才能出现合法的填充。

如果是第一种情况,我们就继续变异C1[15],直到出现合法的填充,即第二种情况。假设我们在变异到C1[15] = 0x42时才出现合法填充,则此时有:

  1. P2[15] = I2[15] xor C1[15] 
  2. I2[15] = P2[15] xor C1[15] = 0x01 xor 0x26 = 0x27 

回顾一下上图,I2的产生与C1无关,只与C2和密钥key相关,但是我们却计算出了I2[15]的值!因此我们可以用I2[15]异或上变异前的C1[15]从而获得原始的明文。

  1. P2[15] = 0x27 xor C1[15] 

这就是Padding Oracle攻击的思路。

五、下一个字节

为了完成攻击,我们继续使用类似方式猜解I2中更多的内容。

  • 将C1前14字节设置为随机值
  • C1[14]设置为0×00
  • C1[15]设置为能令P2[15] = 0x02的值
  1. P2[15] = I2[15] xor C1[15] 
  2. C1[15] = P2[15] xor I2[15] = 0x02 xor 0x27 = 0x25 

即将C1[15]固定为0×25,继续爆破C1[14]知道出现合法的填充,此时P2[14]=0x02,假设出现合法填充时候爆破的C1[14]值为0×68:

  1. P2[14] = I2[14] xor C1[14] = 0x02 
  2. I2[14] = P2[14] xor C1[14] = 0x02 xor 0x68 = 0x6A 

再一次,我们获得了真实的I2[14]值,从何可以算出原始的明文P2[14]。以此类推,最终我们可以计算出完整的明文P2内容。

六、下一个块

根据上述方法,我们已经可以还原最后一个密文块的明文了。而对于CBC模式,每个密文块的解密仅和当前块以及前一个块相关,因此上述攻击可以应用到所有块中,除了第一个。

第一个块的加解密使用初始化向量IV进行,对此没有通用破解方法。但是CBC加密中IV也不是必须保密的,因此在实践中通常会组合到密文的最前面或者最后面,其长度和块大小相同。如果一定要解密第一个块,可以使用这种猜测方法。

七、示例

实践出真知,我们来看一个具体的例子。首先用Flask写一个简单的应用,如下:

  1. #!/usr/bin/env python3 
  2. import binascii 
  3. import string 
  4. import random 
  5.  
  6. from Crypto.Cipher import AES 
  7. from Crypto.Util.Padding import pad, unpad 
  8. from flask import Flask, request 
  9.  
  10. app = Flask(__name__) 
  11. db = {} 
  12. BSIZE = 16 
  13. secret = b'x26' * BSIZE 
  14.  
  15. def get_iv(): 
  16.     return b'x00' * BSIZE 
  17.  
  18. def decrypt(data): 
  19.     datadata = data.encode() 
  20.     data = binascii.unhexlify(data) 
  21.     iv = data[:BSIZE] 
  22.     engine = AES.new(key=secret, mode=AES.MODE_CBC, iviv=iv) 
  23.     datadata = data[BSIZE:] 
  24.     data = engine.decrypt(data) 
  25.     data = unpad(data, BSIZE) 
  26.     return data.decode() 
  27.  
  28. def encrypt(data): 
  29.     datadata = data.encode() 
  30.     iv = get_iv() 
  31.     engine = AES.new(key=secret, mode=AES.MODE_CBC, iviv=iv) 
  32.     return binascii.hexlify(iv + engine.encrypt(pad(data, BSIZE))).decode() 
  33.  
  34. @app.route('/dec/<data>') 
  35. def dec(data): 
  36.     # print('dec:', data) 
  37.     try: 
  38.         key = decrypt(data) 
  39.     except Exception as e: 
  40.         return 'Error: ' + str(e) 
  41.     if key not in db: 
  42.         return 'Error: invalid key' 
  43.     return db[key] 
  44.  
  45. @app.route('/enc/<key>') 
  46. def enc(key): 
  47.     db[key] = 'valid' 
  48.     return encrypt(key) 
  49.  
  50. app.run(debug=False) 

(编辑:济南站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读