2024浙江省赛

2024浙江省赛

2024浙江省赛 哒!

预赛

myez_encode

sinqwq

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from Crypto.Util.number import bytes_to_long, getPrime
from sympy import isprime
import random
from flag import flag
def generate_ecc_parameters():
x = random.randint(1, 1 << 512)
y = random.randint(1, 1 << 512)
return x, y

def find_prime_on_curve(x, y, a, b, ecc_p):
p = x
q = y
while not (isprime(p) and isprime(q)):
p = random.randint(2, ecc_p - 1)
q = (p**3 + a * p + b) % ecc_p
return p, q

def generate_rsa_parameters():
a = getPrime(512)
b = getPrime(512)
ecc_p = getPrime(512)
x, y = generate_ecc_parameters()
p, q = find_prime_on_curve(x, y, a, b, ecc_p)
n = p * q
print(f"p= {p}\nq= {q}\nn= {n}")
print(f"a= {a}\nb= {b}")
print(f"P= {ecc_p}")

if __name__ == "__main__":
generate_rsa_parameters()

n = p*q
e = 9
m = bytes_to_long(flag)
c = pow(m,e,n)
print(c)

'''
n= 23298836191712395990541254600776262066247692725919114528027158820049802443474994576179738462067629079873633948850637889127452791527914591229415148712172587856497614285410824614070907847594399218298016379507879066220104597707859246179921731928508884947347652904142879813069359815823184922170241099916465722623
a= 7388665644223916915334064243181348811184637180763467245762518813757790945069068654378380490110607063038613823004593920489924786053478102905200169738195523
b= 11742940161647091720180482697980016011774828087234021441133595442949631197989696508358388255191793888646498553804646435609849154496274569000398776043150743
P= 11300086101709077144191286182913849072593185125745291892398153828719453495325025227858328617077648296782357912556752467026523366682963139253552060862229027
c= 9314530945343661153059846131608414257092556390479105017633636336832925597262814680689800448223193301814365726128618348603188219757245073917910487794768758461683644600756896595336654006282030911824869219015400826589122838492456940861634378619000373353637666835642505021355710338342048772713981673863167110471
'''

给出了q = (p*3 + a * p + b) % ecc_p,n=pq
设p=x,构建ecc_p上的方程解出p

1
2
3
4
5
6
7
8
9
10
n= 23298836191712395990541254600776262066247692725919114528027158820049802443474994576179738462067629079873633948850637889127452791527914591229415148712172587856497614285410824614070907847594399218298016379507879066220104597707859246179921731928508884947347652904142879813069359815823184922170241099916465722623
a= 7388665644223916915334064243181348811184637180763467245762518813757790945069068654378380490110607063038613823004593920489924786053478102905200169738195523
b= 11742940161647091720180482697980016011774828087234021441133595442949631197989696508358388255191793888646498553804646435609849154496274569000398776043150743
P= 11300086101709077144191286182913849072593185125745291892398153828719453495325025227858328617077648296782357912556752467026523366682963139253552060862229027

R=Zmod(P)['x']
x=R.gen()
f=(x**3 + a * x + b)*x-n
roots=f.roots()
print(roots)

[(2925490712948356009205547798331037409204468852265154197929696123102317330847028997592576845375767951888373634075473448002921250636926630905567362014595493, 1)]

因为GCD(e,(p-1))是3,而GCD(e,(q-1))是1,所以转换到mod q上

1
2
3
4
5
6
7
from Crypto.Util.number import *
p=2925490712948356009205547798331037409204468852265154197929696123102317330847028997592576845375767951888373634075473448002921250636926630905567362014595493
q=7964077988212602731598828926489143570796450850963162530397620970577507270219530635660167912693046701894468774510746807002256765035407708129322533385075411
e=9
d=pow(e,-1,q-1)
plain=pow(c,d,q)
print(long_to_bytes(plain))
1
DASCTF{Very_easy_3NC0dE_Is_1t}

叠叠乐

sinqwq

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from random import *
from secret import flag
from Crypto.Util.number import *

m = bytes_to_long(flag)
p = getPrime(1024)
q = getPrime(1024)
n = p * q
phi = (p - 1) * (q - 1)

while True:
try:
K, Q, P = getrandbits(900), getrandbits(50), getrandbits(40)
Y = K * Q + P
e = inverse(Y, phi)
if GCD(Y, phi) == 1:
break
except ValueError:
continue
c = pow(m,e,n)

print(f"n = {n}\ne = {e}\nc = {c}\nQP = {Q^P}")

a = getPrime(256)
b = getPrime(256)
ct = getPrime(256)
kp = K>>256<<256
kt = K - kp
hint = (a * kt + b) % ct


print(f"a = {a}\nb = {b}\nct = {ct}")
print(f"hint = {hint >> 64}")
print(f"kp = {kp}")
print(f"kt = {kt >> 64}" )

'''
n = 13303856899011983632960307882319638637287550432779792007603701106983751876258258048795658350090305467837563627318527545231628416053156415975945196818433676370277283141965954341888806103176166238312378096457083879950701541506765361840788206662319436206601457152594339944176515389512519816615898370162128798168782601890642932984764317007450016645945780381938581704042377883323192832778751432894895603847845606533248604610646973688090589505251553075107051564166403193760651488750826245412068423204034796156843765421320342265009955812200476134570302591703762798597205025078181770729074023303604132413763581028940724047053
e = 2733517162977325316168171866728796033084902904187914379488075721239142722580656245473605622483921568453860073436024032094493176750414721945725534405036772939927287999268479777085171913762833110203454301633868757808443485399661516913959111387656462439998435796234902268408475529868761969365402107153613238260226108864951738479939189489551038436191545122312333617807990694525995038168231022704371131328332275808094810800990404143404473637884482394299488230831809795888381186519555285694029266922792625447331253019632257369630552871013035628858621927646094270019889444050527156845910381295069049755746679380460434044361
c = 1257188899046514997272405325110424564385768024060742063320284255988190007584654784656431260867071493048511123353948069507669503633550848919744874511579443966819136329852114472266216895363699392703786987813179700514033350248365850450092001546491420343429207567685052543332537686663079614502304203291177287727697712338767938071399864090084866741203851028912823360536739689896262852936314757299216155671690262149783045336778852616143194149940631969143394631299410783137418636516190101007126937403728720725015452113538709754534149425438610714702079839102903881751106774919038549406459141819940733821104205463323546057321
QP = 374563570713029
a = 99122984274070362726537021378927027394007193977385990197140215753769750795421
b = 109980476177887671809918999270373802499713895541798303554775830754300928967413
ct = 107507754155219159022820175387994991690395542115681890441982942540734100538841
hint = 4003137201644984429135979790277666488437115932866581847838
kp = 7184356853939910548131241595220948851978680431483401537207787860047928595973775242115057099194568802207740239839134611884070301385515936096797317313765187937716505251256116706827496362883360670296901928436254026774384214648582578725974699293753323212294005332698430701568
kt = 2000588514863262877141025511928564790205362046489313378420
'''

题目给出了hint和kp的高192位,要求恢复K,再恢复Y,然后解RSA即可。
多元coppersmith梭了。
复现的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import itertools

def small_roots(f, bounds, m=1, d=None):
if not d:
d = f.degree()

R = f.base_ring()
N = R.cardinality()

f /= f.coefficients().pop(0)
f = f.change_ring(ZZ)

G = Sequence([], f.parent())
for i in range(m + 1):
base = N ^ (m - i) * f ^ i
for shifts in itertools.product(range(d), repeat=f.nvariables()):
g = base * prod(map(power, f.variables(), shifts))
G.append(g)

B, monomials = G.coefficient_matrix()
monomials = vector(monomials)

factors = [monomial(*bounds) for monomial in monomials]
for i, factor in enumerate(factors):
B.rescale_col(i, factor)

B = B.dense_matrix().LLL()

B = B.change_ring(QQ)
for i, factor in enumerate(factors):
B.rescale_col(i, 1 / factor)

