这道题充分反应了我的密码学是白学的,总共花的时间肯定24h+。
先看题目脚本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#second.py
# -*- coding: utf-8 -*-
from Crypto.Util.number import *
from Crypto.Random.random import *
from flag import flag
Au = getStrongPrime(1024)
AuAu = getStrongPrime(1024)
AuAuAu = getStrongPrime(1024)
def AuAuAuAu(Au, AuAu):
while AuAu: Au, AuAu = AuAu, Au % AuAu
return Au
def AuAuAuAuAu(Au, AuAu, AuAuAu):
AuAuAuAu = 1
while AuAu != 0:
if (AuAu & 1) == 1:
AuAuAuAu = (AuAuAuAu * Au) % AuAuAu
AuAu >>= 1
Au = (Au * Au) % AuAuAu
return AuAuAuAu
AuAuAuAuAuAuAuAu = AuAuAuAuAu(AuAuAu, Au, AuAu)
while True:
AuAuAuAuAuAuAuAuAu = randint(1, 2 ** 512)
if AuAuAuAu(AuAuAuAuAuAuAuAuAu, AuAu - 1) == 1:
break
AuAuAuAuAuAu = bytes_to_long("AuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAu")
AuAuAuAuAuAuAuAuAuAu = AuAuAuAuAu(AuAuAu, AuAuAuAuAuAuAuAuAu, AuAu)
AuAuAuAuAuAuAuAuAuAuAu = (AuAuAuAuAuAu * AuAuAuAuAu(AuAuAuAuAuAuAuAu, AuAuAuAuAuAuAuAuAu, AuAu)) % AuAu
AuAuAuAuAuAuAu = bytes_to_long(flag)
AuAuAuAuAuAuAuAuAuAuAuAu = (AuAuAuAuAuAuAu * AuAuAuAuAu(AuAuAuAuAuAuAuAu, AuAuAuAuAuAuAuAuAu, AuAu)) % AuAu
with open('cipher_second.txt', 'w') as f:
f.write("AuAuAuAuAuAuAuAuAuAu = " + str(AuAuAuAuAuAuAuAuAuAu) + "\n")
f.write("AuAuAu = " + str(AuAuAu) + "\n")
f.write("AuAuAuAuAuAuAuAuAuAuAu = " + str(AuAuAuAuAuAuAuAuAuAuAu) + "\n")
f.write("AuAu = " + str(AuAu) + "\n")
f.write("AuAuAuAuAuAuAuAuAuAuAuAu = " + str(AuAuAuAuAuAuAuAuAuAuAuAu) + "\n")
其中cipher_second.txt:
AuAuAuAuAuAuAuAuAuAu = 24060165536084067979813052960543411990367073733053765644699769988102126301607236684736234516917540119724097667932884475795898871957309932809071146014543460692909352480408824618517714722984771049822684175641847290185361834032033919030884844384627328802352161436308308068681230733830014160613566516126913599679
AuAuAu = 168230812504917132822031239630078220399074310356381999181653517650324353404279211761461822712544278210131581579847841070580950397484038230733404459908782058900591709322993519389006100884788751465393449665892538579778559870105753578478869369578539551683426350885553541430608204655262429792813559526327112757307
AuAuAuAuAuAuAuAuAuAuAu = 6176793597133333153104561382047091578706459334173172854358730376866346466693739263599908820647251113062601080198894369117388276661115933812633716068890695100939879884301897876409847467119800293136643838117806130141030659269692031448283847911409126502025196469087884093076807854121717604528435136002415867083
AuAu = 167908172755079385864716897695513030660553919301934409681210763749727536722398027958629268482499100608025554396933773154683645615083120905283181619647906045358631174674237455242955211996165382972055067541620477170429863892848862127083204138236540038524086429614874555987063767766002782758903781175206444000363
AuAuAuAuAuAuAuAuAuAuAuAu = 105084272748264545777918765251804955981747011423695761842563445096939882269112639284807907661779031158819140579730636212690913001865142790989296999645422093830570725060828634302857073362387686345561952108096388797147863938775327062182858148523836274897976493706637533409419483577687121544409394830323932412378
可以看到一堆密密麻麻的Au,我们要想怎么把这堆碍眼的Au换成简洁的表现形式。1
2
3
4
5
6
7
8
9#首先是AuAuAuAu,白学之一,我没有看出是gcd
def AuAuAuAu(Au, AuAu):
while AuAu: Au, AuAu = AuAu, Au % AuAu
return Au
#如果看出是gcd,那就解决了AuAuAuAu,
def gcd(Au, AuAu):
while AuAu: Au, AuAu = AuAu, Au % AuAu
return Au1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#然后是AuAuAuAuAu,白学之二,没有看出是pow
def AuAuAuAuAu(Au, AuAu, AuAuAu):
AuAuAuAu = 1
while AuAu != 0:
if (AuAu & 1) == 1:
AuAuAuAu = (AuAuAuAu * Au) % AuAuAu
AuAu >>= 1
Au = (Au * Au) % AuAuAu
return AuAuAuAu
关键在于AuAuAuAu = (AuAuAuAu * Au) % AuAuAu
AuAu是指数项,在while循环中不断右移一位,每右移一位Au就自乘一次,最后AuAu等于1,也就是累乘完了,进入if语句, 模上AuAuAu
#所以如果看出是pow。那就解决了AuAuAuAuAu
def pow(Au, AuAu, AuAuAu):
AuAuAuAu = 1
while AuAu != 0:
if (AuAu & 1) == 1:
AuAuAuAu = (AuAuAuAu * Au) % AuAuAu
AuAu >>= 1
Au = (Au * Au) % AuAuAu
return AuAuAuAu
那题中的代码怎么简约化呢?
大概是照着rsa的思路,pow的元素用p(q、m、c)、e、n的元素替换
在这里用p1
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# -*- coding: utf-8 -*-
from Crypto.Util.number import *
from Crypto.Random.random import *
flag = b"flag{test}"
e0 = getStrongPrime(1024)
n = getStrongPrime(1024)
p = getStrongPrime(1024)
def gcd(Au, AuAu):
while AuAu: Au, AuAu = AuAu, Au % AuAu
return Au
def _pow(Au, AuAu, AuAuAu):
AuAuAuAu = 1
while AuAu != 0:
if (AuAu & 1) == 1:
AuAuAuAu = (AuAuAuAu * Au) % AuAuAu
AuAu >>= 1
Au = (Au * Au) % AuAuAu
return AuAuAuAu
tmp = _pow(p, e0, n)
while True:
e1 = randint(1, 2 ** 512)
if gcd(e1, n - 1) == 1:
break
y = bytes_to_long("AuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAu")
print (y)
r2 = _pow(p, e1, n)
r0 = (y * _pow(tmp, e1, n)) % n
x = bytes_to_long(flag)
r1 = (x * _pow(tmp, e1, n)) % n
with open('cipher_second.txt', 'w') as f:
f.write("r2 = " + str(r2) + "\n")
f.write("p = " + str(p) + "\n")
f.write("r0 = " + str(r0) + "\n")
f.write("n = " + str(n) + "\n")
f.write("r1 = " + str(r1) + "\n")
看到关键的几行代码1
2
3
4
5
6y = bytes_to_long("AuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAu")
print (y)
r2 = _pow(p, e1, n)
r0 = (y * _pow(tmp, e1, n)) % n
x = bytes_to_long(flag)
r1 = (x * _pow(tmp, e1, n)) % n
也就是可以得到y、r2、p、r0、n、r1的值,通过这些值算出x,也就是flag
我们把_pow(tmp, e1, n)看成一个整体,令他为m,则1
2
3
4
5
6y = bytes_to_long("AuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAuAu")
print (y)
r2 = _pow(p, e1, n)
r0 = (y * m) % n
x = bytes_to_long(flag)
r1 = (x * m) % n
对于r0 = (y * m) % n
由于我们知道r0,y,n的值,先通过求y模n的乘法逆元,然后可以求得m
两边同乘$y^{-1}$
修改:乍的一看应该是下面的形式
其实正确的换算应该是
也就是最关键的两个式子
$ (a+b) mod\ n =t $
$ a= (t-b)mod\ n $$(ab) mod\ n=t$
$ a=(tb^{-1})mod\ n$
1 | def inverse(u, v): |
修改:下面这一part是最初没有简单无用的分析
这里应该还是要考虑到数字大小,不知道为什么
由于$m=r0*y^{-1}$ >>$n、r0$ >> $y$
如果知道r0,m,n的值,想通过求m模n的乘法逆元,再求得y
得到的结果需要模一次n,也就是
两边同乘$m^{-1}$
因此,在求flag的时候就需要模多一次n
对于r1 = (x * m) % n
由于我们知道r1,m,n的值,类似的,先通过求m模n的乘法逆元,然后可以求得x
两边同乘$m^{-1}$
1 | m=745957509435219482734373253804065981190948437248355256150465242442432959045431082969859790720189299044887304311722294690152135839444419143214225213328407525753297755021918427145980049335533779804728785413269062910067309714052603591286688787620248422230483101998934871770529606844223269545467008437232325215908344786459547781392201492805051480246088158164570526005111371529954392879157843010695015939697102297822823152011929046829089244920809488280319679486696992650250433965732956012223732584167766555822478417782403940234311102211185014412371857788936016990149145449451013424482481542514501793884162283176004977371 |
1 | 修改: |
可以看到全程不用处理tmp和m
解决python3 无法直接bytes_to_long的方法
进入文件\python\lib\site-packages\Crypto\Util\number.py中1
2
3
4
5
6
7
8
9
10
11
12定位到def bytes_to_long(s):
将
for i in range(0, length, 4):
acc = (acc << 32) + unpack('>I', s[i:i+4])[0]
return acc
替换为
for i in range(0, length, 4):
if isinstance(s[i:i+4],str):
acc = (acc << 32) + unpack('>I', s[i:i+4].encode())[0]
else:
acc = (acc << 32) + unpack('>I', s[i:i+4])[0]
return acc