|
楼主 |
发表于 2021-12-7 21:59:40
|
显示全部楼层
这道题涉及了三元copper,又学习了新的知识点。
题干:
- from Crypto.Util.number import *
- from random import randint, getrandbits
- from sympy import nextprime
- from secret import flag, secreteBitNum
- hint = bytes_to_long((f'secreteBitNum = {secreteBitNum}').encode())
- tmp_e = 65537
- tmp_p = getPrime(int(512))
- tmp_q = getPrime(int(512))
- tmp_N = tmp_p * tmp_q
- print(f'tmp_N = {tmp_N}')
- print(pow(hint, tmp_e, tmp_N))
- print(tmp_p >> 180)
- target_bits = int(256)
- prime = getPrime(target_bits)
- s = randint(prime>>10, prime)
- r = getrandbits(secreteBitNum)
- t = (r*(s^2 + 2*s)) % prime
- gifts = [3, 2]
- ks = [floor(target_bits * (gift / (gift + 1))) for gift in gifts]
- leak1 = s >> (target_bits - ks[0])
- leak2 = t >> (target_bits - ks[1])
- p = nextprime((s*(nextprime(s) * nextprime(r) + t)))
- q = getPrime(p.bit_length())
- N = p*q
- e = 65537
- m = bytes_to_long(flag)
- c = pow(m, e, N)
- print(f'prime = {prime}')
- print(f'c = {c}')
- print(f'N = {N}')
- print(f'leak1 = {leak1}')
- print(f'leak2 = {leak2}')
- """
- tmp_N = 67275889677378946734903321404206582364153218707836044936581311977721676158433934674861722018390091292542128885311842688233567992017423854706617140651934525455990460080562308585391373661331461122947028205118969966760791488914164391921330229025670176008518053339148134137770309365614255463111202481834705060173
- 40399377632586118650556149454962332599993544072289982576457293479237148938553095258299197606759611718110458893982875730643146645623512300513916266262798465380752083932871857821720398540072426424439422364690204675516506456125988918985863308292449915493404572808822346197667419207669315093927318993921905479596
- 4877155090632997781879191807827231697420271396210537080241322765167927413977000532975047982026915056
- prime = 82321753209337659641812698792368753307257174920293482309329229017641186204037
- c = 4327179356609269294409009935591795772603625779675971467878490086808144060225614005300908314649047950861015994603326121468330956776913366179511247457747179889685304469999218104955814145411915021238933150884498316563808220329632240175418452382843973948334446343545955570063628905102384071000832724697885872043017030707897928
- N = 43941665823196509154346632368475246193489316520677500866461851257383928558997955146720003171553041820199105630143274308184375615057136594812756966125202091119439909980006181740220827474838356621605513939553184451557022029987518161532780360148932769025277495283357745880781214097057768654158857096614016596756958574010574773
- leak1 = 4392924728395269190263639346144303703257730516994610750658
- leak2 = 838456777370923849008096179359487752850229097203212
- """
复制代码 首先分析题目流程:
第一部分如下:
- hint = bytes_to_long((f'secreteBitNum = {secreteBitNum}').encode())
- tmp_e = 65537
- tmp_p = getPrime(int(512))
- tmp_q = getPrime(int(512))
- tmp_N = tmp_p * tmp_q
- print(f'tmp_N = {tmp_N}')
- print(pow(hint, tmp_e, tmp_N))
- print(tmp_p >> 180)
复制代码 已知n、c和p的高位,可以利用一元的coppersmith求出secreteBitNum。
- ph = 4877155090632997781879191807827231697420271396210537080241322765167927413977000532975047982026915056
- pp = ph << 180
- print(pp)
- N = 67275889677378946734903321404206582364153218707836044936581311977721676158433934674861722018390091292542128885311842688233567992017423854706617140651934525455990460080562308585391373661331461122947028205118969966760791488914164391921330229025670176008518053339148134137770309365614255463111202481834705060173
- PR.<x> = PolynomialRing(Zmod(N))
- f = x+pp
- pl = f.small_roots(X=2^180,beta=0.4)[0]
- print(pl)
- p=pp+pl
- print(p)
- #p=7474218428506439131024561238447007658574698902527126414652353026654065729675401366440504060759323896095490193371294094265057254763085596066166150006638181
复制代码 求出p后,就可以正常流程解出明文secreteBitNum了。
- tmp_e = 65537
- tmp_N = 67275889677378946734903321404206582364153218707836044936581311977721676158433934674861722018390091292542128885311842688233567992017423854706617140651934525455990460080562308585391373661331461122947028205118969966760791488914164391921330229025670176008518053339148134137770309365614255463111202481834705060173
- tmp_p = 7474218428506439131024561238447007658574698902527126414652353026654065729675401366440504060759323896095490193371294094265057254763085596066166150006638181
- tmp_q = tmp_N // tmp_p
- phi = (tmp_q-1)*(tmp_p-1)
- d = gmpy2.invert(tmp_e, phi)
- c = 40399377632586118650556149454962332599993544072289982576457293479237148938553095258299197606759611718110458893982875730643146645623512300513916266262798465380752083932871857821720398540072426424439422364690204675516506456125988918985863308292449915493404572808822346197667419207669315093927318993921905479596
- m = pow(c,d,tmp_N)
- print(long_to_bytes(m))
- #b'secreteBitNum = 26'
复制代码 得到secreteBitNum = 26后,继续分析题目第二部分。经过运算得出ks=[192, 170]
- target_bits = int(256)
- prime = getPrime(target_bits)
- s = randint(prime>>10, prime)
- r = getrandbits(secreteBitNum)
- t = (r*(s^2 + 2*s)) % prime
- gifts = [3, 2]
- ks = [floor(target_bits * (gift / (gift + 1))) for gift in gifts]
- leak1 = s >> (target_bits - ks[0])
- leak2 = t >> (target_bits - ks[1])
复制代码 这是一个三元的copper,使用脚本解出s,r,t。
- import itertools
-
- def small_roots(f, bounds, m=1, d=None):
- if not d:
- d = f.degree()
-
- R = f.base_ring()
- N = R.cardinality()
-
- f /= f.coefficients().pop(0)
- f = f.change_ring(ZZ)
-
- G = Sequence([], f.parent())
- for i in range(m+1):
- base = N^(m-i) * f^i
- for shifts in itertools.product(range(d), repeat=f.nvariables()):
- g = base * prod(map(power, f.variables(), shifts))
- G.append(g)
-
- B, monomials = G.coefficient_matrix()
- monomials = vector(monomials)
-
- factors = [monomial(*bounds) for monomial in monomials]
- for i, factor in enumerate(factors):
- B.rescale_col(i, factor)
-
- B = B.dense_matrix().LLL()
-
- B = B.change_ring(QQ)
- for i, factor in enumerate(factors):
- B.rescale_col(i, 1/factor)
-
- H = Sequence([], f.parent().change_ring(QQ))
- for h in filter(None, B*monomials):
- H.append(h)
- I = H.ideal()
- if I.dimension() == -1:
- H.pop()
- elif I.dimension() == 0:
- roots = []
- for root in I.variety(ring=ZZ):
- root = tuple(R(root[var]) for var in f.variables())
- roots.append(root)
- return roots
- return []
-
- def trivariate():
- print('Trivariate')
- bounds = (1<<64, 1<<86, 1<<26)
- #roots = tuple(randrange(bound) for bound in bounds)
- R = Integers(prime)
- P.<sl, tl, r> = PolynomialRing(R)
- f = ((sh + sl)**2+2*(sh+sl))*r - (th + tl)
- print(small_roots(f, bounds,6))
-
- if __name__ == '__main__':
- prime = 82321753209337659641812698792368753307257174920293482309329229017641186204037
- leak1 = 4392924728395269190263639346144303703257730516994610750658
- leak2 = 838456777370923849008096179359487752850229097203212
- sh = leak1 << 64
- th = leak2 << 86
- trivariate()
- #[(2837580634489900859, 63360403616040741532234070, 29943235)]
复制代码 继续分析第三部分,第三部分就是简单的RSA加解密。得到flag:
- import gmpy2
- from Crypto.Util.number import *
- from sympy import nextprime
- leak1 = 4392924728395269190263639346144303703257730516994610750658
- leak2 = 838456777370923849008096179359487752850229097203212
- sl, tl, r = (2837580634489900859, 63360403616040741532234070, 29943235)
- sh = leak1 << 64
- th = leak2 << 86
- s = sh+sl
- t = th+tl
- p = nextprime((s*(nextprime(s) * nextprime(r) + t)))
- n = 43941665823196509154346632368475246193489316520677500866461851257383928558997955146720003171553041820199105630143274308184375615057136594812756966125202091119439909980006181740220827474838356621605513939553184451557022029987518161532780360148932769025277495283357745880781214097057768654158857096614016596756958574010574773
- q = n // p
- phi = (p-1)*(q-1)
- e = 65537
- d = gmpy2.invert(e, phi)
- c = 4327179356609269294409009935591795772603625779675971467878490086808144060225614005300908314649047950861015994603326121468330956776913366179511247457747179889685304469999218104955814145411915021238933150884498316563808220329632240175418452382843973948334446343545955570063628905102384071000832724697885872043017030707897928
- m = pow(c,d,n)
- print(long_to_bytes(m))
- #b'flag{bc33c490-4b95-11ec-ad04-00155d9a1603}'
复制代码 附上找到的coppersmith脚本,可用于1、2、3元copper,approximate_factor,boneh_durfee
- import itertools
-
- def small_roots(f, bounds, m=1, d=None):
- if not d:
- d = f.degree()
-
- R = f.base_ring()
- N = R.cardinality()
-
- f /= f.coefficients().pop(0)
- f = f.change_ring(ZZ)
-
- G = Sequence([], f.parent())
- for i in range(m+1):
- base = N^(m-i) * f^i
- for shifts in itertools.product(range(d), repeat=f.nvariables()):
- g = base * prod(map(power, f.variables(), shifts))
- G.append(g)
-
- B, monomials = G.coefficient_matrix()
- monomials = vector(monomials)
-
- factors = [monomial(*bounds) for monomial in monomials]
- for i, factor in enumerate(factors):
- B.rescale_col(i, factor)
-
- B = B.dense_matrix().LLL()
-
- B = B.change_ring(QQ)
- for i, factor in enumerate(factors):
- B.rescale_col(i, 1/factor)
-
- H = Sequence([], f.parent().change_ring(QQ))
- for h in filter(None, B*monomials):
- H.append(h)
- I = H.ideal()
- if I.dimension() == -1:
- H.pop()
- elif I.dimension() == 0:
- roots = []
- for root in I.variety(ring=ZZ):
- root = tuple(R(root[var]) for var in f.variables())
- roots.append(root)
- return roots
- return []
-
- def univariate():
- print('Univariate')
- bounds = (floor(N^.3),)
- roots = tuple(randrange(bound) for bound in bounds)
- R = Integers(N)
- P.<x> = PolynomialRing(R, 1)
- monomials = [x, x^2, x^3]
- f = sum(randrange(N)*monomial for monomial in monomials)
- f -= f(*roots)
- print(small_roots(f, bounds, m=7))
-
- def bivariate():
- print('Bivariate')
- bounds = (floor(N^.15), floor(N^.15))
- roots = tuple(randrange(bound) for bound in bounds)
- R = Integers(N)
- P.<x, y> = PolynomialRing(R)
- monomials = [x, y, x*y, x^2]
- f = sum(randrange(N)*monomial for monomial in monomials)
- f -= f(*roots)
- print(small_roots(f, bounds))
-
- def trivariate():
- print('Trivariate')
- bounds = (floor(N^.12), floor(N^.12), floor(N^.12))
- roots = tuple(randrange(bound) for bound in bounds)
- R = Integers(N)
- P.<x, y, z> = PolynomialRing(R)
- monomials = [x, y, x*y, x*z, y*z]
- f = sum(randrange(N)*monomial for monomial in monomials)
- f -= f(*roots)
- print(small_roots(f, bounds))
-
- def boneh_durfee():
- print('Boneh Durfee')
- bounds = (floor(N^.25), 2^1024)
- d = random_prime(bounds[0])
- e = inverse_mod(d, (p-1)*(q-1))
- roots = (e*d//((p-1)*(q-1)), (p+q)//2)
- R = Integers(e)
- P.<k, s> = PolynomialRing(R)
- f = 2*k*((N+1)//2 - s) + 1
- print(small_roots(f, bounds, m=3, d=4))
-
- def approximate_factor():
- print('Approximate factor')
- bounds = (floor(N^.05), floor(N^.05))
- roots = tuple(randrange(bound) for bound in bounds)
- R = Integers(N)
- P = PolynomialRing(R, len(bounds), 'x')
- f = sum(randrange(2^128)*x for x in P.gens())
- f += p - f(*roots)
- print(small_roots(f, bounds, m=2, d=4))
-
- if __name__ == '__main__':
- print('Generating primes')
- p = random_prime(2^1024)
- q = random_prime(2^1024)
- N = p*q
- univariate()
- bivariate()
- trivariate()
- boneh_durfee()
- approximate_factor()
复制代码
|
|