H = Sequence([], f.parent().change_ring(QQ))
for h in filter(None, B * monomials):
H.append(h)
I = H.ideal()
if I.dimension() == -1:
H.pop()
elif I.dimension() == 0:
roots = []
for root in I.variety(ring=ZZ):
root = tuple(R(root[var]) for var in f.variables())
roots.append(root)
return roots
return []


n =
e =
c =
QP =
a =
b =
ct =
hint =
kp =
kt =
P.<x,y> = PolynomialRing(Zmod(ct))
f=a*((kt<<64)+x)+b-(hint<<64)-y
bounds=(2^64,2^64)
res = small_roots(f,bounds,m =2 ,d = 2)
print(res)

dkt=res[0][0]
dh=res[0][1]
kt=(kt<<64)+dkt
hint=(hint<<64)+dh
assert hint == (a * kt + b) % ct
K=int(kp)+int(kt)
print(K)

下一个还是多元coppersmith。
找的小鸡块的博客:Danger Leak

直接按照这个构建一下方程,解一下即可。第二个参数调错了导致我死活解不出来…
脚本:

1
2
3
4
5
R.<x,y,z> = PolynomialRing(Zmod(e*K))
f=e*x - 1 - n*y + y*z
bounds=(2^39, 2^947, 2^1025)

res = small_roots(f,bounds,m =3 ,d = 3)
1
[(944458204083, 552560007843076923398164260994159471807550408694526455233352292531945811156310842419047890332009181413495561481756007924157620126366568469123253368740622107077476645222325656305794977621972645408084023732255953798516849162998553825344237466120566386612181335521132040599181606274560641, 235681768835910777712622269457346978821121797522206608887974456212118979486411195712467848203727919845155536551605550715865106258897298449186222892938047506561981718836263182343343122200026888924819782172663699192899753711204849338725765643146319190364107913200366351844540910550001346645855729485732602826765)]

最后算一下Y,解个RSA即可

1
2
3
4
5
6
7
from Crypto.Util.number import *
P=int(res[0][0])
Q=QP^^P
Y=K*Q+P
plain=int(pow(c,Y,n))
print(long_to_bytes(plain))
#b'DASCTF{6a4ba557-4fe7-4874-8dad-40e880cb7717}'

SNOW

task.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from sourcecode.secret import flag
from snow import *
import random

key = [random.getrandbits(32) for _ in range(4)]
iv = [random.getrandbits(32) for _ in range(4)]

s = Snow(key,iv)


gift = b"the quick brown fox jumps over the lazy dog\n"
plain = gift + flag

key_stream = s.generate_keystream(len(plain))
C = [i^j for i,j in zip(plain,key_stream)]
print(C)
s.hack()

# [3539094009, 980211684, 2198891016, 905998740, 1595475160, 3962636204, 1199994505, 3190370623, 296595869, 3158272345, 2748985736, 382671580, 2521428409, 248078233, 1528783547, 2729100548, 3426466722, 3192873770, 1337295957, 1431041587, 1607853207, 3998694569, 3160389002, 3728077354, 1120982789, 3443900372, 1811224296, 3102761228, 3296566547, 3724398326, 873334127, 3279785283, 1267844209, 907638672, 2121413959, 3173567371, 4097722407, 844863077, 3114817962, 3619759560, 2198708209, 2363435526, 196774438, 2671749579, 4031688923, 471349633, 778676959, 3608967403, 92491149, 913291948, 3021362116, 1067932129, 999259588, 3190588842, 1828097126, 1450255462, 1305572961, 1341694028, 2350778224, 2932388574, 1204050979, 1294999174, 1921124090, 2342994011, 1941020673, 1191919176, 187588176, 255691701, 274795123, 873091533, 299848364, 870697920, 3387594780, 944072831, 848477078, 447469593, 917439649, 598555627, 3036173079, 3758185777, 4236584984, 4205933999, 1185586113, 3227810954, 2737102694, 3680871868, 4102277292, 378037705]
# 834501734,940247165,2078728259,483907438,1102712410,3110955761,3016462560,871310805,1334672645,1102778698

snow.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import numpy as np



# 定义 S-box
sr = np.array([
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
], dtype=np.uint8)

sq = np.array([
0x25, 0x24, 0x73, 0x67, 0xd7, 0xae, 0x5c, 0x30, 0xa4, 0xee, 0x6e, 0xcb, 0x7d, 0xb5, 0x82, 0xdb,
0xe4, 0x8e, 0x48, 0x49, 0x4f, 0x5d, 0x6a, 0x78, 0x70, 0x88, 0xe8, 0x5f, 0x5e, 0x84, 0x65, 0xe2,
0xd8, 0xe9, 0xcc, 0xed, 0x40, 0x2f, 0x11, 0x28, 0x57, 0xd2, 0xac, 0xe3, 0x4a, 0x15, 0x1b, 0xb9,
0xb2, 0x80, 0x85, 0xa6, 0x2e, 0x02, 0x47, 0x29, 0x07, 0x4b, 0x0e, 0xc1, 0x51, 0xaa, 0x89, 0xd4,
0xca, 0x01, 0x46, 0xb3, 0xef, 0xdd, 0x44, 0x7b, 0xc2, 0x7f, 0xbe, 0xc3, 0x9f, 0x20, 0x4c, 0x64,
0x83, 0xa2, 0x68, 0x42, 0x13, 0xb4, 0x41, 0xcd, 0xba, 0xc6, 0xbb, 0x6d, 0x4d, 0x71, 0x21, 0xf4,
0x8d, 0xb0, 0xe5, 0x93, 0xfe, 0x8f, 0xe6, 0xcf, 0x43, 0x45, 0x31, 0x22, 0x37, 0x36, 0x96, 0xfa,
0xbc, 0x0f, 0x08, 0x52, 0x1d, 0x55, 0x1a, 0xc5, 0x4e, 0x23, 0x69, 0x7a, 0x92, 0xff, 0x5b, 0x5a,
0xeb, 0x9a, 0x1c, 0xa9, 0xd1, 0x7e, 0x0d, 0xfc, 0x50, 0x8a, 0xb6, 0x62, 0xf5, 0x0a, 0xf8, 0xdc,
0x03, 0x3c, 0x0c, 0x39, 0xf1, 0xb8, 0xf3, 0x3d, 0xf2, 0xd5, 0x97, 0x66, 0x81, 0x32, 0xa0, 0x00,
0x06, 0xce, 0xf6, 0xea, 0xb7, 0x17, 0xf7, 0x8c, 0x79, 0xd6, 0xa7, 0xbf, 0x8b, 0x3f, 0x1f, 0x53,
0x63, 0x75, 0x35, 0x2c, 0x60, 0xfd, 0x27, 0xd3, 0x94, 0xa5, 0x7c, 0xa1, 0x05, 0x58, 0x2d, 0xbd,
0xd9, 0xc7, 0xaf, 0x6b, 0x54, 0x0b, 0xe0, 0x38, 0x04, 0xc8, 0x9d, 0xe7, 0x14, 0xb1, 0x87, 0x9c,
0xdf, 0x6f, 0xf9, 0xda, 0x2a, 0xc4, 0x59, 0x16, 0x74, 0x91, 0xab, 0x26, 0x61, 0x76, 0x34, 0x2b,
0xad, 0x99, 0xfb, 0x72, 0xec, 0x33, 0x12, 0xde, 0x98, 0x3b, 0xc0, 0x9b, 0x3e, 0x18, 0x10, 0x3a,
0x56, 0xe1, 0x77, 0xc9, 0x1e, 0x9e, 0x95, 0xa3, 0x90, 0x19, 0xa8, 0x6c, 0x09, 0xd0, 0xf0, 0x86
], dtype=np.uint8)

class Snow:
def __init__(self, k, iv):
self.lfsr = np.zeros(16, dtype=np.uint32)
self.fsm = np.zeros(3, dtype=np.uint32)
self.initialize(k, iv)
self.S =[]
self.R1 = []
self.R2 = []
self.R3 = []


def mulx(self, V, c):
if V & 0x80:
return (V << 1) ^ c
else:
return V << 1

