Week1
InfantRSA 50pt
|
|
Affine 75pt
Affine_task.py
|
|
exp.py
|
|
not_One-time 150pt
not_One-time_task.py
|
|
Flag重用可还行。
-
可以获取任意数量密文
-
key space仅
26*2+10=62
这里用了一个统计方法。
先获取很多个密文c
,将其他密文和第一个密文异或,消去flag,得到的就只有ki = key0 ^ keyi
。
我们的目标是要获得这个key0
。
长度都是43。
考虑key0
的第i
位字母,只能是string.ascii_letters+string.digits
中的某一个ch
。
那么这个特定的ch
与其他keyi
对应位置的字母异或得到的结果,就只有62种可能,将其看作一个集合set_ch
。
且不同的ch
得到的结果集合set_ch
中至少是会有几个元素是不同的,即不同的ch
得到的结果集合不相同。
那么,(当我们掌握足够多的数据时)我们就可以通过每一位字母得到的结果集合,去反推这个字母是什么。
例如:如果key0
第i
位字母是a
,那么ki = key0 ^ keyi
的所有62种可能的结果就是set_a = {a^a, a^b, ..., a^A, a^B, ..., a^0, ..., a^9}
;如果key0
第i
位字母是b
,那么ki = key0 ^ keyi
的所有62种可能的结果就是set_b = {b^a, b^b, ..., b^A, b^B, ..., b^0, ..., b^9}
;。。。。。。
且这些set_a != set_b != ... !=set_9
。
在第i
位,如果我们得到的结果集合是set_a
,那么我们就可以推断出这一位的字母一定是a
。
可能画图会更清晰一些。
算一些没用的:1000组数据,这个结果集合的长度不满62的概率。
也就是说有一个位置,1000次都没选中。 $$ P = C_{62}^{1} (1 - \frac{1}{62})^{1000} \approx 5 \times 10^{-6} $$ 所以1000组数据足够了
|
|
Reorder 75pt
Input: hgame{ABCDEFGHIJKLMNOPQRSTUVWXY}
Output: {hHDCFABGemEaJIgPKXTSVQRWONUM}YL
Encrypted flag: {hmt$5jUIem+aLpgm3!TA0uTnReiP}!_
|
|
Week2
Verification_code 125pt
Verification_code.py
|
|
exp.py
|
|
Remainder 150pt
Remainder_task.py
|
|
关键在于assert 256 < len(msg) < 384
,也就是说m
在2048~3072bit之间。
但是p, q, r
只有1024bit,显然只用其中一个是算不出来m
的,需要把模数扩大下。
exp.sage
|
|
Inv 175pt
有点意思,Subs
也能当作一个运算。
|
|
notRC4 200pt
notRC4_task.py
|
|
逆一下fun2
exp.py
|
|
Week3
RSA? 150pt
RSA_task.py
|
|
n = p*q + r
迷惑行为。
看了一下,n
是一个素数,GF(n)
上开平方根。
exp.sage
|
|
ToyCipher_XorShift 175pt
task.py
|
|
就逆一个xor shift
exp.py
|
|
Exchange 150pt
中间人攻击,就是写脚本费时间。
|
|
Feedback 150pt
task.py
|
|
看图解题。
exp.py
|
|
Week4
CBCBC 150pt
task.py
|
|
没图?那就自己画一个。
考虑第一段M1
,即flag[:16]
。
解密完了会unpad
,unpad
成功后会返回Decryption done
,否则返回sth must be wrong
。
可以在这边操作下。
对mid_1
(即IV1
)异或上一些东西,来逐字节爆破。
例如,如果解密出来的m
满足???????????????\x01
,那么就会显示Decryption done
,所以我们可以在mid_1
的最后一字节异或上某个东西i
(尝试所有256种可能),使它回显Decryption done
,那么原来的m
的最后一位就肯定是i ^ 1
;如果解密出来的m
满足``??????????????\x02\x02,也会显示
Decryption done,可以把
mid_1的最后一位设置成
\x02(我们已经知道什么时候会是
\x01了,所以再异或一下
1^2就能把它给设置成
\x02),在倒数第二位处尝试256种可能
i,使它回显
Decryption done,那么原来的
m的倒数第二位肯定就是
i ^ 2 。一直这样下去,可以通过平均
256/2 * 16 = 2048 次尝试爆破出
flag[:16]`。
考虑第二段M2
,即flag[16:32]
。
同样的思路,可以对mid_2
(即IV_2
)异或上一些东西,逐字节爆破M2
。
后面2段M3, M4
也是一样,分别对C1, C2
异或上一些东西,逐字节爆破M3, M4
。
exp.py
|
|
ToyCipher_Linear 175pt
整个加密过程可以用一个$32 \times 224$的矩阵来表示,以前也出过一道基本一样的题目。
太费时间了,懒得写了。
|
|