题目:
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- from Crypto.Util.number import getPrime, bytes_to_long
- from secret import flag
- import gmpy2
-
- m = bytes_to_long(flag)
- p1 = getPrime(256)
- p2 = gmpy2.next_prime(p1)
- q1 = getPrime(256)
- q2 = gmpy2.next_prime(q1)
- n = p1*p2*q1*q2
- e = 65537
- c = pow(m, e, n)
- print "n = %s" % str(n)
- print "c = %s" % str(c)
-
- # n = 64167976067579049714960625453369319623574147507612434283986049223337768780480307767872484679214997588434480836733456745370562072077109044069294552424055163225824033286416753073591864962033181307822913035174676405849974928866646899569297852568167037383571518655075260561571463850326020102574832776970253538663
- # c = 61862798948167945139222097835309318688214053098609025632041946354708220281670731577734398373186075525909035569024535800893559811995294302363408878574730352951360726686941143742759917076156204564133401228995322937563878389120770732315714920284214472911769619065607001763986611359218449802649142381309774537696
-
利用费马定理,分解2组素数:
首先列出一个式子:n=p*q
,代换到上面提到的p=a-b
,q=a+b
,那么就是n=(a-b)*(a+b)
,可以发现其实就是n=a*a-b*b
,而b2不就是b的平方吗,所以有n=a*a-b2
。
a的值在整个爆破过程中是从小到大的,相应的,b的值也是从小到大的,因为b*b=a*a-n
,随着a的增大,b也会变大,而与之相应的,两个解:a-b
和a+b
,之间的差距也会变大,而在最开始爆破的时候我们可以认为b=0
,此时的a*a
相当于在0~n之间求解的最‘中间’,这样我们就可以明白了,这个脚本正是从n的平方根这个‘中间值’开始,逐渐向两边扫描,直到得到解或者a-b==0
,所以原理上它可以爆破出所有解。
这个脚本其实是一个爆破脚本,它会尝试每一种可能性,直到得到解,所以这个脚本也只能在初始值和解相近的时候使用。
好处就在于,这个脚本是一个爆破脚本,所以它能爆破出所有可能的解。
在本题中,n由4个质数因子组成,其中两个成对近似相等。
- p1*q1, p2*q2非常相近
- p1*q2, p2*q1非常相近
-
- n = (p1*q1)*(p2*q2) = (p1*q2)*(p2*q1)
-
- 在sqrt(n) 这个‘中间值’两侧可以暴力破解出p1*q1, p2*q2,p1*q2, p2*q1等4个因子,进一步求出p1,p2, q1, q2。
exp:
- from Crypto.Util.number import *
- from gmpy2 import *
-
- n = 64167976067579049714960625453369319623574147507612434283986049223337768780480307767872484679214997588434480836733456745370562072077109044069294552424055163225824033286416753073591864962033181307822913035174676405849974928866646899569297852568167037383571518655075260561571463850326020102574832776970253538663
- c = 61862798948167945139222097835309318688214053098609025632041946354708220281670731577734398373186075525909035569024535800893559811995294302363408878574730352951360726686941143742759917076156204564133401228995322937563878389120770732315714920284214472911769619065607001763986611359218449802649142381309774537696
- e = 65537
-
- def fermat_factorization(n):
- factor_list = []
- a,f = iroot(n,2)
-
- while(True):
- a += 1
- try:
- b,f = iroot(a*a - n, 2)
- except:
- pass
-
- if f: # b*b == a*a - n
- factor_list.append([a-b,a+b])
-
- if len(factor_list) == 2:
- break
- return factor_list
-
- factor_list = fermat_factorization(n)
- [p1q1,p2q2] = factor_list[0]
- [p1q2,p2q1] = factor_list[1]
- assert( p1q1*p2q2 == n)
- assert( p1q2*p2q1 == n)
-
- p1 = GCD(p1q1,p1q2)
- p2 = GCD(p2q1,p2q2)
- q1 = GCD(p1q1,p2q1)
- q2 = GCD(p1q2,p2q2)
-
- assert(isPrime(p1))
- assert(isPrime(p2))
- assert(isPrime(q1))
- assert(isPrime(q2))
- assert(p1*q1*p2*q2==n)
-
- phi = (p1 - 1) * (q1 - 1) * (p2 - 1) * (q2 - 1)
- d = inverse(e, phi)
- flag = pow(c, d, n)
- print(long_to_bytes(flag).decode())
-
- # CnHongKe{195a65b1-daa8-4786-b4f8-ca9e29d8804d}