def mulx_pow(self, V, i, c):
if i == 0:
return V
else:
return self.mulx(self.mulx_pow(V, i - 1, c), c)

def s1(self, w):
w0 = (w >> 24) & 0xff
w1 = (w >> 16) & 0xff
w2 = (w >> 8) & 0xff
w3 = w & 0xff

r0 = (self.mulx(sr[w0], 0x1b) ^ sr[w1] ^ sr[w2] ^ self.mulx(sr[w3], 0x1b) ^ sr[w3]) & 0xff
r1 = (self.mulx(sr[w0], 0x1b) ^ sr[w0] ^ self.mulx(sr[w1], 0x1b) ^ sr[w2] ^ sr[w3]) & 0xff
r2 = (sr[w0] ^ self.mulx(sr[w1], 0x1b) ^ sr[w1] ^ self.mulx(sr[w2], 0x1b) ^ sr[w3]) & 0xff
r3 = (sr[w0] ^ sr[w1] ^ self.mulx(sr[w2], 0x1b) ^ sr[w2] ^ self.mulx(sr[w3], 0x1b)) & 0xff

return (r0 << 24) | (r1 << 16) | (r2 << 8) | r3

def s2(self, w):
w0 = (w >> 24) & 0xff
w1 = (w >> 16) & 0xff
w2 = (w >> 8) & 0xff
w3 = w & 0xff

r0 = (self.mulx(sq[w0], 0x69) ^ sq[w1] ^ sq[w2] ^ self.mulx(sq[w3], 0x69) ^ sq[w3]) & 0xff
r1 = (self.mulx(sq[w0], 0x69) ^ sq[w0] ^ self.mulx(sq[w1], 0x69) ^ sq[w2] ^ sq[w3]) & 0xff
r2 = (sq[w0] ^ self.mulx(sq[w1], 0x69) ^ sq[w1] ^ self.mulx(sq[w2], 0x69) ^ sq[w3]) & 0xff
r3 = (sq[w0] ^ sq[w1] ^ self.mulx(sq[w2], 0x69) ^ sq[w2] ^ self.mulx(sq[w3], 0x69)) & 0xff
return (r0 << 24) | (r1 << 16) | (r2 << 8) | r3

def mul_alpha(self, c):
r0 = self.mulx_pow(c, 23, 0xa9) & 0xff
r1 = self.mulx_pow(c, 245, 0xa9) & 0xff
r2 = self.mulx_pow(c, 48, 0xa9) & 0xff
r3 = self.mulx_pow(c, 239, 0xa9) & 0xff
return (r0 << 24) | (r1 << 16) | (r2 << 8) | r3

def div_alpha(self, c):
r0 = self.mulx_pow(c, 16, 0xa9) & 0xff
r1 = self.mulx_pow(c, 39, 0xa9) & 0xff
r2 = self.mulx_pow(c, 6, 0xa9) & 0xff
r3 = self.mulx_pow(c, 64, 0xa9) & 0xff
return (r0 << 24) | (r1 << 16) | (r2 << 8) | r3

def lfsr_initialization_mode(self, F):
v = (self.lfsr[0] << 8) ^ self.mul_alpha((self.lfsr[0] >> 24) & 0xff) ^ self.lfsr[2] ^ (self.lfsr[11] >> 8) ^ \
self.div_alpha(self.lfsr[11] & 0xff) ^ F
for i in range(15):
self.lfsr[i] = self.lfsr[i + 1]
self.lfsr[15] = v

def lfsr_keystream_mode(self):
v = (self.lfsr[0] << 8) ^ self.mul_alpha((self.lfsr[0] >> 24) & 0xff) ^ self.lfsr[2] ^ (self.lfsr[11] >> 8) ^ \
self.div_alpha(self.lfsr[11] & 0xff)
for i in range(15):
self.lfsr[i] = self.lfsr[i + 1]
self.lfsr[15] = v


def clock_fsm(self, s15, s5):
F = (s15 + self.fsm[0]) ^ self.fsm[1]
r = self.fsm[1] + (self.fsm[2] ^ s5)
self.fsm[2] = self.s2(self.fsm[1])
self.fsm[1] = self.s1(self.fsm[0])
self.fsm[0] = r
return F

def initialize(self, k, iv):
self.lfsr[0] = k[0] ^ 0xffffffff
self.lfsr[1] = k[1] ^ 0xffffffff
self.lfsr[2] = k[2] ^ 0xffffffff
self.lfsr[3] = k[3] ^ 0xffffffff
self.lfsr[4] = k[0]
self.lfsr[5] = k[1]
self.lfsr[6] = k[2]
self.lfsr[7] = k[3]
self.lfsr[8] = k[0] ^ 0xffffffff
self.lfsr[9] = k[1] ^ 0xffffffff ^ iv[3]
self.lfsr[10] = k[2] ^ 0xffffffff ^ iv[2]
self.lfsr[11] = k[3] ^ 0xffffffff
self.lfsr[12] = k[0] ^ iv[1]
self.lfsr[13] = k[1]
self.lfsr[14] = k[2]
self.lfsr[15] = k[3] ^ iv[0]

for i in range(3):
self.fsm[i] = 0

for i in range(32):
F = self.clock_fsm(self.lfsr[15], self.lfsr[5])
self.lfsr_initialization_mode(F)

def generate_keystream(self, n):
keystream = np.zeros(n, dtype=np.uint32)
self.clock_fsm(self.lfsr[15], self.lfsr[5])
self.lfsr_keystream_mode()
self.R1.append(self.fsm[0])
self.R2.append(self.fsm[1])
self.R3.append(self.fsm[2])

for i in range(n):
F = self.clock_fsm(self.lfsr[15], self.lfsr[5])
self.R1.append(self.fsm[0])
self.R2.append(self.fsm[1])
self.R3.append(self.fsm[2])
self.S.append(self.lfsr[0])
keystream[i] = F ^ self.lfsr[0]
self.lfsr_keystream_mode()
return keystream

def hack(self):
print(self.R1[2],self.R2[2],self.R3[2],self.S[2],self.S[3],self.S[6],self.S[7],self.S[8],self.R1[5],self.R1[7],sep=",")

我自己在本地跑的时候是需要稍微改一下源码的,不然数据有问题。
得把s1和s2改一下,因为sr和sq是int8的,在return的时候会把那个值也转成int8的,只会得到低8位的值,但题目给出的数据明显不是这样的,所以加点int就好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def s1(self, w):
w0 = (w >> 24) & 0xff
w1 = (w >> 16) & 0xff
w2 = (w >> 8) & 0xff
w3 = w & 0xff

r0 = (self.mulx(sr[w0], 0x1b) ^ sr[w1] ^ sr[w2] ^ self.mulx(sr[w3], 0x1b) ^ sr[w3]) & 0xff
r1 = (self.mulx(sr[w0], 0x1b) ^ sr[w0] ^ self.mulx(sr[w1], 0x1b) ^ sr[w2] ^ sr[w3]) & 0xff
r2 = (sr[w0] ^ self.mulx(sr[w1], 0x1b) ^ sr[w1] ^ self.mulx(sr[w2], 0x1b) ^ sr[w3]) & 0xff
r3 = (sr[w0] ^ sr[w1] ^ self.mulx(sr[w2], 0x1b) ^ sr[w2] ^ self.mulx(sr[w3], 0x1b)) & 0xff

return (int(r0) << 24) | (int(r1) << 16) | (int(r2) << 8) | r3

def s2(self, w):
w0 = (w >> 24) & 0xff
w1 = (w >> 16) & 0xff
w2 = (w >> 8) & 0xff
w3 = w & 0xff

