CISCN-2018-Quals_Crypto_MS
k
e
y
w
o
r
d
s
:
keywords:
keywords: 有限域GF(2)下的矩阵乘法
D e s c r i p t i o n Description Description
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()
A n a l y s i s Analysis Analysis
首先介绍一个性质:
R
e
s
u
l
t
=
R
e
s
u
l
t
⊕
(
A
b
i
n
⋅
B
i
)
Result = Result \oplus (A_{bin} \cdot B_i)
Result=Result⊕(Abin⋅Bi)
其中
A
b
i
n
A_{bin}
Abin是一个数
A
A
A的各个二进制位;
B
i
B_i
Bi是一个数组的各个数值
意思就是 R e s u l t Result Result分别异或每一个 A b i n A_{bin} Abin和 B i B_i Bi的乘积
那么以上等式等价于在有限域
G
F
(
2
)
GF(2)
GF(2)上进行的矩阵乘法
M
A
⋅
M
B
=
M
R
M_A\cdot M_B = M_R
MA⋅MB=MR
其中
M
A
M_A
MA是由数值
A
A
A的各个二进制位构成的一维行向量;
M
B
M_B
MB是由数组
B
B
B得到各个数值的各个二进制位构成的二维向量(其中需要数组中数值的个数等于二进制位个数,也就是该二维向量行列长度相同);
M
R
M_R
MR即为结果
R
e
s
u
l
t
Result
Result的二进制位组成的一维行向量
例如假设 A = 5 A=5 A=5, B = [ 5 , 3 , 6 ] B = [5,3,6] B=[5,3,6];那么经计算 R e s u l t = 3 Result = 3 Result=3
等价式子:
( 1 0 1 ) ⋅ ( 1 0 1 0 1 1 1 1 0 ) = ( 0 1 1 ) \left( \begin{array}{rr} 1&0&1 \end{array} \right)\cdot \left( \begin{array}{rr} 1&0&1\\ 0&1&1\\ 1&1&0 \end{array} \right)= \left( \begin{array}{rr} 0&1&1 \end{array} \right) (101)⋅⎝⎛101011110⎠⎞=(011)
二进制转十进制 R e s u l t = 3 Result =3 Result=3,与之前的结果一致
那么本题就是运用上述性质进行求解
flag
由AES_ECB
加密,需要key
;而key
是choose
,其二进制位bchoose
构成了等价于上述性质的
A
b
i
n
A_{bin}
Abin;所以我们要找到上述性质中出现的其他参数
首先生成了由
512
512
512个数值构成的数组ps
,也就是
B
B
B
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
通过不断异或生成r
r=0
bchoose = "0"*(512-len(bchoose))+bchoose # 填充bchoose到512位二进制
for i in range(512):
if bchoose[i]=='1':
r=r^ps[i]
r
的生成过程就是等价于
r
=
r
⊕
(
B
c
h
o
o
s
e
b
i
n
⋅
P
S
i
)
r = r \oplus (Bchoose_{bin} \cdot PS_i)
r=r⊕(Bchoosebin⋅PSi)
那么由之前提到的性质,以上等式等价于在有限域
G
F
(
2
)
GF(2)
GF(2)上的矩阵乘法
M
r
=
M
b
c
h
o
o
s
e
⋅
M
p
s
M_r = M_{bchoose}\cdot M_{ps}
Mr=Mbchoose⋅Mps
需要知道
M
b
c
h
o
o
s
e
M_{bchoose}
Mbchoose;那么直接解矩阵乘法即可
M
b
c
h
o
o
s
e
=
M
r
⋅
M
p
s
−
1
M_{bchoose}=M_r\cdot M_{ps}^{-1}
Mbchoose=Mr⋅Mps−1
这样就能解到
b
c
h
o
o
s
e
bchoose
bchoose的大小,进而解出key
和flag
S o l v i n g c o d e Solving~code Solving code
import base64
from Crypto.Cipher import AES
import numpy
from Crypto.Util.number import *
import hashlib
f = open("ps","r")
ps = []
for line in f.readlines():
ps.append(int(line.strip('\n')))
# print(ps)
f.close()
f = open("r","r")
r = int(f.read())
# print(r)
f.close()
f = open("ef","r")
ef = f.read()
enc = base64.b64decode(ef)
# print(ef)
f.close()
A = []
B = []
for i in ps:
A.append([int(x) for x in bin(i)[2:].zfill(512)])
# print(A)
B=[int(x) for x in bin(r)[2:].zfill(512)]
# print(B)
A = matrix(GF(2),A)
B = matrix(GF(2),B)
Result = A.solve_left(B) # 这个函数是专门用来解矩阵乘法的,分为左乘、右乘
key = ""
# print(numpy.matrix.tolist(Result))
for i in numpy.matrix.tolist(Result)[0]:
key += str(i)
key = int(key,2)
key = long_to_bytes(int(hashlib.md5(long_to_bytes(key)).hexdigest(),16))
aes_obj = AES.new(key, AES.MODE_ECB)
print(bytes.decode(aes_obj.decrypt(enc)))