1. 程式人生 > >護網杯一道密碼學的感想

護網杯一道密碼學的感想

       護網杯比賽,一道不算難的密碼學卻思路繞了好久才和出題人相符合,這裡記錄一下做題的過程及感想

       題目的原始碼如下:

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^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盒子和初始的明文的兩部分組成  

又因為在包含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.逆向分析,從後往前推