题目展现
from Crypto.Util.number import getPrime,long_to_bytes,bytes_to_long
from Crypto.Cipher import AES
import hashlib
from random import randint
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
def run():
choose=getPrime(512)
ps=gen512num()
print "gen over"
bchoose=bin(choose)[2:]
r=0
bchoose = "0"*(512-len(bchoose))+bchoose
for i in range(512):
if bchoose[i]=='1':
r=r^ps[i]
flag=open("flag","r").read()
key=long_to_bytes(int(hashlib.md5(long_to_bytes(choose)).hexdigest(),16))
aes_obj = AES.new(key, AES.MODE_ECB)
ef=aes_obj.encrypt(flag).encode("base64")
open("r", "w").write(str(r))
open("ef","w").write(ef)
gg=""
for p in ps:
gg+=str(p)+"\n"
open("ps","w").write(gg)
run()
分析题目
逐个分析一下:
先看get512num()
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
主要是生成512个数字
虽然是通过随机数生成的,但事实上这个前缀的长度是可以反算出来的,不妨试一下
f = open("ps","r")
line = f.readlines()
s=[]
for i in range(len(line)):
line[i] = int(line[i].strip('\n'))
t=line[i]
len=0
while(t%2==0):
len+=1
t=t>>1
s.append(512-len)
#s.sort() 一旦排序了就看出其中玄机了
print(s)
再看run()
def run():
choose=getPrime(512)
ps=gen512num()
print "gen over"
bchoose=bin(choose)[2:]
r=0
bchoose = "0"*(512-len(bchoose))+bchoose
for i in range(512):
if bchoose[i]=='1':
r=r^ps[i]
flag=open("flag","r").read()
key=long_to_bytes(int(hashlib.md5(long_to_bytes(choose)).hexdigest(),16))
aes_obj = AES.new(key, AES.MODE_ECB)
ef=aes_obj.encrypt(flag).encode("base64")
open("r", "w").write(str(r))
open("ef","w").write(ef)
gg=""
for p in ps:
gg+=str(p)+"\n"
open("ps","w").write(gg)
这里面就是看bchoose里面的数字,如果是1,那么r与ps异或,我们再看,key中需要choose,所以现在我们要做的很像逆向工程的事情,就是倒求出choose。
这是因为比如最后一个值为1的位,导致它值为1的可能,只有前缀长为它对应位置的那个数(因为前缀的结尾必为1)
异或这个数把这个数造成的影响消除,这样从后往前找可以再发现一个位仅受ps中的一个数的影响的情况,依次类推,就可以还原出 r 到底异或了哪些数,找到都是异或了哪些数,根据 r 的产生的方式,我们就能知道choose的哪些位是1。
f1=open("r","r")
k=int(f1.read())
m=list("0"*512) #bchoose
for i in range(511,-1,-1):
if((k>>(511-i))%2==1):
k=k^line[s.index(i+1)]
m[s.index(i+1)]= "1"
else:
m[s.index(i+1)]="0"
choose=int("0b"+"".join(m),2)
#choose=11400599473028310480620591074112690318799501642425666449519888152497765475409346201248744734864375690112798434541063767944755958258558428437088372812844657
EXP
import base64
from Crypto.Util.number import getPrime,long_to_bytes,bytes_to_long
from Crypto.Cipher import AES
import hashlib
with open("ps", "r") as f:
p=f.readlines()
s=[]
for i in range(len(p)):
x=0
a=int(p[i])
while a%2==0:
x+=1
a=a>>1
s.append(x)
#s序列表示数组中的每个数的最后有几个零
r= int(open("r","r").read())
bchoose=[0]*512
for i in range(512-1,-1,-1):
if (r>>(511-i))%2==1:
r=r^int(p[s.index(511-i)])
bchoose[s.index(511-i)]=1
else:
bchoose[s.index(511-i)]=0
choose=''
for i in bchoose:
choose+=str(i)
choose=int(choose,2)
key=long_to_bytes(int(hashlib.md5(long_to_bytes(choose)).hexdigest(),16))
aes_obj = AES.new(key, AES.MODE_ECB)
ef = open("ef","r").read().encode()
ef=base64.b64decode(ef)
flag=aes_obj.decrypt(ef)
print(flag)