HWS2023

ezrsa

题如其名,真的ez,可以看出是一个二次剩余,直接 from sympy.ntheory.residue_ntheory import nthroot_mod 调用函数就行了。(一开始没发现c和r给反了,卡挺久)

1
2
3
4
5
6
7
8
9
from Crypto.Util.number import long_to_bytes
c = 4124820799737107236308837008524397355107786950414769996181324333556950154206980059406402767327725312238673053581148641438494212320157665395208337575556385
r = 13107939563507459774616204141253747489232063336204173944123263284507604328885680072478669016969428366667381358004059204207134817952620014738665450753147857

from sympy.ntheory.residue_ntheory import nthroot_mod
x=nthroot_mod(c,2,r)

print(x)
print(long_to_bytes(x))

得到flag:

flag{9971e255f0c020e8e57fbae75f43d7fb}

H0xSJ.png

hdrsa

题如其名,确实hard,观察发现破解的核心在于p的生成方式,搜索发现可以通过 Cheng’s 4p - 1 elliptic curve complex multiplication based factorization algorithm破解。然后找到了github上写好的脚本:
https://github.com/pwang00/Cryptographic-Attacks/blob/master/Public%20Key/Factoring/cm_factor.sage

于是现在能分解n了,接着网上找到了一个类似的题目的脚本

https://angmar2722.github.io/CTFwriteups/2021/idek2021/#destroyed-rsa

稍作修改就能得到flag了

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
from sage.all import *
from random import choice
from math import gcd
import sys
from Crypto.Util.number import *
from tqdm import tqdm
import time

sys.setrecursionlimit(100000)

def polynomial_xgcd(a, b):
"""
Computes the extended GCD of two polynomials using Euclid's algorithm.
:param a: the first polynomial
:param b: the second polynomial
:return: a tuple containing r, s, and t
"""
assert a.base_ring() == b.base_ring()

r_prev, r = a, b
s_prev, s = 1, 0
t_prev, t = 0, 1

while r:
try:
q = r_prev // r
r_prev, r = r, r_prev - q * r
s_prev, s = s, s_prev - q * s
t_prev, t = t, t_prev - q * t
except RuntimeError:
raise ArithmeticError("r is not invertible", r)

return r_prev, s_prev, t_prev

def polynomial_inverse(p, m):
"""
Computes the inverse of a polynomial modulo a polynomial using the extended GCD.
:param p: the polynomial
:param m: the polynomial modulus
:return: the inverse of p modulo m
"""
g, s, t = polynomial_xgcd(p, m)
return s * g.lc() ** -1

def factorize(N, D):
"""
Recovers the prime factors from a modulus using Cheng's elliptic curve complex multiplication method.
More information: Sedlacek V. et al., "I want to break square-free: The 4p - 1 factorization method and its RSA backdoor viability"
:param N: the modulus
:param D: the discriminant to use to generate the Hilbert polynomial
:return: a tuple containing the prime factors
"""
assert D % 8 == 3, "D should be square-free"

zmodn = Zmod(N)
pr = zmodn["x"]

H = pr(hilbert_class_polynomial(-D))
Q = pr.quotient(H)
j = Q.gen()