r0 = (self.mulx(sq[w0], 0x69) ^ sq[w1] ^ sq[w2] ^ self.mulx(sq[w3], 0x69) ^ sq[w3]) & 0xff
r1 = (self.mulx(sq[w0], 0x69) ^ sq[w0] ^ self.mulx(sq[w1], 0x69) ^ sq[w2] ^ sq[w3]) & 0xff
r2 = (sq[w0] ^ self.mulx(sq[w1], 0x69) ^ sq[w1] ^ self.mulx(sq[w2], 0x69) ^ sq[w3]) & 0xff
r3 = (sq[w0] ^ sq[w1] ^ self.mulx(sq[w2], 0x69) ^ sq[w2] ^ self.mulx(sq[w3], 0x69)) & 0xff
return (int(r0) << 24) | (int(r1) << 16) | (int(r2) << 8) | r3

先说一下大致的思路,这题我们要拿到flag就要拿到key_stream,而key_stream是由F和lfsr推出来的,F又是由fsm和lfsr推出来的,也就是说我们需要还原fsm和lfsr。所以我们需要去关注一下这两个的推导公式。
lfsr:

1
2
3
4
5
6
def lfsr_keystream_mode(self):
v = (self.lfsr[0] << 8) ^ self.mul_alpha((self.lfsr[0] >> 24) & 0xff) ^ self.lfsr[2] ^ (self.lfsr[11] >> 8) ^ \
self.div_alpha(self.lfsr[11] & 0xff)
for i in range(15):
self.lfsr[i] = self.lfsr[i + 1]
self.lfsr[15] = v

这是一个长15的lfsr,也就是说还原出任意连续15个值,我们就能还原出整个lfsr序列。
fsm:

1
2
3
4
5
6
7
def clock_fsm(self, s15, s5):
F = (s15 + self.fsm[0]) ^ self.fsm[1]
r = self.fsm[1] + (self.fsm[2] ^ s5)
self.fsm[2] = self.s2(self.fsm[1])
self.fsm[1] = self.s1(self.fsm[0])
self.fsm[0] = r
return F

下一轮的fsm由上一轮的fsm和lfsr共同决定。
综上,我们只需要获得连续15个lfsr和这15个对应的最开始的fsm就能还原后面的所有数据。
这是我复现时手动还原的思路,实际上只需要不断地检查能否推出新的值就可以了。不用管这些有的没的
首先正向推下一个数据就不用多说了,源码里都有,直接给你们贴出来了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
def mulx(V, c):
if V & 0x80:
return (V << 1) ^ c
else:
return V << 1

def mulx_pow(V, i, c):
if i == 0:
return V
else:
return mulx(mulx_pow(V, i - 1, c), c)

def mul_alpha(c):
r0 = mulx_pow(c, 23, 0xa9) & 0xff
r1 = mulx_pow(c, 245, 0xa9) & 0xff
r2 = mulx_pow(c, 48, 0xa9) & 0xff
r3 = mulx_pow(c, 239, 0xa9) & 0xff
return (r0 << 24) | (r1 << 16) | (r2 << 8) | r3

def div_alpha(c):
r0 = mulx_pow(c, 16, 0xa9) & 0xff
r1 = mulx_pow(c, 39, 0xa9) & 0xff
r2 = mulx_pow(c, 6, 0xa9) & 0xff
r3 = mulx_pow(c, 64, 0xa9) & 0xff
return (r0 << 24) | (r1 << 16) | (r2 << 8) | r3

def s1(w):
w0 = (w >> 24) & 0xff
w1 = (w >> 16) & 0xff
w2 = (w >> 8) & 0xff
w3 = w & 0xff

r0 = (mulx(sr[w0], 0x1b) ^ sr[w1] ^ sr[w2] ^ mulx(sr[w3], 0x1b) ^ sr[w3]) & 0xff
r1 = (mulx(sr[w0], 0x1b) ^ sr[w0] ^ mulx(sr[w1], 0x1b) ^ sr[w2] ^ sr[w3]) & 0xff
r2 = (sr[w0] ^ mulx(sr[w1], 0x1b) ^ sr[w1] ^ mulx(sr[w2], 0x1b) ^ sr[w3]) & 0xff
r3 = (sr[w0] ^ sr[w1] ^ mulx(sr[w2], 0x1b) ^ sr[w2] ^ mulx(sr[w3], 0x1b)) & 0xff

return (int(r0) << 24) | (int(r1) << 16) | (int(r2) << 8) | int(r3)

def s2(w):
w0 = (w >> 24) & 0xff
w1 = (w >> 16) & 0xff
w2 = (w >> 8) & 0xff
w3 = w & 0xff

r0 = (mulx(sq[w0], 0x69) ^ sq[w1] ^ sq[w2] ^ mulx(sq[w3], 0x69) ^ sq[w3]) & 0xff
r1 = (mulx(sq[w0], 0x69) ^ sq[w0] ^ mulx(sq[w1], 0x69) ^ sq[w2] ^ sq[w3]) & 0xff
r2 = (sq[w0] ^ mulx(sq[w1], 0x69) ^ sq[w1] ^ mulx(sq[w2], 0x69) ^ sq[w3]) & 0xff
r3 = (sq[w0] ^ sq[w1] ^ mulx(sq[w2], 0x69) ^ sq[w2] ^ mulx(sq[w3], 0x69)) & 0xff
return (int(r0) << 24) | (int(r1) << 16) | (int(r2) << 8) | int(r3)

def clock_fsm(s15, s5):
F = (s15 + fsm[0]) ^ fsm[1]
r = fsm[1] + (fsm[2] ^ s5)
fsm[2] = s2(fsm[1])
fsm[1] = s1(fsm[0])
fsm[0] = r
return F

def lfsr_keystream_mode(S0,S2,S11):
v = (S0 << 8) ^ mul_alpha((S0 >> 24) & 0xff) ^ S2 ^ (S11 >> 8) ^ \
div_alpha(S11 & 0xff)
return v

之后我们就需要来通过下一个值来反推上一个值了。我是用的z3来解的。
对于s1,s2,函数内部是有对sr,sq的切片的,并且sr,sq里面每一个值都是唯一的,所以我们直接把这4个切片的值设为未知数,解出来后直接在sr,sq里找对应的索引即可。
同时我们需要重新定义一下mulx(AI是说是算术右移和逻辑右移的原因,实际解是需要重新定义的),直接就在函数里面临时定义了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def de_s1(s):
r0=(s>>24)&0xff
r1=(s>>16)&0xff
r2=(s>>8)&0xff
r3=s&0xff

def mulx(V, c):
return (V << 1) ^ (c*LShR(V, 7))& 0xff
solver=Solver()
srw0,srw1,srw2,srw3=BitVecs('srw0 srw1 srw2 srw3', 8)
solver.add(r0 == (mulx(srw0, 0x1b) ^ srw1 ^ srw2 ^mulx(srw3, 0x1b) ^ srw3) & 0xff)
solver.add(r1 == (mulx(srw0, 0x1b) ^ srw0 ^ mulx(srw1, 0x1b) ^ srw2 ^ srw3) & 0xff)
solver.add(r2 == (srw0 ^ mulx(srw1, 0x1b) ^ srw1 ^ mulx(srw2, 0x1b) ^ srw3) & 0xff)
solver.add(r3 == (srw0 ^ srw1 ^ mulx(srw2, 0x1b) ^ srw2 ^ mulx(srw3, 0x1b)) & 0xff)

if solver.check()==sat:
res=solver.model()
__sr=sr.tolist()
w0=__sr.index(res[srw0].py_value())
w1=__sr.index(res[srw1].py_value())
w2=__sr.index(res[srw2].py_value())
w3=__sr.index(res[srw3].py_value())
return (w0 << 24) | (w1 << 16) | (w2 << 8) | w3
else:
return False
def de_s2(s):
r0=(s>>24)&0xff
r1=(s>>16)&0xff
r2=(s>>8)&0xff
r3=s&0xff

