护网杯比赛,一道不算难的密码学却思路绕了很久才和出题人相符合,这里记录一下作题的过程及感想安全
题目的源码以下:app
import os def xor(a,b): assert len(a)==len(b) c="" for i in range(len(a)): c+=chr(ord(a[i])^ord(b[i])) return c def f(x,k): return xor(xor(x,k),7) def round(M,K): L=M[0:27] R=M[27:54] new_l=R new_r=xor(xor(R,L),K) return new_l+new_r def fez(m,K): for i in K: m=round(m,i) return m K=[] for i in range(7): K.append(os.urandom(27)) m=open("flag","rb").read() assert len(m)<54 m+=os.urandom(54-len(m)) test=os.urandom(54) print test.encode("hex") print fez(test,K).encode("hex") print fez(m,K).encode("hex")
除了源码,还给了三行16进制的数,看到这道题目时,首先分析一下题目,给了一个K盒子,用于加密过程使用,K是一个由7个随机字符串产生的。其中m变量的前面一部分包含着flag,test变量也是一串随机的字符串dom
加密函数最外层是fez,而后fez中循环调用round函数进行加密,每一次循环都是使用K盒子中的一个随机字符串,其中round是真正实现加密的过程,是一个异或的过程,异或是将传入的明文的两部分还有一个K做为变量。函数
第一种思路:刚开始的时候,一看到urandom,便想到是否是伪随机数,可是google了一段时间发现urandom算是一个强伪随机数,仍是比较安全的,并且就算我知道随机数种子,对于我前面解flag也没有帮助,还得靠暴力破解,应该不是出题人想要考的,因此这条路是行不通的,主要是以往在比赛中作的一些题目不少用到了暴力破解,因此看到密码学造成了一种思惟定式,就想看看能不能结合暴力破解来解题。。。。唉google
第二种思路:由于test是已知的,第一次fez的调用中用到了test和K,而且密文也是已知的,那么能不能解出来K,而后去解flag?因而回到round函数,能够看到最后一次加密结束时,用到的是K7,那么最后一次的E_L和E_R咱们是知道的,咱们能不能推出前一次的L和R,也就是没有通过轮加密的L和R,咱们已经知道下一轮的密文L等于上一轮的R,下一轮的R等于上一轮的R异或L再异或当前轮所使用的K,那么很容易得出咱们能得到上一轮所使用的明文的右半部分,有了上一轮的右半部分,加密后的新的右半部分,若是咱们求出上一轮的左边的部分,就能求出当前轮所使用的K,可是根绝目前已知的全部条件,上一轮的明文的左半部分是没法求出的,卡在这里了很长时间,结果无奈放弃了加密
第三种思路:正向来模拟加密的过程,来发现是否存在漏洞,在round函数中,新一轮的左半部分等于上一轮的右半部分,下一轮的右半部分等于上一轮的左右两部分异或以后再和当前轮的K异或,产生的新一轮的左右两部分拼接成为新的密文。spa
即假设初始明文为M,分为L和R两部分code
1 第一轮:R+R^L^K1 2 第二轮:R^L^K1+R^R^L^K1=>R^L^K1+L^K1^K2 3 第三轮:L^K1^K2+R^K2^K3 4 第四轮:R^K2^K3+L^R^K1^K3^K4 5 第五轮:L^R^K1^K3^K4+L^K1^K2^K4^K5 6 第六轮:L^K1^K2^K4^K5+R^K2^K3^K5^k6 7 第七轮:R^K2^K3^K5^k6+R^L^K1^K3^K4^K6^K7
由最终的形式能够看到,结果由K盒子和初始的明文的两部分组成 blog
又由于在包含flag的m变量中进行了相同的fez函数加密,因此和test调用fez函数之后的结果形式是相同的,只是初始的明文不一样,又由于根据异或运算的计算逻辑,相同的数异或为0,0异或任何数仍是其自己,所i有即便咱们不知道K盒子,由于两次运算结果的K盒子在结果中的形式相同,因此能够抵消掉。字符串
所以解为两部分:
1.第七轮结束后的密文的左半部分异或后实际就是test变量的右半部分和flag的右半部分进行了一次异或,再和test自己的右半部分异或一次,就能获得m变量的右半部分。
2.第七轮结束后的密文的左右两部分异或获得只剩下原明文左半部分和K盒组成的结果,即两次fez加密的结果的各自的左右两部分先作异或运算,而后再把两组异或结果再一块儿异或一次,即为test变量的左半部分和m变量的左半部分异或的结果,又由于test变量已知,因此把结果再和test变量的左半部分异或一次就能获得m的左半部分。
通过以上两步,就能获得明文m,又由于m中包含了flag,因此咱们就解出了答案。
仍是本身不懂套路,K盒属于中间变量,而且加密为异或加密,更况且这是已知密文的攻击,调用了两次相同的加密方式,使用的K盒也是相同的,因此才产生了这样的漏洞,下次分析题目2条路:
1.先正向分析加密流程,分析加密后的结果组成,能不用暴力解决就不要用
2.逆向分析,从后往前推