文章目录
easy_factor1
task.py
python
from Crypto.Util.number import *
from Crypto.Util.Padding import *
from Crypto.Cipher import AES
from hashlib import sha256
from random import *
from secret import flag
p,q,r = getPrime(256),getPrime(256),getPrime(256)
n = p*q*r
phi = (p-1)*(q-1)*(r-1)
key = sha256(str(p+q+r).encode()).digest()
enc = AES.new(key, AES.MODE_ECB)
c = enc.encrypt(pad(flag,16))
print("n =",n)
print("hint =",getrandbits(256)*phi**3)
print("c =",c)
'''
n = ...
hint = ...
c = b'...'
'''
analysis
n = p q r → φ ( n ) = ( p − 1 ) ( q − 1 ) ( r − 1 ) → h i n t = x ⋅ φ ( n ) 3 n=pqr\rightarrowφ(n)=(p-1)(q-1)(r-1)\rightarrow hint=x\cdotφ(n)^3 n=pqr→φ(n)=(p−1)(q−1)(r−1)→hint=x⋅φ(n)3
i f g c d ( a , n ) = 1 t h e n a φ ( n ) ≡ 1 ( m o d n ) → 2 h i n t = 2 x ⋅ φ ( n ) 3 ≡ 1 ( m o d n ) if\quad gcd(a,n)=1\quad then\quad a^{φ(n)}\equiv 1\pmod{n} \rightarrow 2^{hint}=2^{x\cdotφ(n)^3}\equiv1\pmod n ifgcd(a,n)=1thenaφ(n)≡1(modn)→2hint=2x⋅φ(n)3≡1(modn)
f a c t o r ( h i n t ) = x 1 e 1 ⋅ x 2 e 2 ⋅ ⋯ ⋅ x m e m → i f e i = 3 t h e n ( x i ∣ p − 1 ) ∧ ( x i ∤ q − 1 ) ∧ ( x i ∤ r − 1 ) factor(hint)=x_1^{e_1}\cdot x_2^{e_2}\cdot \cdots \cdot x_m^{e_m}\rightarrow if\quad e_i=3\quad then\quad (x_i|p-1)\land (x_i\nmid q-1)\land (x_i\nmid r-1) factor(hint)=x1e1⋅x2e2⋅⋯⋅xmem→ifei=3then(xi∣p−1)∧(xi∤q−1)∧(xi∤r−1)
- 简单说就是,我们分解 h i n t = 2 11 ⋅ 3 6 ⋅ 7 3 ⋅ 13 6 ⋅ 41 3 ⋅ 79 3 ⋅ 83 3 ⋅ 277 3 ⋅ 248701 3 ⋅ ⋯ hint=2^{11}·3^6·7^3·13^6·41^3·79^3·83^3·277^3·248701^3·\cdots hint=211⋅36⋅73⋅136⋅413⋅793⋅833⋅2773⋅2487013⋅⋯,其中指数为 3 3 3的底数就意味着其是 ( p − 1 ) / ( q − 1 ) / ( r − 1 ) (p-1)/(q-1)/(r-1) (p−1)/(q−1)/(r−1)中其中一个数的一个因子并且不能整除另外两个数字。不妨设 7 ∣ ( p − 1 ) 7\mid (p-1) 7∣(p−1),那么就有 7 ∤ ( q − 1 ) ∧ 7 ∤ ( r − 1 ) 7\nmid(q-1)\land7\nmid(r-1) 7∤(q−1)∧7∤(r−1)。
h i n t ′ = h i n t 7 3 → h i n t ′ = x ′ ( q − 1 ) ( r − 1 ) = x ′ φ ( q ⋅ r ) → [ φ ( q ⋅ r ) ∣ h i n t ′ ] ∧ [ φ ( n ) ∤ h i n t ′ ] hint'={hint\over 7^3}\rightarrow hint'=x'(q-1)(r-1)=x'φ(q\cdot r)\rightarrow [φ(q\cdot r)\mid hint']\land[φ(n)\nmid hint'] hint′=73hint→hint′=x′(q−1)(r−1)=x′φ(q⋅r)→[φ(q⋅r)∣hint′]∧[φ(n)∤hint′]
a h i n t ′ ≡ 1 ( m o d q ⋅ r ) ∧ a h i n t ′ ≢ 1 ( m o d n ) → g c d ( a h i n t ′ − 1 , n ) = q ⋅ r a^{hint'}\equiv 1\pmod{q\cdot r}\land a^{hint'}\not\equiv 1\pmod{n}\rightarrow gcd(a^{hint'}-1,n)=q\cdot r ahint′≡1(modq⋅r)∧ahint′≡1(modn)→gcd(ahint′−1,n)=q⋅r - 以此类推就可以完成 n n n的分解最终解密获得 f l a g flag flag,这里我们可以本地测试一下上面的推论
test.py
python
from Crypto.Util.number import getPrime, GCD
import random
"""
p = getPrime(256); q = getPrime(256); r = getPrime(256)
n = p * q * r
phi = (p - 1) * (q - 1) * (r - 1)
x = random.getrandbits(256)
hint = x * phi ** 3
print(f"p = {p}")
print(f"q = {q}")
print(f"r = {r}")
print(f"n = {n}")
print(f"hint = {hint}")
"""
p = 73608154003061233104177509387667712211557064770723977386548374466018717192211
q = 94558431882119069067217274911370009404045898851791183353228750362715589640147
r = 70581840519696884460882863496740725413786323150873495056810067996583082557887
n = 491268781193129960637873722186856651832533559182849470367350757095097164398651789139907234039979192347999125267900789978376604384889541436299631192780916367902465974295365015386920260079419708547502160650220530780165493600507149079
hint = 13098743114530789703597219713107085796520075379808786410757706269259451742619034622984586566572470190522835532374813542920370516639546248670300891042455270884034518169821662645883966782375677166303596540082369533556864829012023630321150994058015559180716134081103460987909004798177266305382927577141165815403830027261866872151179894054244594900044178344542540130615696747850182011031423575194653049201446575648199265169961384947891544790692027162283512632649095204860643424194518427208015551752621876099668873856206349147490976155046961244886400609569736076498371549757287610670364783154820252971817778620125915467648828720104345023860484790099710704222910035709147390668060770216332697505967362622031619959326861256777044942769591630740968754002556698752210461239360000
# 2^9 · 3^3 · 5^4 · 17^3 · 167^3 · 317^3 · 397^3 · 313783^3
# temp(hint')
temp = hint // (17 ** 3)
a = 2
# print(pow(a, temp, n) == 1) # False
# print(n // GCD(pow(a, temp, n) - 1, n)) # 73608154003061233104177509387667712211557064770723977386548374466018717192211
# print(pow(a, temp, q * r) == 1) # True
exp.py
python
from Crypto.Cipher import AES
from Crypto.Util.number import GCD
from Crypto.Util.Padding import unpad
import hashlib
n = 343127312894441264623060100705188723106648253383902349620699412384677995734576572885137280031507308915752070128528949423639735964709160841591038148069185325450544546735392923674211031016035209702254447128968565740534765322198664691
hint = 3802744632475774666777934738986183209966233570124815804333822490240409933768208822899072601181527365734196352249978937639454658680559993507805820991037544059215540360338084909833242583087617315128513337647913472696515770688338805196215328080662137260951972365100322795737835152857750114216709340410268143017180826135339564387228460663261697814425298725805568817218360964967025967384766127098203664964210047103829182895016532403825215903779806760754721373523135367007867453212189953817229696304611549977864533229540971457717668560698088917340909962348110683581294453903261530189579223087858081200349343639420534779115290433982968345085704202494045885911950427043282588446343291558819683037970053828479057449781943479407877748772895179095205885377333120540311815022381056
# hint = 2^11 · 3^6 · 7^3 · 13^6 · 41^3 · 79^3 · 83^3 · 277^3 · 248701^3
c = b';#\x1b\xa6R\xe2\x1d\x9dpf\x8e\xda\xe4\x14\x9a\xfb\tr\x99\x8a\xc9r\x03C\xb58Zb\x97\x0b\xc7S\x0fa\x88\xb4\xe4\x16.M\x92\x94\x94\x8b\xa9Ki\x9b\xe4\xe9d5\xa3~\x1a\x9cx\x03\xdc\x1f\x87\x14E\x90'
a = 2
temp = hint // (7 ** 3)
p = n // GCD(pow(a, temp, n) - 1, n)
temp = hint // (277 ** 3)
q = n // GCD(pow(a, temp, n) - 1, n)
assert p != q
r = n // p // q
key = hashlib.sha256(str(p + q + r).encode()).digest()
cipher = AES.new(key=key, mode=AES.MODE_ECB)
print(unpad(cipher.decrypt(c), 16))
# b'NSSCTF{Just_simply_try_t0_divid3_s0m3_f4ct0rs_0f_phi}'
summary
- 本道题木一般情况下遇到的话应该可以叫做欧拉分解 , φ ( n ) φ(n) φ(n)的指数为 1 1 1的模板如下:
python
# sage 10.7
def factorize_multi_prime(N, phi):
"""
Recovers the prime factors from a modulus if Euler's totient is known.
This method works for a modulus consisting of any number of primes, but is considerably be slower than factorize.
More information: Hinek M. J., Low M. K., Teske E., "On Some Attacks on Multi-prime RSA" (Section 3)
:param N: the modulus
:param phi: Euler's totient, the order of the multiplicative group modulo N
:return: a tuple containing the prime factors
"""
prime_factors = set()
factors = [N]
while len(factors) > 0:
# Element to factorize.
N = factors[0]
w = randrange(2, N - 1)
i = 1
while phi % (2 ** i) == 0:
sqrt_1 = pow(w, phi // (2 ** i), N)
if sqrt_1 > 1 and sqrt_1 != N - 1:
# We can remove the element to factorize now, because we have a factorization.
factors = factors[1:]
p = gcd(N, sqrt_1 + 1)
q = N // p
if is_prime(p):
prime_factors.add(p)
elif p > 1:
factors.append(p)
if is_prime(q):
prime_factors.add(q)
elif q > 1:
factors.append(q)
# Continue in the outer loop
break
i += 1
return tuple(prime_factors)
easy_factor2
task.py
python
from Crypto.Util.number import *
from random import *
from gmpy2 import *
from secret import flag
m = bytes_to_long(flag)
def gen_prime(bits, common_bits):
shift = bits - common_bits
while(True):
high = ((1<<(common_bits-1)) + getrandbits(common_bits-1)) << shift
p = high + 2 * getrandbits(shift-1) + 1
q = high + 2 * getrandbits(shift-1) + 1
if(isPrime(p) and isPrime(q)):
return p,q
p, q = gen_prime(1024, 350)
n = p * q
leak = (pow(p, q, n) + pow(q, p, n)) & ((1 << 300) - 1)
e = 65537
c = pow(m,e,n)
print("n =",n)
print("e =",e)
print("c =",c)
print("leak =",leak)
# n = ...
# e = ...
# c = ...
# leak = ...
analysis
- 由 ( p , q ) (p,q) (p,q)的特殊生成方式可知, p , q p,q p,q的高 350 350 350位是相同的 1024 1024 1024位的大素数:
test.py
python
from Crypto.Util.number import isPrime
import random
def gen_prime(bits,common_bits):
shift = bits - common_bits
while(True):
high = ((1<<(common_bits-1)) + random.getrandbits(common_bits-1)) << shift
p = high + 2 * random.getrandbits(shift - 1) + 1
q = high + 2 * random.getrandbits(shift - 1) + 1
if(isPrime(p) and isPrime(q)):
return p, q
p, q = gen_prime(1024, 350)
print("gen_prime done.")
p = bin(p)[2:]
q = bin(q)[2:]
for i in range(400):
if p[i] != q[i]:
print(f"i = {i}")
break
# gen_prime done.
# i = 351
- 于此同时,我们就需要分析 l e a k leak leak的真实泄露信息:
F e r m a t ′ s l i t t l e t h e o r e m → p q ≡ p ( m o d q ) Fermat's\ little\ theorem\rightarrow p^q\equiv p\pmod {q} Fermat′s little theorem→pq≡p(modq)p q ≡ 0 ( m o d p ) \] ∧ \[ p q ≡ p ( m o d q ) \] → C R T p q ≡ p ( m o d n ) → ( p q + q p ) ≡ p + q ( m o d ( p ⋅ q ) ) \[p\^q\\equiv0\\pmod{p}\]\\land\[p\^q\\equiv p\\pmod {q}\]\\xrightarrow{CRT}p\^q\\equiv p\\pmod{n}\\rightarrow (p\^q+q\^p)\\equiv p+q\\pmod{(p\\cdot q)} \[pq≡0(modp)\]∧\[pq≡p(modq)\]CRT pq≡p(modn)→(pq+qp)≡p+q(mod(p⋅q)) `test.py`
from Crypto.Util.number import getPrime
p = getPrime(1024); q = getPrime(1024)
n = p * q
print(p + q == pow(p, q, n) + pow(q, p, n)) # True
* l e a k leak leak就是 p + q p+q p+q的低 300 300 300位,我们该怎么 f a c t o r ( n ) factor(n) factor(n)?
p = x + p l o w ; q = x + q l o w → n = p ⋅ q = x 2 + x ⋅ ( p + q ) + p l o w ⋅ q l o w p=x+p_{low};q=x+q_{low}\\rightarrow n=p\\cdot q=x\^2+x\\cdot(p+q)+p_{low}\\cdot q_{low} p=x+plow;q=x+qlow→n=p⋅q=x2+x⋅(p+q)+plow⋅qlow
* 接下来就是**费马分解** 的知识点了,提到**费马分解** ,我觉得举出一个比较好的实例的话就是最初入门 C r y p t o Crypto Crypto的时候可能会遇到`p=nextprime(q)`此类两个素数非常接近的赛题,其分解思想如下:
n = p ⋅ q = ( p + q 2 ) 2 − ( p − q 2 ) 2 ; l e t a = p + q 2 , b = p − q 2 → n = ( a + b ) ( a − b ) n=p\\cdot q=({p+q\\over2})\^2-({p-q\\over2})\^2;let\\quad a={p+q\\over2},b={p-q\\over2}\\rightarrow n=(a+b)(a-b) n=p⋅q=(2p+q)2−(2p−q)2;leta=2p+q,b=2p−q→n=(a+b)(a−b)
s e a r c h a f r o m n ↑ search\\quad a\\quad from\\quad \\sqrt{n}↑ searchafromn ↑
* 也就是从 n \\sqrt{n} n 开始逐渐增大寻找 a a a,直到找到的 a a a满足 a 2 − n a\^2-n a2−n是一个完全平方数就意味着我们找到了正确的 ( a , b ) (a,b) (a,b),进而分解 n n n,而这个分解算法的速度就取决于 a ( p + q 2 ) − n a({p+q\\over2})-\\sqrt{n} a(2p+q)−n 的大小, ( p , q ) (p,q) (p,q)越接近,则 a − n a-\\sqrt{n} a−n 越小,该分解算法成功的可能性就越高。
* 对于这道题目而言,或者说是 ( p , q ) (p,q) (p,q)接近的定义就可以理解为 ( p , q ) (p,q) (p,q)的高位("高位更能决定大小"),我们可以测试比较一下对于这道题目而言 a a a与 n \\sqrt{n} n 的高多少位相同,这样子我们就可以通过题目中的 n \\sqrt{n} n 获得多少位准确的 p + q p+q p+q了,再结合 l e a k leak leak进行准确的 p + q p+q p+q的计算:
`test.py`
```python
from Crypto.Util.number import isPrime
import random
import gmpy2
def gen_prime(bits,common_bits):
shift = bits - common_bits
while(True):
high = ((1<<(common_bits-1)) + random.getrandbits(common_bits-1)) << shift
p = high + 2*random.getrandbits(shift-1) + 1
q = high + 2*random.getrandbits(shift-1) + 1
if(isPrime(p) and isPrime(q)):
return p,q
p, q = gen_prime(1024, 350)
print("gen_prime done.")
n = p * q
nn = 2 * gmpy2.iroot(n, 2)[0]
temp = p + q
# print(temp.bit_length()) # 1025 1025
temp = bin(temp)[2:]
nn = bin(nn)[2:]
for i in range(1024):
if temp[i] != nn[i]:
print(f"i = {i}")
break
# 700 702 711 710 705
- 这里我们可以发现,我们可以通过 n \sqrt{n} n 得到 a a a的高 698 698 698位,以及 l e a k leak leak可以得到 p + q p+q p+q的低 300 300 300位,相比于完整的 a a a,我们还缺失中间的 1025 − 700 − 300 = 25 1025-700-300=25 1025−700−300=25位未知,属于可爆破的范围,因此我们可以顺理成章地找到 p + q p+q p+q,进而 a = p + q 2 a={p+q\over2} a=2p+q,最终分解 n n n求解 f l a g flag flag。
exp.py
python
from Crypto.Util.number import long_to_bytes
from tqdm import tqdm
import gmpy2
n = 20304817598463991883487911425007927214135740826150882692657608404060781116387976327509281041677948119173928648751205240686682904704601086882134602075008186227364732648337539221512524800875230120183740426722086488143679856177002068856911689386346260227545638754513723197073169314634515297819111746527980650406024533140966706487847121511407833611739619493873042466218612052791074001203074880497201822723381092411392045694262494838335876154820241827541930328508349759776586915947972105562652406402019214248895741297737940426853122270339018032192731304168659857343755119716209856895953244774989436447915329774815874911183
e = 65537
c = 7556587235137470264699910626838724733676624636871243497222431220151475350453511634500082904961419456561498962154902587302652809217390286599510524553544201322937261018961984214725167130840149912862814078259778952625651511254849935498769610746555495241583284505893054142602024818465021302307166854509140774804110453227813731851908572434719069923423995744812007854861031927076844340649660295411912697822452943265295532645300241560020169927024244415625968273457674736848596595931178772842744480816567695738191767924194206059251669256578685972003083109038051149451286043920980235629781296629849866837148736553469654985208
leak = 1511538174156308717222440773296069138085147882345360632192251847987135518872444058511319064
nn = 2 * gmpy2.iroot(n, 2)[0]
pq_high = nn >> 325 << 325
for mid in tqdm(range(2 ** 26)):
pq = pq_high + mid * 2 ** 300 + leak
a = pq // 2
temp = a ** 2 - n
if temp > 0 and gmpy2.is_square(temp):
b = gmpy2.iroot(temp, 2)[0]
p = a + b
q = n // p
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
m = pow(c, d, n)
print(long_to_bytes(m))
break
# "NSSCTF{JUST_@pply_Fermat's_factorization_method_W1tH_Brut3F0rce!}"
easy_factor3
task.py
python
from Crypto.Util.number import *
from secret import flag
def gen_noisy_sum_of_base(m, p):
sum = 0
while(m):
sum += m % p
m //= p
return sum//1000
flag = bytes_to_long(flag)
e = 65537
p = getPrime(256)
q = getPrime(256)
n = p * q
m1 = getRandomNBitInteger(2048)
m2 = getRandomNBitInteger(2048)
print("m1 =", m1)
print("m2 =", m2)
print("sum1 =", gen_noisy_sum_of_base(m1, p))
print("sum2 =", gen_noisy_sum_of_base(m2, p))
print("n =", n)
print("c =", pow(flag, e, n))
'''
m1 = ...
m2 = ...
sum1 = ...
sum2 = ...
n = ...
c = ...
'''
analysis
g e n _ n o i s y _ s u m _ o f _ b a s e ( m , p ) → m = a n p n + a n − 1 p n − 1 + ⋯ + a 1 p 1 + a 0 gen\_noisy\_sum\of\base(m,p)\rightarrow m=a_np^n+a{n-1}p^{n-1}+\cdots +a_1p^1+a_0 gen_noisy_sum_of_base(m,p)→m=anpn+an−1pn−1+⋯+a1p1+a0
s u m = ⌊ a n + a n − 1 + ⋯ + a 1 + a 0 1000 ⌋ sum=\lfloor{a_n+a{n-1}+\cdots +a_1+a_0\over 1000}\rfloor sum=⌊1000an+an−1+⋯+a1+a0⌋
- 我们可以通过现有的 s u m sum sum通过 s u m = 1000 ⋅ s u m + b [ b ∈ [ 0 , 1000 ) ] sum=1000\cdot sum + b[b\in[0,1000)] sum=1000⋅sum+b[b∈[0,1000)]爆破 b b b还原得到 s u m = a n + a n − 1 + ⋯ + a 1 + a 0 sum=a_n+a_{n-1}+\cdots+a_1+a_0 sum=an+an−1+⋯+a1+a0。
m − s u m = a n ( p n − 1 ) + a n − 1 ( p n − 1 − 1 ) + ⋯ + a 1 ( p − 1 ) m-sum=a_n(p^n-1)+a_{n-1}(p^{n-1}-1)+\cdots + a_1(p-1) m−sum=an(pn−1)+an−1(pn−1−1)+⋯+a1(p−1)
m 1 − s u m 1 = a 1 , n ( p n − 1 ) + a 1 , n − 1 ( p n − 1 − 1 ) + ⋯ + a 1 , 1 ( p − 1 ) (1) m_1-sum_{1}=a_{1,n}(p^n-1)+a_{1,n-1}(p^{n-1}-1)+\cdots +a_{1,1}(p-1)\tag{1} m1−sum1=a1,n(pn−1)+a1,n−1(pn−1−1)+⋯+a1,1(p−1)(1)
m 2 − s u m 2 = a 2 , n ( p n − 1 ) + a 2 , n − 1 ( p n − 1 − 1 ) + ⋯ + a 2 , 1 ( p − 1 ) (2) m_2-sum_2=a_{2,n}(p^n-1)+a_{2,n-1}(p^{n-1}-1)+\cdots+a_{2,1}(p-1)\tag{2} m2−sum2=a2,n(pn−1)+a2,n−1(pn−1−1)+⋯+a2,1(p−1)(2)
( p − 1 ) ∣ ( p i − 1 ) [ i ≥ 1 ] (3) (p-1)\mid (p^i-1)[i≥1]\tag{3} (p−1)∣(pi−1)[i≥1](3)
( 1 ) ∧ ( 2 ) ∧ ( 3 ) → g c d ( m 1 − s u m 1 , m 2 − s u m 2 ) = p − 1 (1)\land(2)\land(3)\rightarrow gcd(m_1-sum_1,m_2-sum_2)=p-1 (1)∧(2)∧(3)→gcd(m1−sum1,m2−sum2)=p−1
exp.py
python
from Crypto.Util.number import long_to_bytes, GCD, isPrime
e = 65537
m1 = 23145761572719481962762273155673006162798724771853359777738044204075205506442533110957905454673168677138390288946164925146182350082798412822843805544411533748092944111577005586562560198883223125408349637392132331590745338744632420471550117436081738053152425051777196723492578868061454261995047266710226954140246577840642938899700421187651113304598644654895965391847939886431779910020514811403672972939220544348355199254228516702386597854501038639792622830084538278039854948584633614251281566284373340450838609257716124253976669362880920166668588411500606044047589369585384869618488029661584962261850614005626269748136
m2 = 21293043264185301689671141081477381397341096454508291834869907694578437286574195450398858995081655892976217341587431170279280993193619462282509529429783481444479483042173879669051228851679105028954444823160427758701176787431760859579559910604299900563680491964215291720468360933456681005593307187729279478018539532102837247060040450789168837047742882484655150731188613373706854145363872001885815654186972492841075619196485090216542847074922791386068648687399184582403554320117303153178588095463812872354300214532980928150374681897550358290689615020883772588218387143725124660254095748926982159934321361143271090861833
sum1 = 309575642078438773208947649750793560438038690144069550000470706236111082406
sum2 = 303394719183577651416751448350927044928060280972644968966068528268042222965
n = 4597063839057338886607228486569583368669829061896475991448013970518668754752831268343529061846220181652766402988715484221563478749446497476462877699249731
c = 3253873276452081483545152055347615580632252871708666807881332670645532929747667442194685757039215506084199053032613562932819745309368748317106660561209205
for i in range(1000):
s1 = 1000 * sum1 + i
for j in range(1000):
s2 = 1000 * sum2 + j
pp = GCD(m1 - s1, m2 - s2)
p = pp + 1
if n % p == 0:
q = n // p
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
m = pow(c, d, n)
print(long_to_bytes(m))
exit(0)
# b'NSSCTF{M@k3_U53_0F_GCD_beHinD_th3_p-Base!}'
easy_factor4
task.py
python
from Crypto.Util.number import *
from Crypto.Util.Padding import *
from Crypto.Cipher import AES
from hashlib import sha256
from random import *
from secret import flag
p = getPrime(256)
q = getPrime(256)
n = p*q
phi = (p - 1) * (q - 1)
e = 65537
d = inverse(e, phi)
key = sha256(str(p + q).encode()).digest()
enc = AES.new(key, AES.MODE_ECB)
c = enc.encrypt(pad(flag, 16))
hint = getPrime(20) * d ** 3 + getPrime(128) * phi ** 2
print("n =",n)
print("c =",c)
print("hint =",hint)
'''
n = ...
c = b'...'
hint = ...
'''
analysis
d = e − 1 ( m o d φ ( n ) ) ; h i n t = a ⋅ d 3 + b ⋅ φ ( n ) 2 d=e^{-1}\pmod{φ(n)};hint=a\cdot d^3+b\cdot φ(n)^2 d=e−1(modφ(n));hint=a⋅d3+b⋅φ(n)2
e ⋅ d = k φ ( n ) + 1 → e 3 ⋅ h i n t = a ⋅ ( e ⋅ d ) 3 + b ⋅ e 3 ⋅ φ ( n ) 2 = a ⋅ ( k 3 φ ( n ) 3 − k φ ( n ) + 1 ) + b ′ ⋅ φ ( n ) 2 e\cdot d=kφ(n)+1\rightarrow e^3\cdot hint=a\cdot (e\cdot d)^3+b\cdot e^3\cdot φ(n)^2=a\cdot (k^3φ(n)^3-kφ(n)+1)+b'\cdot φ(n)^2 e⋅d=kφ(n)+1→e3⋅hint=a⋅(e⋅d)3+b⋅e3⋅φ(n)2=a⋅(k3φ(n)3−kφ(n)+1)+b′⋅φ(n)2
→ φ ( n ) ∣ ( e 3 ⋅ h i n t − a ) [ a ∈ ( 2 19 , 2 20 ) ] → 2 e 3 ⋅ h i n t − a ≡ 1 ( m o d n ) \rightarrow φ(n)\mid (e^3\cdot hint - a)[a\in(2^{19},2^{20})]\rightarrow 2^{e^3\cdot hint-a}\equiv 1\pmod {n} →φ(n)∣(e3⋅hint−a)[a∈(219,220)]→2e3⋅hint−a≡1(modn)
- 也就是说,如果我们能得到争取的 e 3 ⋅ h i n t − a e^3\cdot hint-a e3⋅hint−a,问题就转化为我们在已知 K φ ( n ) Kφ(n) Kφ(n)的情况下分解 n n n的欧拉分解了,可以使用
easy_factor1中的模板,也可以在factordb.com分解后找到指数为 1 1 1的底数进行计算,原理在easy_factor1已经进行解释。
exp.py
python
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from tqdm import tqdm
from Crypto.Util.number import GCD
import hashlib
e = 65537
n = 8218998145909849489767589224752145194323996231101223014114062788439896662892324765430227087699807011312680357974547103427747626031176593986204926098978521
c = b'\x9a \x8f\x96y-\xb4\tM\x1f\xe6\xcc\xef\xd5\x19\xf26`|B\x10N\xd7\xd0u\xafH\x8d&\xe3\xdbG\x13\x8e\xea\xc0N\n\r\x91\xdc\x95\x9b\xb1Ny\xc1\xc4'
hint = 1860336365742538749239400340012599905091601221664081527583387276567734082070898348249407548568429668674672914754714801138206452116493106389151588267356258514501364109988967005351164279942136862087633991319071449095868845225164481135177941404709110974226338184970874613912364483762845606151111467768789248446875083250614540611690257121725792701375153027230580334095192816413366949340923355547691884448377941160689781707403607778943438589193122334667641037672649189861
"""
temp = e ** 3 * hint
for a in tqdm(range(2 ** 19, 2 ** 20)):
if pow(2, temp - a, n) == 1:
print(f"a = {a}")
print(f"Kφ(n) = {temp - a}")
break
a = 565237
Kφ(n) = ...
"""
temp = 523662105838677660582686635196127963655253087955793573042216743904347453375547362107072436544833745710962955346057622029955845068053732688144460700231984435506145110687285329625777406301427939686319955136093297689967125429241176888393605984367539796791189337678238063753130426457804100078882620588797225584627566066946728209766829451305616636855293925878620009475826965348891907357396982278118427951914602953964780161369588355268500813612249886658302938073620187213292887244032496
# temp = 2^4 · 3^4 · 11 · 31 · 73 · 101 · 137 · 179 · 397 · 1871 · 6113 · 74713 · 1050887 · 106031326409 · 1081244969177 · 7836595938569 · 9491217938233
temp = temp // 101
assert pow(2, temp, n) != 1
p = GCD(pow(2, temp, n) - 1, n)
q = n // p
key = hashlib.sha256(str(q + p).encode()).digest()
cipher = AES.new(key=key, mode=AES.MODE_ECB)
print(unpad(cipher.decrypt(c), 16))
# b'NSSCTF{H0w_70_F4ct0R_N_7h1s_tim3?}'