def mulx(V, c):
return (V << 1) ^ (c*LShR(V, 7))& 0xff
solver=Solver()
sqw0,sqw1,sqw2,sqw3=BitVecs('sqw0 sqw1 sqw2 sqw3', 8)
solver.add(r0 == (mulx(sqw0, 0x69) ^ sqw1 ^ sqw2 ^mulx(sqw3, 0x69) ^ sqw3) & 0xff)
solver.add(r1 == (mulx(sqw0, 0x69) ^ sqw0 ^ mulx(sqw1, 0x69) ^ sqw2 ^ sqw3) & 0xff)
solver.add(r2 == (sqw0 ^ mulx(sqw1, 0x69) ^ sqw1 ^ mulx(sqw2, 0x69) ^ sqw3) & 0xff)
solver.add(r3 == (sqw0 ^ sqw1 ^ mulx(sqw2, 0x69) ^ sqw2 ^ mulx(sqw3, 0x69)) & 0xff)

if solver.check()==sat:
res=solver.model()
__sq=sq.tolist()
w0=__sq.index(res[sqw0].py_value())
w1=__sq.index(res[sqw1].py_value())
w2=__sq.index(res[sqw2].py_value())
w3=__sq.index(res[sqw3].py_value())
return (w0 << 24) | (w1 << 16) | (w2 << 8) | w3
else:
return False

题目中我们可以看到lfsr的值都被添加进S中了,所以可以认为S序列包含了lfsr的各个状态的值(可能最开始的没有,但不重要)。
接下来就是对lfsr_keystream_mode的逆向了。lfsr是由前面的3个值来推出下一个值的,也就是说我们需要3个值,剩下的值才能被确定。我同样采取解方程的方式来求解其中任意一个值。但我在实际求解的时候发现S11的值大部分情况求解不对,暂时也不知道是什么的问题。但在最后只需要稍微改动一下就可以避免去用de_lfsr_keystream_mode来求解S11,S11还可以由别的数据来确定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def de_lfsr_keystream_mode(S0, S2, S11, S16):
if S0 == '':
S0 = BitVec('S0', 32)
else:
S0 = np.uint32(S0)
if S2 == '':
S2 = BitVec('S2', 32)
else:
S2 = np.uint32(S2)
if S11 == '':
S11 = BitVec('S11', 32)
else:
S11 = np.uint32(S11)
if S16 == '':
S16 = BitVec('S16', 32)
else:
S16 = np.uint32(S16)

solver = Solver()
solver.add(S16 == lfsr_keystream_mode(S0, S2, S11))

if solver.check() == sat:
res = solver.model()
if isinstance(S0, BitVecRef):
return res[S0].as_long()
if isinstance(S2, BitVecRef):
return res[S2].as_long()
if isinstance(S11, BitVecRef):
return res[S11].as_long()
if isinstance(S16, BitVecRef):
return res[S16].as_long()
else:
return False

写完了这三个函数的逆向求解的函数,我们来理一下fsm,lfsr,S,F,key_stream之间的关系。
前面我们提到lfsr的值都被添加进了S,所以可以用S来代替lfsr序列,大致是如下的对应关系。

所以接下来我就用S[i+k]来表示第i+1轮第k+1个lfsr的值,以S[0+0]为第1轮第1个lfsr的值。
然后是fsm,fsm的值的推导是在clock_fsm中,在generate_keystream里调用完clock_fsm函数后,R1,R2,R3添加的是第i+2轮的fsm的值,而S添加的是第i+1轮第一个lfsr的值,return的F是第i+1轮的fsm,lfsr的值得出的。但在for循环之前R1,R2,R3先append了一轮,所以每次for循环就类似于下面这种情况:

所以接下来我用fsm[i][k]来表示第i+1R(k+1)的值,以fsm[0][0]为第1轮R1的值,也就是R1[0]
那么,各个数据之间的关系就是:

1
2
3
4
F[i]是S[i+15],fsm[i][0],fsm[i][1]得出的
fsm[i+1][2]是fsm[i][1]得出的
fsm[i+1][1]是fsm[i][0]得出的
fsm[i+1][0]是fsm[i][1],fsm[i][2],S[i+5]得出的

请牢记这些关系,等下会经常用到。

我在初始化key_stream,fsm,S,F的时候是用的空字符串来初始化,因为它能在我尝试用未知的值来推别的值时报错,来让我更好的发现错误。

1
2
3
4
key_stream=['']*150
fsm=[['']*3 for i in range(150)]
S=['']*150
F=['']*150

接下来我们来写check函数,顾名思义,就是检查能否推出别的值。
首先是S序列,我们可以由任意三个值推出剩下的一个值。所以我们要的数据就是S[i],S[i+2],S[i+11],S[i+15+1](lfsr序列推出的下一个值是赋S[i+15+1]的,而不是S[i+15],不懂的再想一下)。
checkS:

1
2
3
4
5
6
7
8
9
10
11
12
13
#检查S序列能否向后推导或者推出前面的某一个值
def checkS():
flag=False#标记是否有check出新的值
for i in range(len(S)-16):
__l=[type(S[i]),type(S[i+2]),type(S[i+11]),type(S[i+15+1])]
if __l.count(int)==3:
flag=True
if __l.index(str)==3:
S[i+15+1]=int(lfsr_keystream_mode(np.uint32(S[i+0]),np.uint32(S[i+2]),np.uint32(S[i+11])))
else:
__index=[i,i+2,i+11,i+15+1]
S[__index[__l.index(str)]]=de_lfsr_keystream_mode(S[i],S[i+2],S[i+11],S[i+15+1])
return flag

再提一下,我的de_lfsr_keystream_mode并不能很好的解S[i+11]是未知数的情况,如果你发现了我的de_lfsr_keystream_mode的错误请和我说一下。我们最后只需要更改一下checkS的调用顺序就能避免这种情况,很神奇。

然后是fsm序列的向前逆向推导和向后推导,对于fsm[i][0],只要知道其中任意三个值就可以推出剩下的一个值。
checkFSM:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#检查fsm能否向前或向后推导
def checkFSM():
flag=False
for i in range(len(fsm)-5):
if type(fsm[i][1])==int and type(fsm[i+1][2])!=int:#fsm[i][1] -s2-> fsm[i+1][2]
fsm[i+1][2]=int(s2(fsm[i][1]))
flag=True
if type(fsm[i][0])==int and type(fsm[i+1][1])!=int:#fsm[i][0] -s1-> fsm[i+1][1]
fsm[i+1][1]=int(s1(fsm[i][0]))
flag=True
if type(fsm[i][1])!=int and type(fsm[i+1][2])==int:#fsm[i][1] -de_s2-> fsm[i+1][2]
fsm[i][1]=de_s2(fsm[i+1][2])
flag=True
if type(fsm[i][0])!=int and type(fsm[i+1][1])==int:#fsm[i][0] -de_s1-> fsm[i+1][1]
fsm[i][0]=de_s1(fsm[i+1][1])
flag=True
#对于fsm[i][0],只要知道其中任意三个值就可以推出剩下的一个值,所以顺带都写在这了
__l=[type(fsm[i][1]),type(fsm[i][2]),type(S[i+5]),type(fsm[i+1][0])]
if __l.count(int)==3:
flag=True
__=__l.index(str)
if __==0:
fsm[i][1]=(fsm[i+1][0]-(fsm[i][2]^S[i+5]))%2**32
elif __==1:
fsm[i][2]=((fsm[i+1][0]-fsm[i][1])^S[i+5])%2**32
elif __==2:
S[i+5]=((fsm[i+1][0]-fsm[i][1])^fsm[i][2])%2**32
elif __==3:
fsm[i+1][0]=(fsm[i][1]+(fsm[i][2]^S[i+5]))%2**32
return flag

在clock_fsm中还有对F的赋值,我们也可以由任意3个值推出剩下的
checkFSFSM:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#检查clock_fsm里面的F的推导,只要知道其中任意三个值就可以推出剩下的一个值
def checkFSFSM():
flag=False
for i in range(len(S)-15):
__l=[type(fsm[i][0]),type(fsm[i][1]),type(F[i]),type(S[i+15])]
if __l.count(int)==3:
flag=True
__=__l.index(str)
if __==0:
fsm[i][0]=((F[i]^fsm[i][1])-S[i+15])%2**32
elif __==1:
fsm[i][1]=(F[i]^(S[i+15]+fsm[i][0]))%2**32
elif __==2:
F[i]=((S[i+15]+fsm[i][0])^fsm[i][1])%2**32
elif __==3:
S[i+15]=((F[i]^fsm[i][1])-fsm[i][0])%2**32
return flag

