kp = t^4 + t^3 + t^2 + t + 1997 - c1 p = gcd(mpz(kp), mpz(n)) qr = n // p assert isPrime(p)
此时,利用倍数关系,直接把$p$利用gcd()函数进行求解。
方程组求解-groebner_basis()
同样的操作,设置未知数。
利用groebner_basis()函数进行求解,此时必须三个方程才能求解对应未知量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
P.<x, t> = PolynomialRing(Zmod(qr)) f1 = t - 2915836867 f2 = 1997 - c2 f3 = 1997 - c3 for i in range(1, 20): f2 += (x * t) ^ i f3 += (x + t) ^ i G = [f1, f2, f3] I = Ideal(G) B = I.groebner_basis() print(B) res = [i.constant_coefficient() for i in B] print(res) q = int(res[2]) m = int(-res[0] % q) tt = -res[1] % q print(q) print(m)
求出m转字符,发现得不到结果,结果是m % q,猜测比q大,爆破一下。
1 2 3 4 5 6 7
for i inrange(0x1000000): v = long_to_bytes(m + i * q) # if b'ctf' in v: # print(v) ifall(0x20 <= k < 0x7ffor k in v): print(v,i) break
[DASCTF 2023 & 0X401]ezRSA
coppersmith-已知高位求解p
Franklin Reiter 相关信息攻击
coppersmith-已知高位求解p
$$ gift = P (Q >> 16) $$
$$ c_1 = pow(n, e, N) \equiv n^{e} \mod N $$
$$ c_2 = pow(secret, e, N) \equiv secret^{e} \mod N $$
$$ c_3 = pow(flag, e, n) \equiv flag^{e} \mod N $$
*已知,$N$,$gift$,$c_1$,$c_2$,$c_3$*,求解flag。
只能从gift入手,P高16位已知,又N = P * Q ,那么Q的高位也能得出,考虑到进位问题,可以将Q的高位位数求小一点(假设为x),之后再根据Q的高位和异或性质,又能求出P的高16 + x位,这里取x = 10,如此循环往复,最后大概剩6比特没恢复,枚举下即可。
# for i in range(64): # P = (P_h << 6) + i # if N % P == 0: # print(P) # break
ph = bin(gift)[2:][:16] + '0'*(512-16) ph = int(ph,2) x = bin(gift)[2:][17:] def fac(x,tp,tq): if len(x) == 0: return if tp*tq>N: return if N%(tp+1)==0: print(tp+1) return v = x[0] r = x[1:] l = len(r) if (tp+(1<<(l+1)))*(tq+(1<<(l+17)))<N: print(bin(tp)[:50]) print(bin(tq)[:50]) print(l) return if v == '0': fac(r, tp, tq) fac(r, tp+(1<<l), tq+(1<<(l+16))) else: fac(r, tp+(1<<l), tq) fac(r, tp, tq+(1<<(l+16))) #q第1位为1 x[0]=='0' tq = 1<<511 tp = ph + (1<<(512-16-1)) fac(x,tp,tq)
之后来到 flag == b"dasctf{" + secret + b"}"这一步。
已知bytes转long型相当于256进制,假设secret的长度为i,那么。
1 2 3
c2 = x ^ 11 c3 = (bytes_to_long(b'dasctf{' + b'\00' * i + b'}' ) * 256 ** (i + 1) + 256 * x) ^ 11 (其中x = secret , i = len(secret))
Franklin Reiter 相关信息攻击
把$n$先确定下来。
1 2 3 4 5 6 7 8 9 10 11 12 13
P = 8006847171912577069085166877758626954304824756138758266557706391662987806065132448544117840031499707938227955094109779732609035310252723066470330862622641 Q = N // P n = powmod(c1, int(invert(e, (P - 1) * (Q - 1))), N) # n = n + N # print(n) k = 0 while True: n = n + k * N if n % 2 == 1: print(n) break else: k += 1
相关信息攻击。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
# c2 = x ^ 11 # c3 = (bytes_to_long(b'dasctf{' + b'00' * i + b'}') * 256 ** (i + 1) + 256 * x) ^ 11 # x为secret, i = len(secret)
def GCD(a,b): if b == 0: return a.monic() else: return GCD(b,a % b) PR.<x> = PolynomialRing(Zmod(n)) for i in range(50): f1 = x ^ 11 - c2 f2 = (bytes_to_long(b'dasctf{' + b'\x00' * i + b'}') + 256 * x) ^ 11 - c3 if GCD(f1,f2)[0] != 1: secret = long_to_bytes(int(n - int(GCD(f1,f2)[0]))) flag = b'dasctf{' + secret + b'}' print(flag)
[宁波天一杯]rsa
构造满足条件的$f$,进行根的求解
Pollard_rho 算法
方程化简,模数分解
Relating: 羊城杯2021-easy_rsa
法1——构造$f$
构造$f = 2 \cdot g \cdot x + 1$ 在模$n$情况下有解。
1 2 3 4 5 6
R.<x> = Zmod(n)[] f = 2 * a * x + 1 g = int(f.monic().small_roots(X=2^51, beta=0.4)[0]) phi = (a - 1) * (g - 1) n = a * g d = invert(e, phi)
defrho(n): i = 1 whileTrue: a = getRandomRange(2, n) b = f(a, n) j = 1 whileTrue: p = GCD(abs(a - b), n) # print('{} in {} circle'.format(j, i)) if p == n: break elif p > 1: return (p, n // p) else: a = f(a, n) b = f(f(b, n), n) j += 1 i += 1
gh = (n - 1) // 2 # print(gh) h = 13570850594633462506426369052182298554140635599543685835372377476383038708650421475723391142118956001358520246769650699398490037618758005241062608387057439283872260149565854577827352267289963736282502923131251179400580891491236925451166755184695335564693793568286112036468975877609637392241679 g = 1346104232461691 phi = (a - 1) * (g - 1) n = a * g d = invert(e, phi)
# %% n = 36535558847082719901201561031181835346574576610950713924924272947759193576365817762980927638691696601293089537315055413746788190208875234794229119049056299551864869870291634941246362436491006904347559559494705922259007299126640817275929491680601926404543198957206717290905220235571289759182878331893962038379 c = 532997872940452282189043430008002793694788439822465302532208754231005799057972378308576109082463996551992533174546386979606697890310597738637156771564229 a = 2694858406312563434474553988904403597551484373358339092528913028454100111881368126493990657117571672510331411186745639563619323775673115439 e = 65537
# %% # 法1 # 构造f = 2 * g * x + 1 在模n情况下有解 from Crypto.Util.number import * from gmpy2 import *
R.<x> = Zmod(n)[] f = 2 * a * x + 1 g = int(f.monic().small_roots(X=2^51, beta=0.4)[0]) phi = (a - 1) * (g - 1) n = a * g d = invert(e, phi) m = powmod(c, d, n) print(m) print(long_to_bytes(m))
def rho(n): i = 1 while True: a = getRandomRange(2, n) b = f(a, n) j = 1 while True: p = GCD(abs(a - b), n) print('{} in {} circle'.format(j, i)) if p == n: break elif p > 1: return (p, n // p) else: a = f(a, n) b = f(f(b, n), n) j += 1 i += 1
# %% # 法3 # 神奇非预期 d = invert(e, a - 1) m = powmod(c, d, a) print(m) print(long_to_bytes(m))
# %% # 法4 # 直接利用等式进行分解,化简可得p*q - 1 = 2gh,g为51bit,h约为972bit,两者相差非常大,利用factordb/yafu进行分解 gh = (n - 1) // 2 # print(gh) h = 13570850594633462506426369052182298554140635599543685835372377476383038708650421475723391142118956001358520246769650699398490037618758005241062608387057439283872260149565854577827352267289963736282502923131251179400580891491236925451166755184695335564693793568286112036468975877609637392241679 g = 1346104232461691 phi = (a - 1) * (g - 1) n = a * g d = invert(e, phi) m = powmod(c, d, n) print(m) print(long_to_bytes(m))
f = 2^kbits*x + p0 f = f.monic() roots = f.small_roots(X=2^(nbits//2-kbits), beta=0.3) # find root < 2^(nbits//2-kbits) with factor >= n^0.3 if roots: x0 = roots[0] p = gcd(mpz(2^kbits*x0 + p0), mpz(n)) return ZZ(p)
deffind_p(d0, kbits, e, n): X = var('X')
for k inrange(1, e+1): results = solve_mod([e*d0*X - k*X*(n-X+1) + k*n == X], 2^kbits) for x in results: p0 = ZZ(x[0]) p = partial_p(p0, kbits, n) if p: return p
p = find_p(part_d, 1024-part_d.bit_length(), 7, n) # 12800335172378590918875662486524333103691215133150369430200420149970735808370081784433007260276277361253378071964953226360740601994258142232798414547092861
已知$p$之后那就直接转换成基础RSA了。
1 2 3 4 5 6 7
q = n // p d = invert(0x10001, (p-1)*(q-1)) m = powmod(c, d, n) print(m) print(unpad(long_to_bytes(m)).decode()) # 280953633736431747947064628051293908189096295024698457307220800187630550375386320255208827601751935813552184196283101709554718133038728081799604794900708412174536625884689548714026681568503654577602432205861968756823980122854293696554980209163635856940269021305243235482137890575873848821429361178108376901 # flag{54b5dc19-5037-46c3-8afe-45394f236852}
[HDCTF2023]math_rsa
二次剩余
主要通过生成参数的满足条件进行判定的。
1 2 3 4 5 6 7 8 9
r=getPrime(1024) assert r%4==3 # 可得r模4余3 p=getPrime(1024) assertpow(p,(r-1)//2,r)==1 # 满足二次剩余相关,勒让德符号为1,则,p是r的二次剩余 # 即 p = x^2 mod r a=pow(p,2,r) # a = p^2 mod r,
defTonelli_Shanks(a, p): """ no satisfy 3mod4,to calculate remainder or p is prime references: - https://rosettacode.org/wiki/Tonelli-Shanks_algorithm - [V&N2020]Easy RSA - 可等价于from sympy.ntheory.residue_ntheory import nthroot_mod(c, 2, r)-> x^2 = c mod r - 可等价于sagemath: f.roots() :param a: remainder :param p: modulo :return: r """ # STEP0 assertpow(a, (p-1)//2, p) == 1 if p % 4 == 3: return Fermat_2remainder(a, p) # STEP1 q = p - 1 s = 0 while q % 2 == 0: q = q // 2 s += 1 # STEP2 for z inrange(2, p): if Legendre_Symbol(z, p) == p - 1: c = pow(z, q, p) break # STEP3 r = pow(a, (q+1)//2, p) t = pow(a, q, p) m = s # STEP4 if t % p == 1: return r else: i = 0 while t % p != 1: temp = pow(t, 2**(i + 1), p) i += 1 if temp % p == 1: b = pow(c, 2**(m - i - 1), p) r = r*b % p c = b*b % p t = t*c % p m = i i = 0 return r
from pwn import * import string from hashlib import sha256
defproof_of_work(known: bytes,hashcode): """ know sha256(XXXX+known) == hashcode get the XXXX charset = letter + digits XXXX has four char """ charset = string.ascii_letters + string.digits for a in charset: for b in charset: for c in charset: for d in charset: guess = a + b + c + d if sha256(guess.encode()+known).hexdigest() == hashcode: return guess
num1 = 134186458247304184975418956047750205959249518467116558944535042073046353646812210914711656218265319503240074967140027248278994209294869476247136854741631971975560846483033205230015783696055443897579440474585892990793595602095853960468928457703619205343030230201261058516219352855127626321847429189498666288452 num2 = 142252615203395148320392930915384149783801592719030740337592034613073131106036364733480644482188684184951026866672011061092572389846929838149296357261088256882232316029199097203257003822750826537629358422813658558008420810100860520289261141533787464661186681371090873356089237613080052677646446751824502044253 n = 154128165952806886790805410291540694477027958542517309121222164274741570806324940112942356615458298064007096476638232940977238598879453357856259085001745763666030177657087772721079761302637352680091939676709372354103177660093164629417313468356185431895723026835950366030712541994019375251534778666996491342313 c = 9061020000447780498751583220055526057707259079063266050917693522289697419950637286020502996753375864826169562714946009146452528404466989211057548905704856329650955828939737304126685040898740775635547039660982064419976700425595503919207903099686497044429265908046033565745195837408532764433870408185128447965
from gmpy2 import * from Crypto.Util.number import long_to_bytes p = gcd(num1 + num2, n) q = n // p assert is_prime(p) assert is_prime(q) assert p % 4 == 3 assert q % 4 == 3 # print(p) # print(q) # print(p.bit_length()) # print(q.bit_length())
# 65536 == 2**16 cs = [c]
gcd, yp, yq = gcdext(p, q) for i inrange(16): ps = [] for cc in cs: mp = powmod(cc, (p + 1) // 4, p) mq = powmod(cc, (q + 1) // 4, q)
m1 = (yp * p * mq + yq * q * mp) % n m2 = n - m1 m3 = (yp * p * mq - yq * q * mp) % n m4 = n - m3 if m1 notin ps: ps.append(m1) if m2 notin ps: ps.append(m2) if m3 notin ps: ps.append(m3) if m4 notin ps: ps.append(m4)
cs = ps
for m in ps: flag = long_to_bytes(m) ifb'nss'in flag: print(flag) break # nssctf{W3lc0me_t0_nssctf_R0undll_w15h_U_can_have_Fun_t0day!!!#0919}
[DASCTF2020-4]not RSA
relating: [网鼎杯2020华南区复赛]paillier
paillier-2
$n$比较小,直接yafu分解或者费马分解都可以。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
c = 29088911054711509252215615231015162998042579425917914434962376243477176757448053722602422672251758332052330100944900171067962180230120924963561223495629695702541446456981441239486190458125750543542379899722558637306740763104274377031599875275807723323394379557227060332005571272240560453811389162371812183549 n = 6401013954612445818165507289870580041358569258817613282142852881965884799988941535910939664068503367303343695466899335792545332690862283029809823423608093
from gmpy2 import * from Crypto.Util.number import * # yafu p = 80006336965345725157774618059504992841841040207998249416678435780577798937819 q = 80006336965345725157774618059504992841841040207998249416678435780577798937447
L = lambda x: (x - 1) // n lam = (p - 1)*(q - 1) miu = invert(lam, n)
m = L(pow(c, int(lam), n*n)) * miu % n print(m) print(long_to_bytes(m))