护网杯比赛,一道不算难的密码学却思路绕了好久才和出题人相符合,这里记录一下做题的过程及感想
题目的源码如下:
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变量也是一串随机的字符串
加密函数最外层是fez,然后fez中循环调用round函数进行加密,每一次循环都是使用K盒子中的一个随机字符串,其中round是真正实现加密的过程,是一个异或的过程,异或是将传入的明文的两部分还有一个K作为变量。
第一种思路:刚开始的时候,一看到urandom,便想到是不是伪随机数,但是google了一段时间发现urandom算是一个强伪随机数,还是比较安全的,而且就算我知道随机数种子,对于我前面解flag也没有帮助,还得靠暴力破解,应该不是出题人想要考的,所以这条路是行不通的,主要是以往在比赛中做的一些题目很多用到了暴力破解,所以看到密码学形成了一种思维定式,就想看看能不能结合暴力破解来解题。。。。唉
第二种思路:因为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异或,产生的新一轮的左右两部分拼接成为新的密文。
即假设初始明文为M,分为L和R两部分
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^