最后就是key_stream了,知道key_stream,F,S(也就是lfsr)任意2个可以推出剩下的一个
checkFSSTREAM:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#检查F,S,key_stream的互相之间的推导,知道任意2个可以推出剩下的一个
def checkFSSTREAM():
flag=False
for i in range(len(key_stream)):
__l=[type(key_stream[i]),type(F[i]),type(S[i])]
if __l.count(int)==2:
flag=True
__=__l.index(str)
if __==0:
key_stream[i]=F[i]^S[i]
elif __==1:
F[i]=key_stream[i]^S[i]
elif __==2:
S[i]=key_stream[i]^F[i]
return flag

最后把这些函数全丢进一个函数里调用就好了,我本地调试时加了一个checkCORRECT来检验正确性。
因为我de_lfsr_keystream_mode的问题,所以把checkS尽量在后面调用。
checkALL():

1
2
3
4
5
6
7
def checkALL():
flag=checkFSM()
flag=flag or checkFSFSM()
flag=flag or checkFSSTREAM()
flag=flag or checkS()
checkCORRECT()
return flag

只需要不断调用checkALL直到返回值是False即可。
exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
import numpy as np
from z3 import *
from Crypto.Util.number import *

# 定义 S-box
sr = np.array([
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
], dtype=np.uint8)

sq = np.array([
0x25, 0x24, 0x73, 0x67, 0xd7, 0xae, 0x5c, 0x30, 0xa4, 0xee, 0x6e, 0xcb, 0x7d, 0xb5, 0x82, 0xdb,
0xe4, 0x8e, 0x48, 0x49, 0x4f, 0x5d, 0x6a, 0x78, 0x70, 0x88, 0xe8, 0x5f, 0x5e, 0x84, 0x65, 0xe2,
0xd8, 0xe9, 0xcc, 0xed, 0x40, 0x2f, 0x11, 0x28, 0x57, 0xd2, 0xac, 0xe3, 0x4a, 0x15, 0x1b, 0xb9,
0xb2, 0x80, 0x85, 0xa6, 0x2e, 0x02, 0x47, 0x29, 0x07, 0x4b, 0x0e, 0xc1, 0x51, 0xaa, 0x89, 0xd4,
0xca, 0x01, 0x46, 0xb3, 0xef, 0xdd, 0x44, 0x7b, 0xc2, 0x7f, 0xbe, 0xc3, 0x9f, 0x20, 0x4c, 0x64,
0x83, 0xa2, 0x68, 0x42, 0x13, 0xb4, 0x41, 0xcd, 0xba, 0xc6, 0xbb, 0x6d, 0x4d, 0x71, 0x21, 0xf4,
0x8d, 0xb0, 0xe5, 0x93, 0xfe, 0x8f, 0xe6, 0xcf, 0x43, 0x45, 0x31, 0x22, 0x37, 0x36, 0x96, 0xfa,
0xbc, 0x0f, 0x08, 0x52, 0x1d, 0x55, 0x1a, 0xc5, 0x4e, 0x23, 0x69, 0x7a, 0x92, 0xff, 0x5b, 0x5a,
0xeb, 0x9a, 0x1c, 0xa9, 0xd1, 0x7e, 0x0d, 0xfc, 0x50, 0x8a, 0xb6, 0x62, 0xf5, 0x0a, 0xf8, 0xdc,
0x03, 0x3c, 0x0c, 0x39, 0xf1, 0xb8, 0xf3, 0x3d, 0xf2, 0xd5, 0x97, 0x66, 0x81, 0x32, 0xa0, 0x00,
0x06, 0xce, 0xf6, 0xea, 0xb7, 0x17, 0xf7, 0x8c, 0x79, 0xd6, 0xa7, 0xbf, 0x8b, 0x3f, 0x1f, 0x53,
0x63, 0x75, 0x35, 0x2c, 0x60, 0xfd, 0x27, 0xd3, 0x94, 0xa5, 0x7c, 0xa1, 0x05, 0x58, 0x2d, 0xbd,
0xd9, 0xc7, 0xaf, 0x6b, 0x54, 0x0b, 0xe0, 0x38, 0x04, 0xc8, 0x9d, 0xe7, 0x14, 0xb1, 0x87, 0x9c,
0xdf, 0x6f, 0xf9, 0xda, 0x2a, 0xc4, 0x59, 0x16, 0x74, 0x91, 0xab, 0x26, 0x61, 0x76, 0x34, 0x2b,
0xad, 0x99, 0xfb, 0x72, 0xec, 0x33, 0x12, 0xde, 0x98, 0x3b, 0xc0, 0x9b, 0x3e, 0x18, 0x10, 0x3a,
0x56, 0xe1, 0x77, 0xc9, 0x1e, 0x9e, 0x95, 0xa3, 0x90, 0x19, 0xa8, 0x6c, 0x09, 0xd0, 0xf0, 0x86
], dtype=np.uint8)

def mulx(V, c):
return (V << 1) ^ (c*((V&0x80)>>7))
def mulx_pow(V, i, c):
if i == 0:
return V
else:
return mulx(mulx_pow(V, i - 1, c), c)

def mul_alpha(c):
r0 = mulx_pow(c, 23, 0xa9) & 0xff
r1 = mulx_pow(c, 245, 0xa9) & 0xff
r2 = mulx_pow(c, 48, 0xa9) & 0xff
r3 = mulx_pow(c, 239, 0xa9) & 0xff
return (r0 << 24) | (r1 << 16) | (r2 << 8) | r3

def div_alpha(c):
r0 = mulx_pow(c, 16, 0xa9) & 0xff
r1 = mulx_pow(c, 39, 0xa9) & 0xff
r2 = mulx_pow(c, 6, 0xa9) & 0xff
r3 = mulx_pow(c, 64, 0xa9) & 0xff
return (r0 << 24) | (r1 << 16) | (r2 << 8) | r3

def s1(w):
w0 = (w >> 24) & 0xff
w1 = (w >> 16) & 0xff
w2 = (w >> 8) & 0xff
w3 = w & 0xff

r0 = (mulx(sr[w0], 0x1b) ^ sr[w1] ^ sr[w2] ^ mulx(sr[w3], 0x1b) ^ sr[w3]) & 0xff
r1 = (mulx(sr[w0], 0x1b) ^ sr[w0] ^ mulx(sr[w1], 0x1b) ^ sr[w2] ^ sr[w3]) & 0xff
r2 = (sr[w0] ^ mulx(sr[w1], 0x1b) ^ sr[w1] ^ mulx(sr[w2], 0x1b) ^ sr[w3]) & 0xff
r3 = (sr[w0] ^ sr[w1] ^ mulx(sr[w2], 0x1b) ^ sr[w2] ^ mulx(sr[w3], 0x1b)) & 0xff

return (int(r0) << 24) | (int(r1) << 16) | (int(r2) << 8) | int(r3)

def s2(w):
w0 = (w >> 24) & 0xff
w1 = (w >> 16) & 0xff
w2 = (w >> 8) & 0xff
w3 = w & 0xff

r0 = (mulx(sq[w0], 0x69) ^ sq[w1] ^ sq[w2] ^ mulx(sq[w3], 0x69) ^ sq[w3]) & 0xff
r1 = (mulx(sq[w0], 0x69) ^ sq[w0] ^ mulx(sq[w1], 0x69) ^ sq[w2] ^ sq[w3]) & 0xff
r2 = (sq[w0] ^ mulx(sq[w1], 0x69) ^ sq[w1] ^ mulx(sq[w2], 0x69) ^ sq[w3]) & 0xff
r3 = (sq[w0] ^ sq[w1] ^ mulx(sq[w2], 0x69) ^ sq[w2] ^ mulx(sq[w3], 0x69)) & 0xff
return (int(r0) << 24) | (int(r1) << 16) | (int(r2) << 8) | int(r3)

