攻防世界-密码学-SM

1. 题目信息

附件中包含一个Python脚本sm.py,3个文本文件。

2. 分析

读完一遍sm.py后,可以确定解题的思路是先由ps与r解出bchoose,再由bchoose按照同样的过程计算出密钥key,最后进行AES解密求出flag。首先看生成r的代码:

r=0
for i in range(512):
    if bchoose[i]=='1':
        r=r^ps[i]

(r=sum_{i=1}^{512} extrm{bchoose[i]}cdot extrm{ps[i]})(此处的加法是异或);虽然生成方式类似背包加密,但是由于ps具有很好的性质,我们不使用破解背包加密的方法来解此题;我们来分析生成ps的gen512num函数:

def gen512num():
    order=[]
    while len(order)!=512:
        tmp=randint(1,512)
        if tmp not in order:
            order.append(tmp)
    ps=[]
    for i in range(512):
        p=getPrime(512-order[i]+10)
        pre=bin(p)[2:][0:(512-order[i])]+"1"
        ps.append(int(pre+"0"*(512-len(pre)),2))
    return ps

order是1,2,...,512的一个随机的排列,对ps[i]:首先生成一个长度为512-order[i]+10的素数,去掉此素数的最后10位,同时在尾部追加一个二进制位1,最后在后面填充0使得长度为512;我们首先考虑生成r的最后1个二进制位,ps中只有1个数最后1位为1,其余数最后1位均为0,那么最后1位为1的数如果没有“加入”异或运算,那么r的最后1位一定为0,否则,一定为1,这样我们通过r的最后1位就可以推断出bchoose的第j位(记order[j]=1)。接下来,(roplus ( extrm{bchoose[j]}cdot extrm{ps[j]})=sum_{i eq j} extrm{bchoose[i]}cdot extrm{ps[i]}),在{ps[i]| i( eq)j}中,只有1个数倒数第2位为1,同理,可推断出bchoose的第k位(记order[k]=2),直到推断出bchoose所有位。

3. 解题

实现的Python脚本如下:

from base64 import b64decode
from hashlib import md5
from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes

def cal_k():
    with open('ps','r') as f:
        ps=[long(x) for x in f.read().split('
')[:-1]]
    with open('r','r') as f:
        r=long(f.read())
    pbits=[bin(x).rfind('1')-2 for x in ps]
    bc=['0']*512
    for le in range(512):
        ind=pbits.index(511-le)
        tt=bin(r)[2:].rjust(512,'0')[511-le]
        if tt=='1':
            bc[ind]='1'
            r^=ps[ind]
    return long(''.join(bc),2)

def solve():
    with open('ef','rb') as f:
        ef=b64decode(f.read())
    key=long_to_bytes(int(md5(long_to_bytes(cal_k())).hexdigest(),16))
    aes_obj = AES.new(key, AES.MODE_ECB)
    return aes_obj.decrypt(ef)

if __name__=='__main__':
    print solve()

程序运行结果如下:

$ python solve.py
flag{shemir_alotof_in_wctf_fun!}
原文地址:https://www.cnblogs.com/coming1890/p/13547193.html