1. 程式人生 > 實用技巧 >攻防世界-密碼學-onetimepad

攻防世界-密碼學-onetimepad

1. 題目資訊

附件中包含實現加密的Python指令碼,與密文檔案。

2. 分析

2.1. 有限域GF(2^n)

構造有限域GF(2^n)時,首先需要GF(2)上次數為n的本原多項式g(x);對於GF(2^n)上的每個元素a,都可以用一個次數不超過n的多項式\(f_{a}\)表示:\(f_{a}(x)=\sum_{i=0}^{n-1}a_{i}\cdot x^{i}\),其中\(a_{n-1}\cdots a_{0}\)是a的二進位制表示;從而GF(2^n)上的四則運算定義如下:

  • 加法:對於\(a,b\in GF(2^{n})\),它們的多項式表示分別為\(f_{a},f_{b}\),記\(f_{c}=f_{a}+f_{b}\)

    (其中係數的加法為GF(2)上的加法,即異或運算),則\(c_{n-1}\cdots c_{0}\)的二進位制值c為a+b的值;

  • 減法:由於GF(2)上的加法與減法等價,因此對於\(a,b\in GF(2^{n})\),a+b=a-b;

  • 乘法:同樣地,a,b的多項式表示\(f_{a},f_{b}\),記\(f_c=f_{a}\cdot f_{b}\ \textrm{mod}\ g\),由於多項式\(g\)的次數為n,故多項式\(f_{c}\)的次數不超過n,則\(c_{n-1}\cdots c_{0}\)的二進位制值c為\(a\cdot b\)的值;

  • 除法:先介紹(乘法)逆元,本原多項式是一種具有特殊性質的不可約多項式,對GF(2)上任意次數不超過n的多項式f,都存在GF(2)上次數不超過n的多項式h,使得\(f\cdot h \equiv 1\ \textrm{mod}\ g\)

    ;與f作除法等價於與f的逆元h作乘法;

2.2. process(m,k)

考慮\(t^{2},t\in GF(2^{256})\),構造\(GF(2^{256})\)的本原多項式為\(g=x^{256}+x^{10}+x^{5}+x^{2}+1\),記t的二進位制表示為\(t_{n-1}\cdots t_{0}=(((t_{n-1}\cdot x+t_{n-2})\cdot x+\cdots +t_{1})\cdot x+t_{0})\),則t的多項式表示\(f_{t}(x)=\sum_{i=0}^{n-1}t_{i}\cdot x^{i}\),考慮\(t^{2}\)

\(f_{t}^{2}\ \textrm{mod}\ g\)

\(=(((t_{n-1}\cdot x+t_{n-2})\cdot x+\cdots +t_{1})\cdot x+t_{0})\cdot f_{t}\ \textrm{mod}\ g\)

\(=((((t_{n-1}\cdot f_{t})\cdot x+t_{n-2}\cdot f_{t})\cdot x+\cdots +t_{1}\cdot f_{t})\cdot x+t_{0}\cdot f_{t})\ \textrm{mod}\ g\)

\(=((((((t_{n-1}\cdot f_{t})\cdot x+t_{n-2}\cdot f_{t})\ \textrm{mod}\ g)\cdot x+\cdots +t_{1}\cdot f_{t})\ \textrm{mod}\ g)\cdot x+t_{0}\cdot f_{t})\ \textrm{mod}\ g\)

我們再來對比函式process(m,k):

def process(m, k):
    tmp = m ^ k
    res = 0
    for i in bin(tmp)[2:]:
        res = res << 1;
        if (int(i)):
            res = res ^ tmp
        if (res >> 256):
            res = res ^ P
    return res

res=res<<1代表乘以x,多項式的係數全體左移一位;

if (int(i)):res^=tmp等價於res^=int(i)*tmp,代表\(+t_{i}\cdot f_{t}\)

if (res>>256):res^=P代表模本原多項式g;

綜上,process(m,k)實際上實現了GF(2^256)上的元素m與k之和的平方\((m+k)^{2}\)

2.3. 解密過程

\(k_{2}=(k_{1}+secret)^{2},k_{3}=(k_{2}+secret)^{2}\)(在GF(2^256)上的運算)

\(c_{1}=m_{1}\oplus k_{1},c_{2}=m_{2}\oplus k_{2},c_{3}=m_{3}\oplus k_{3}\),其中\(c_{i}(i=1,2,3),m_{i}(i=1,2)\)已知

\(k_{2}=m_{2}\oplus c_{2},k_{3}=m_{3}\oplus c_{3}\),可解出secret:\(secret=k_{3}^{1/2}+k_{2}\)(在GF(2^256)上的運算)

接下來解出\(k_{1}\)\(k_{1}=k_{2}^{1/2}+secret\)(在GF(2^256)上的運算)

然後解出flag(即\(m_{1}\)):\(m_{1}=c_{1}\oplus k_{1}\)

3. 解題

實現的sage指令碼如下:

from Crypto.Util.number import bytes_to_long,long_to_bytes

K.<x>=GF(2L**256,modulus=x^256+x^10+x^5+x^2+1)

def polify(N):
    bN=list(bin(N)[2:])
    bN.reverse()
    return K(bN)

def unpolify(Poly):
    bN=Poly.polynomial().list()
    bN.reverse()
    return long(''.join([str(it) for it in bN]),2)

def solve():
    cip1=polify(0xaf3fcc28377e7e983355096fd4f635856df82bbab61d2c50892d9ee5d913a07f)
    cip2=polify(0x630eb4dce274d29a16f86940f2f35253477665949170ed9e8c9e828794b5543c)
    cip3=polify(0xe913db07cbe4f433c7cdeaac549757d23651ebdccf69d7fbdfd5dc2829334d1b)
    msg2=polify(bytes_to_long('I_am_not_a_secret_so_you_know_me'))
    msg3=polify(bytes_to_long('feeddeadbeefcafefeeddeadbeefcafe'))
    secret=cip2+msg2+(cip3+msg3).sqrt()
    key1=(cip2+msg2).sqrt()+secret
    msg1=cip1+key1
    return long_to_bytes(unpolify(msg1))

if __name__=='__main__':
    print 'flag{'+solve()+'}'

程式執行結果如下:

$ sage solve.sage
flag{t0_B3_r4ndoM_en0Ugh_1s_nec3s5arY}