def clock_fsm(s15, s5):
F = (s15 + fsm[0]) ^ fsm[1]
r = fsm[1] + (fsm[2] ^ s5)
fsm[2] = s2(fsm[1])
fsm[1] = s1(fsm[0])
fsm[0] = r
return F

def lfsr_keystream_mode(S0,S2,S11):
v = (S0 << 8) ^ mul_alpha((S0 >> 24) & 0xff) ^ S2 ^ (S11 >> 8) ^ \
div_alpha(S11 & 0xff)
return v

def de_lfsr_keystream_mode(S0, S2, S11, S16):
if S0 == '':
S0 = BitVec('S0', 32)
else:
S0 = np.uint32(S0)
if S2 == '':
S2 = BitVec('S2', 32)
else:
S2 = np.uint32(S2)
if S11 == '':
S11 = BitVec('S11', 32)
else:
S11 = np.uint32(S11)
if S16 == '':
S16 = BitVec('S16', 32)
else:
S16 = np.uint32(S16)

solver = Solver()
solver.add(S16 == lfsr_keystream_mode(S0, S2, S11))

if solver.check() == sat:
res = solver.model()
if isinstance(S0, BitVecRef):
return res[S0].as_long()
if isinstance(S2, BitVecRef):
return res[S2].as_long()
if isinstance(S11, BitVecRef):
return res[S11].as_long()
if isinstance(S16, BitVecRef):
return res[S16].as_long()
else:
return False

def de_s1(s):
r0=(s>>24)&0xff
r1=(s>>16)&0xff
r2=(s>>8)&0xff
r3=s&0xff

def mulx(V, c):
return (V << 1) ^ (c*LShR(V, 7))& 0xff
solver=Solver()
srw0,srw1,srw2,srw3=BitVecs('srw0 srw1 srw2 srw3', 8)
solver.add(r0 == (mulx(srw0, 0x1b) ^ srw1 ^ srw2 ^mulx(srw3, 0x1b) ^ srw3) & 0xff)
solver.add(r1 == (mulx(srw0, 0x1b) ^ srw0 ^ mulx(srw1, 0x1b) ^ srw2 ^ srw3) & 0xff)
solver.add(r2 == (srw0 ^ mulx(srw1, 0x1b) ^ srw1 ^ mulx(srw2, 0x1b) ^ srw3) & 0xff)
solver.add(r3 == (srw0 ^ srw1 ^ mulx(srw2, 0x1b) ^ srw2 ^ mulx(srw3, 0x1b)) & 0xff)

if solver.check()==sat:
res=solver.model()
__sr=sr.tolist()
w0=__sr.index(res[srw0].py_value())
w1=__sr.index(res[srw1].py_value())
w2=__sr.index(res[srw2].py_value())
w3=__sr.index(res[srw3].py_value())
return (w0 << 24) | (w1 << 16) | (w2 << 8) | w3
else:
return False
def de_s2(s):
r0=(s>>24)&0xff
r1=(s>>16)&0xff
r2=(s>>8)&0xff
r3=s&0xff

def mulx(V, c):
return (V << 1) ^ (c*LShR(V, 7))& 0xff
solver=Solver()
sqw0,sqw1,sqw2,sqw3=BitVecs('sqw0 sqw1 sqw2 sqw3', 8)
solver.add(r0 == (mulx(sqw0, 0x69) ^ sqw1 ^ sqw2 ^mulx(sqw3, 0x69) ^ sqw3) & 0xff)
solver.add(r1 == (mulx(sqw0, 0x69) ^ sqw0 ^ mulx(sqw1, 0x69) ^ sqw2 ^ sqw3) & 0xff)
solver.add(r2 == (sqw0 ^ mulx(sqw1, 0x69) ^ sqw1 ^ mulx(sqw2, 0x69) ^ sqw3) & 0xff)
solver.add(r3 == (sqw0 ^ sqw1 ^ mulx(sqw2, 0x69) ^ sqw2 ^ mulx(sqw3, 0x69)) & 0xff)

if solver.check()==sat:
res=solver.model()
__sq=sq.tolist()
w0=__sq.index(res[sqw0].py_value())
w1=__sq.index(res[sqw1].py_value())
w2=__sq.index(res[sqw2].py_value())
w3=__sq.index(res[sqw3].py_value())
return (w0 << 24) | (w1 << 16) | (w2 << 8) | w3
else:
return False
#检查S序列能否向后推导或者推出前面的某一个值
def checkS():
flag=False#标记是否有check出新的值
for i in range(len(S)-16):
__l=[type(S[i]),type(S[i+2]),type(S[i+11]),type(S[i+15+1])]
if __l.count(int)==3:
flag=True
if __l.index(str)==3:
S[i+15+1]=int(lfsr_keystream_mode(np.uint32(S[i+0]),np.uint32(S[i+2]),np.uint32(S[i+11])))
else:
__index=[i,i+2,i+11,i+15+1]
S[__index[__l.index(str)]]=de_lfsr_keystream_mode(S[i],S[i+2],S[i+11],S[i+15+1])
return flag

#检查fsm能否向前或向后推导
def checkFSM():
flag=False
for i in range(len(fsm)-5):
if type(fsm[i][1])==int and type(fsm[i+1][2])!=int:#fsm[i][1] -s2-> fsm[i+1][2]
fsm[i+1][2]=int(s2(fsm[i][1]))
flag=True
if type(fsm[i][0])==int and type(fsm[i+1][1])!=int:#fsm[i][0] -s1-> fsm[i+1][1]
fsm[i+1][1]=int(s1(fsm[i][0]))
flag=True
if type(fsm[i][1])!=int and type(fsm[i+1][2])==int:#fsm[i][1] -de_s2-> fsm[i+1][2]
fsm[i][1]=de_s2(fsm[i+1][2])
flag=True
if type(fsm[i][0])!=int and type(fsm[i+1][1])==int:#fsm[i][0] -de_s1-> fsm[i+1][1]
fsm[i][0]=de_s1(fsm[i+1][1])
flag=True
#对于fsm[i][0],只要知道其中任意三个值就可以推出剩下的一个值,所以顺带都写在这了
__l=[type(fsm[i][1]),type(fsm[i][2]),type(S[i+5]),type(fsm[i+1][0])]
if __l.count(int)==3:
flag=True
__=__l.index(str)
if __==0:
fsm[i][1]=(fsm[i+1][0]-(fsm[i][2]^S[i+5]))%2**32
elif __==1:
fsm[i][2]=((fsm[i+1][0]-fsm[i][1])^S[i+5])%2**32
elif __==2:
S[i+5]=((fsm[i+1][0]-fsm[i][1])^fsm[i][2])%2**32
elif __==3:
fsm[i+1][0]=(fsm[i][1]+(fsm[i][2]^S[i+5]))%2**32
return flag
#检查clock_fsm里面的F的推导,只要知道其中任意三个值就可以推出剩下的一个值
def checkFSFSM():
flag=False
for i in range(len(S)-15):
__l=[type(fsm[i][0]),type(fsm[i][1]),type(F[i]),type(S[i+15])]
if __l.count(int)==3:
flag=True
__=__l.index(str)
if __==0:
fsm[i][0]=((F[i]^fsm[i][1])-S[i+15])%2**32
elif __==1:
fsm[i][1]=(F[i]^(S[i+15]+fsm[i][0]))%2**32
elif __==2:
F[i]=((S[i+15]+fsm[i][0])^fsm[i][1])%2**32
elif __==3:
S[i+15]=((F[i]^fsm[i][1])-fsm[i][0])%2**32
return flag

#检查F,S,key_stream的互相之间的推导,知道任意2个可以推出剩下的一个
def checkFSSTREAM():
flag=False
for i in range(len(key_stream)):
__l=[type(key_stream[i]),type(F[i]),type(S[i])]
if __l.count(int)==2:
flag=True
__=__l.index(str)
if __==0:
key_stream[i]=F[i]^S[i]
elif __==1:
F[i]=key_stream[i]^S[i]
elif __==2:
S[i]=key_stream[i]^F[i]
return flag