try:
k = j * polynomial_inverse((1728 - j).lift(), H)
except ArithmeticError as err:
# If some polynomial was not invertible during XGCD calculation, we can factor n.
p = gcd(int(err.args[1].lc()), N)
return int(p), int(N // p)

E = EllipticCurve(Q, [3 * k, 2 * k])
while True:
x = zmodn.random_element()

#print(f"Calculating division polynomial of Q{x}...")
z = E.division_polynomial(N, x=Q(x))

try:
d, _, _ = polynomial_xgcd(z.lift(), H)
except ArithmeticError as err:
# If some polynomial was not invertible during XGCD calculation, we can factor n.
p = gcd(int(err.args[1].lc()), N)
return int(p), int(N // p)

p = gcd(int(d), N)
if 1 < p < N:
return int(p), int(N // p)

n=330961752887996173328854935965112588884403584531022561119743740650364958220684640754584393850796812833007843940336784599719224428969119533284286424077547165101460469847980799370419655082069179038497637761333327079374599506574723892143817226751806802676013225188467403274658211563655876500997296917421904614128056847977798146855336939306463059440416150493262973269431000762285579221126342017624118238829230679953011897314722801993750454924627074264353692060002758521401544361385231354313981836056855582929670811259113019012970540824951139489146393182532414878214182086999298397377845534568556100933934481180701997394558264969597606662342898026915506749002491326250792107348176681795942799954526068501499100232598658650184565873243525176833451664254917655703178472944744658628534195346977023418550761620254528178516972066618936960223660362493931786389085393392950207048675797593816271435700130995225483316625836104802608163745376633884840588575355936746173068655319645572100149515524131883813773486917122153248495022372690912572541775943614626733948206252900473118240712831444072243770979419529210034883903111038448366933374841531126421441232024514486168742686297481063089161977054825621099768659097509939405315056325336120929492838479309609958696957890570295444494277819063443427972643459784894450787015151715676537385237767990406742547664321563688829289809321534752244260529319454316532580416182438749849923354060125229328043961355894086576238519138868298499249023773237770103057707912709725417033309061308880583988666463892828633292839968866953776989722310954204550783825704710017434214644199415756584929214239679433211393230307782953067246529626136446314941258877439356094775337541321331600788042698664632064112896956898222397445497695982546922871549828242938368486774617350420790711093069910914135319635330786253331223459637232106417577225350441291
e=65537
c=187275367513186345104534865239994699892170904489725413330767115192172530253625393062151741036312498277557971553595091826062438445856091864605758318579599363539202154625683947568962358702545878760994434813222953503460910447662183200334960821110618746899798165363389255347363192576250804362413854445821046755759458439443253294822553986237695607000569717855942461517564526611106601774100617668231506539201297550376834067118784548951699927659889815770492684106287801610261026674778509245649501695344652216367741171392139049785280654043804502329999760613658697298671602787929199239524617160567336634126185042907593427921016129734757065504417112269027028799047579450965076835882020261162192475637278445255805339324893626400179818784574957669576516363342104273184813708475202313539634027764340858242764934872804570810575764191987921655276520658100755510986290562980055133376750812535713567917823663134974180449002466833109112866681229626239871954125027501071383217816313440079294139254989413050731511516498127225020975071747314764552267845933494600295296885808466296844091612401062566502515356974852161817112538289440970059783116540091633055220150093646069438113246518726017868258339512247175386052684861670431148484455765445960495130308147156436998327553854387741014177421559585683382003377803158283603889312107837885491964835073892174406797445622388505256985237867456926792546588756970045576002345376035346727906264683596628903417932566383221754976804148878057310066885140776352202510584461556988179369177560403923399529842871087532495739921906849249072433614545319458973155343802539527630971239359995893495205324483418191744545506744253222956232506980824457995662900264427265978239540089825733734306363153471606200228841997928021468359645661221933848545854596097640552489404777927679709089475954033350287287833943519423030861868256961619722983499902810335
a = [35,51,91,115,123,187,235,267,403,427]
b = [427,403,267,235,187,123,115,91,51,35]

def roots_of_unity(e, phi, n, rounds=250):
# Divide common factors of `phi` and `e` until they're coprime.
phi_coprime = phi
while gcd(phi_coprime, e) != 1:
phi_coprime //= gcd(phi_coprime, e)

# Don't know how many roots of unity there are, so just try and collect a bunch
roots = set(pow(i, phi_coprime, n) for i in range(1, rounds))

assert all(pow(root, e, n) == 1 for root in roots)
return roots, phi_coprime

start_time = time.time()
for D in b:
p, q = factorize(n, D)

assert p*q == n
# n is prime
# Problem: e and phi are not coprime - d does not exist
phi = (p - 1) * (q-1)

# Find e'th roots of unity modulo n
roots, phi_coprime = roots_of_unity(e, phi, n)

# Use our `phi_coprime` to get one possible plaintext
d = inverse_mod(e, phi_coprime)
pt = pow(c, d, n)
assert pow(pt, e, n) == c

# Use the roots of unity to get all other possible plaintexts
pts = [(pt * root) % n for root in roots]
pts = [long_to_bytes(int(pt)) for pt in pts]

for pt in pts:
if b'flag' in pt:
end_time = time.time()
print(pt, 'time:', end_time-start_time)
break

flag{2c8a995547553aa788b43f26a57111edb2588304}

H05WC.png

PS:倒着遍历a有奇效