XYCTF-crypto

前言

第一次打比赛,被新生赛狠狠拷打了QAQ

Complex_dlp

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
from Crypto.Util.number import *
from secrets import flag


class Complex:
def __init__(self, re, im):
self.re = re
self.im = im

def __mul__(self, c):
re_ = self.re * c.re - self.im * c.im
im_ = self.re * c.im + self.im * c.re
return Complex(re_, im_)

def __str__(self):
if self.im == 0:
return str(self.re)
elif self.re == 0:
if abs(self.im) == 1:
return f"{'-' if self.im < 0 else ''}i"
else:
return f"{self.im}i"
else:
return f"{self.re} {'+' if self.im > 0 else '-'} {abs(self.im)}i"


def complex_pow(c, exp, n):
result = Complex(1, 0)
while exp > 0:
if exp & 1:
result = result * c
result.re = result.re % n
result.im = result.im % n
c = c * c
c.re = c.re % n
c.im = c.im % n
exp >>= 1
return result


flag = flag.strip(b"XYCTF{").strip(b"}")
p = 1127236854942215744482170859284245684922507818478439319428888584898927520579579027
g = Complex(3, 7)
x = bytes_to_long(flag)
#complex_pow(g, x, p)==5699996596230726507553778181714315375600519769517892864468100565238657988087817 + 198037503897625840198829901785272602849546728822078622977599179234202360717671908i


做的时候一直卡在复数转实数上,想到了共轭复数但是没有去仔细研究。

赛后看wp知道了定义image-20240428191957162

这样题目中的g和c都可以通过实部和虚部平方相加的方式转为实数再进行普通的dlp求解

exp:

1
2
3
4
5
6
7
8
from Cryptodome.Util.number import *
import gmpy2
from sympy.ntheory import discrete_log
p=1127236854942215744482170859284245684922507818478439319428888584898927520579579027
g=58
c=(5699996596230726507553778181714315375600519769517892864468100565238657988087817**2)+(198037503897625840198829901785272602849546728822078622977599179234202360717671908**2)
flag=discrete_log(p,c,g)
print(long_to_bytes(flag))

Complex_rsa

与上题类似,也是一个复数域上的问题

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
from Crypto.Util.number import *
from secrets import flag


class Complex:
def __init__(self, re, im):
self.re = re
self.im = im

def __mul__(self, c):
re_ = self.re * c.re - self.im * c.im
im_ = self.re * c.im + self.im * c.re
return Complex(re_, im_)

def __str__(self):
if self.im == 0:
return str(self.re)
elif self.re == 0:
if abs(self.im) == 1:
return f"{'-' if self.im < 0 else ''}i"
else:
return f"{self.im}i"
else:
return f"{self.re} {'+' if self.im > 0 else '-'} {abs(self.im)}i"


def complex_pow(c, exp, n):
result = Complex(1, 0)
while exp > 0:
if exp & 1:
result = result * c
result.re = result.re % n
result.im = result.im % n
c = c * c
c.re = c.re % n
c.im = c.im % n
exp >>= 1
return result


m = bytes_to_long(flag)
key = getRandomNBitInteger(m.bit_length())
c = m ^ key
com = Complex(key, c)
p = getPrime(512)
q = getPrime(512)
e = 9
enc = complex_pow(com, e, p * q)
print(enc)
print(Complex(p, q) * Complex(p, q))
# 66350931528185981323649477263900844564494528747802437244889229343520648562164950914433406604580038018765783183569276743239888668912948977370163046257917321742455772852779551569446155827368453262479370103326286297164105599131090881306108546341785251895116423206455175290083968296281375908109039893280371271943 + 65266730684129269806656018828265187384002656633231286337130178390517924611751697965395744944541329793503617856896706439809241745206839328124348693486741656130890593895436661857688522977866438805549144904296596887218275440542852887148071837153436265722614658566275517205322945316112048487893204059562830581004i
# -28814875173103880290298835537218644402443395484370652510062722255203946330565951328874411874019897676900075613671629765922970689802650462822117767927082712245512492082864958877932682404829188622269636302484189627580600076246836248427780151681898051243380477561480415972565859837597822263289141887833338111120 + 235362412848885579543400940934854106052672292040465052424316433330114813432317923674803623227280862945857543620663672974955235166884830751834386990766053503640556408758413592161122945636548462064584183165189050320898315823173824074873376450569212651128285746330837777597290934043912373820690250920839961482862i

已知Complex(p, q) * Complex(p, q),明显通过该式子求得p,q,同时在复数域中phi=(p^2^-1)(q^2^-1),按照一般的思路求e关于phi的逆元即可得到结果,但对于这道题有

gcd(e,p^2^-1)=gcd(e,q^2^-1)=3,所以逆元不存在。

反方向的密码 相思

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.Util.number import *
import hashlib
from secrets import flag


def hash(x):
return hashlib.sha256(x.encode()).digest()


def pad(message):
return message + hash(str(len(message)))


m = bytes_to_long(pad(flag))
p = getStrongPrime(512)
q = getStrongPrime(512)
n = p * q
e = 3
print(pow(m, e, n))
print(n)
# c=120440199294949712392334113337541924034371176306546446428347114627162894108760435789068328282135879182130546564535108930827440004987170619301799710272329673259390065147556073101312748104743572369383346039000998822862286001416166288971531241789864076857299162050026949096919395896174243383291126202796610039053
# n=143413213355903851638663645270518081058249439863120739973910994223793329606595495141951165221740599158773181585002460087410975579141155680671886930801733174300593785562287068287654547100320094291092508723488470015821072834947151827362715749438612812148855627557719115676595686347541785037035334177162406305243
# m=1252734178929444996144243699830218307941015280272407466795285950142407741311749512416560379489724065530428888294520405996969464281930538422811270188075397985

其实就是将sha256看做256进制,256^32^代表将m作为高位拼接到32字节的h之前,其实与二进制移位乘2^n^道理一样。最后copper求小根。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from Crypto.Util.number import *
import hashlib
from tqdm import *


def hash(x):
return hashlib.sha256(x.encode()).digest()

e = 3
c = 120440199294949712392334113337541924034371176306546446428347114627162894108760435789068328282135879182130546564535108930827440004987170619301799710272329673259390065147556073101312748104743572369383346039000998822862286001416166288971531241789864076857299162050026949096919395896174243383291126202796610039053
n = 143413213355903851638663645270518081058249439863120739973910994223793329606595495141951165221740599158773181585002460087410975579141155680671886930801733174300593785562287068287654547100320094291092508723488470015821072834947151827362715749438612812148855627557719115676595686347541785037035334177162406305243

PR.<x> = PolynomialRing(Zmod(n))
for length in trange(20,50):
suffix = bytes_to_long(hash(str(length)))
f = (256^32*x + suffix)^3 - c
f = f.monic()
res = f.small_roots(X=256^length,beta=1,epsilon=0.05)
if(res != []):
print(long_to_bytes(int(res[0])))
break