def checkALL():
flag=checkFSM()
flag=flag or checkFSFSM()
flag=flag or checkFSSTREAM()
flag=flag or checkS()
#checkCORRECT()
return flag


#测试用函数===================================================================================
def checkCORRECT():
t_S=[3728967755, 3495356165, 472187142, 886943789, 4084678986, 114208514, 4079807976, 4275161248, 3282638664, 2076006597, 3373805671, 2974123815, 3847446102, 2029449241, 1167248190, 3124340476, 2413002776, 3447953474, 4266587847, 4175396429, 4131847277, 1684661431, 2541104664, 2037740470, 2396869767, 4221185578, 3017606363, 2068083020, 2267507878, 3591283476, 2686059627, 1351965579, 545189806, 3529654008, 795261281, 3336159413, 55920688, 3640778187, 10677684, 2992943598, 1690983591, 1929655536, 858855436, 3516290525, 208822826, 1790432759, 1090329888, 3311895372, 2442868764, 525297149, 1581426865, 2535702230, 3690055020, 2897748567, 1087734291, 2968696404, 790180987, 1067508412, 1812069970]

for i in range(len(t_S)):
if type(S[i])==int:
if S[i]!=t_S[i]:
print('S:',i)
t_r1=[4288109169, 566438029, 3252420959, 310114661, 405113667, 42168638, 426348252, 2217508059, 2364527128, 2513670487, 4258403922, 1344762431, 3259421801, 2290768410, 3562266277, 3034556817, 2874338847, 2207755823, 3434078908, 3673270886, 3634307680, 887505320, 3272180482, 3182178649, 2463707393, 3945361442, 532203740, 3515575884, 2670224373, 219742259, 3138161244, 1504798987, 3549858809, 1036509647, 2256657537, 4291048480, 3146309710, 1353304775, 3251573430, 278650815, 2240592460, 2202855101, 3645670807, 2183393958, 1051616755, 3920219094, 3655214575, 2766578751, 1372178632, 1819972070, 4032746236, 3996865332, 2470546560, 2521538742, 562444771, 2248808042, 3424030997, 638968787, 1996261738, 2006370108]

t_r2=[1355885794, 3828109594, 472496693, 1076682495, 3872837314, 1840614625, 1816901402, 3255922705, 262821239, 1309786686, 1583923810, 1523195432, 3041126837, 1214947918, 2931262268, 1778538638, 3573090404, 3075404417, 2429921657, 3637677643, 4131381119, 3779984047, 1617841815, 686529006, 3837496372, 3892378064, 2477993090, 2397911448, 2777576939, 1392741422, 1550955835, 2448835842, 3240053317, 3509923480, 4119599101, 375278529, 3937252695, 2608352072, 1358566283, 1627404846, 503044471, 3736592806, 3934907064, 1460859829, 3855897853, 3244167835, 4051089435, 847623116, 3403687926, 2949222116, 1917891093, 624600427, 2001915094, 147539826, 3128478596, 2224489645, 2923913710, 3146498598, 398940241, 1637262462]

t_r3=[3594474665, 780361133, 142866320, 340900620, 1611791033, 1655452060, 2795848422, 797785169, 4276079609, 3931283242, 1267140897, 3903796825, 516286503, 1973930640, 4277622808, 3071699452, 3405201788, 2182536739, 862548827, 1896988818, 3309063171, 1382452360, 645501838, 4006280117, 3496165626, 2544749415, 1833769537, 809879027, 3051926704, 1198409551, 1004958565, 1123356359, 2779335233, 3052290141, 3093081549, 3252733994, 385360256, 359128930, 1849137641, 687792692, 266786993, 3127492305, 1392346274, 1979730466, 479859492, 1187167205, 608981746, 3300250000, 220351399, 4245003, 3407353675, 1092604782, 559427932, 1958415395, 2773555934, 1261361337, 1619553922, 3312946173, 3589284217, 4259352522]

for i in range(len(t_r1)):
if type(fsm[i][0])==int and fsm[i][0]!=t_r1[i]:
print('R1:',i,0)
if type(fsm[i][1])==int and fsm[i][1]!=t_r2[i]:
print('R2:',i,1)
if type(fsm[i][2])==int and fsm[i][2]!=t_r3[i]:
print('R3:',i,2)
t_F=[3909102991, 1438316991, 2473993108, 1357262547, 4157851474, 2508185930, 295224457, 3652442850, 164565177, 1788946400, 2802091550, 1590585650, 2294852608, 1205560462, 81068677, 1056699762, 789660110, 324562780, 264734925, 3532320140, 1766276202, 3648418679, 4234489434, 2527364835, 2709941979, 2817733913, 17813838, 2320613312, 3576745017, 1250487923, 2041959784, 190366505, 1507935488, 508966771, 1348294019, 1213765392, 3087084147, 3085163387, 1048389254, 812735484, 730114519, 1825700510, 4066673387, 3107390285, 1220207318, 883241532, 5483853, 275268404, 384384940, 2648392877, 2643780042, 2388170262, 704314697, 1113445259, 3645689675, 4150313002, 1649850319, 77719709, 1803356974]
for i in range(len(t_F)):
if type(F[i])==int and F[i]!=t_F[i]:
print('F:',i)
#测试用函数===================================================================================


key_stream=['']*150
gift=b"the quick brown fox jumps over the lazy dog\n"
C=[3539094009, 980211684, 2198891016, 905998740, 1595475160, 3962636204, 1199994505, 3190370623, 296595869, 3158272345, 2748985736, 382671580, 2521428409, 248078233, 1528783547, 2729100548, 3426466722, 3192873770, 1337295957, 1431041587, 1607853207, 3998694569, 3160389002, 3728077354, 1120982789, 3443900372, 1811224296, 3102761228, 3296566547, 3724398326, 873334127, 3279785283, 1267844209, 907638672, 2121413959, 3173567371, 4097722407, 844863077, 3114817962, 3619759560, 2198708209, 2363435526, 196774438, 2671749579, 4031688923, 471349633, 778676959, 3608967403, 92491149, 913291948, 3021362116, 1067932129, 999259588, 3190588842, 1828097126, 1450255462, 1305572961, 1341694028, 2350778224, 2932388574, 1204050979, 1294999174, 1921124090, 2342994011, 1941020673, 1191919176, 187588176, 255691701, 274795123, 873091533, 299848364, 870697920, 3387594780, 944072831, 848477078, 447469593, 917439649, 598555627, 3036173079, 3758185777, 4236584984, 4205933999, 1185586113, 3227810954, 2737102694, 3680871868, 4102277292, 378037705]

hack=[834501734,940247165,2078728259,483907438,1102712410,3110955761,3016462560,871310805,1334672645,1102778698]


fsm=[['']*3 for i in range(150)]
S=['']*150
F=['']*150

#填一下已知数据
fsm[2][0]=hack[0]
fsm[2][1]=hack[1]
fsm[2][2]=hack[2]
S[2]=hack[3]
S[3]=hack[4]
S[6]=hack[5]
S[7]=hack[6]
S[8]=hack[7]
fsm[5][0]=hack[8]
fsm[7][0]=hack[9]

for i in range(len(gift)):
key_stream[i]=C[i]^gift[i]

F[2]=S[2]^key_stream[2]
F[3]=S[3]^key_stream[3]
F[6]=S[6]^key_stream[6]
F[7]=S[7]^key_stream[7]
F[8]=S[8]^key_stream[8]

while checkALL():
None

plain=b''
for i in range(len(C)):
plain+=long_to_bytes(key_stream[i]^C[i])
print(plain)
1
b'the quick brown fox jumps over the lazy dog\nDASCTF{2bfc1bd3-740e-4b3f-ab9f-9587b1d47209}'

那么预赛也是全复现完了,我是没找到预赛的密码的wp,那么就这样吧。
发现我的de_lfsr_keystream_mode的错误了请和我说一下哦。


2024浙江省赛
https://bddye.github.io/2025/02/01/2024浙江省赛/
作者
蹦跶的鱼儿
发布于
2025年2月1日
许可协议