Crypto RSA中的数学技巧

本文围绕CTF比赛中的RSA题目展开,涵盖2022 ACTF、GKCTF 2021等多场赛事的题目。介绍了通过爆破、中间相遇攻击、二项式定理、费马定理等方法求解p、q值,还提及二分法逼近、coppersmith攻击等技巧,最后总结了解题的通用思路和方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2022 ACTF impossible RSA

from Crypto.Util.number import *
from Crypto.PublicKey import RSA

e = 65537
flag = b'ACTF{...}'

while True:
    p = getPrime(1024)
    q = inverse(e, p)
    if not isPrime(q):
        continue
    n = p * q;
    public = RSA.construct((n, e))
    with open("public.pem", "wb") as file:
        file.write(public.exportKey('PEM'))
    with open("flag", "wb") as file:
        file.write(long_to_bytes(pow(bytes_to_long(flag), e, n)))
    break

n , c , e 已知 q ∗ e ≡ 1 ( m o d p ) q ∗ e = 1 + k ∗ p p ∗ q ∗ e = p + k ∗ p ∗ p n ∗ e = p + k ∗ p ∗ p n ∗ e k = p k + p ∗ p n ∗ e k = p ∗ ( 1 k + p ) n,c,e已知\\q*e\equiv 1\pmod p\\q*e=1+k*p\\p*q*e=p+k*p*p\\n*e=p+k*p*p\\ \frac{n*e}{k}=\frac{p}{k}+p*p\\ \sqrt{\frac{n*e}{k}}=\sqrt{p*(\frac{1}{k}+p)} n,c,e已知qe1(modp)qe=1+kppqe=p+kppne=p+kppkne=kp+ppkne =p(k1+p)

爆破k求解

yihzilic = bytes_to_long(open("flag","rb").read())
n = 15987576139341888788648863000534417640300610310400667285095951525208145689364599119023071414036901060746667790322978452082156680245315967027826237720608915093109552001033660867808508307569531484090109429319369422352192782126107818889717133951923616077943884651989622345435505428708807799081267551724239052569147921746342232280621533501263115148844736900422712305937266228809533549134349607212400851092005281865296850991469375578815615235030857047620950536534729591359236290249610371406300791107442098796128895918697534590865459421439398361818591924211607651747970679849262467894774012617335352887745475509155575074809
e = 65537
for k in range(2,10000000):
    q = gmpy2.iroot(n*e//k,2)[0]
    p = n//q
    if p == 1:
        continue
    if p*q == n:
        d = gmpy2.invert(e,(p-1)*(q-1))
        print(long_to_bytes(pow(c,d,n)))
b'ACTF{F1nD1nG_5pEcia1_n_i5

q ∗ e ≡ 1 ( m o d p ) − > n ∗ e k = p ∗ ( 1 k + p ) q*e\equiv 1\pmod p->\sqrt{\frac{n*e}{k}}=\sqrt{p*(\frac{1}{k}+p)} qe1(modp)>kne =p(k1+p)

2022 ACTF RSA LEAK

from sage.all import *
from secret import flag
from Crypto.Util.number import bytes_to_long

def leak(a, b):
    p = random_prime(pow(2, 64))
    q = random_prime(pow(2, 64))
    n = p*q
    e = 65537
    print(n)
    print((pow(a, e) + pow(b, e) + 0xdeadbeef) % n)

def gen_key():
    a = randrange(0, pow(2,256))
    b = randrange(0, pow(2,256))
    p = pow(a, 4)
    q = pow(b, 4)
    rp = randrange(0, pow(2,24))
    rq = randrange(0, pow(2,24))
    pp = next_prime(p+rp)
    qq = next_prime(q+rq)
    if pp % pow(2, 4) == (pp-p) % pow(2, 4) and qq % pow(2, 4) == (qq-q) % pow(2, 4):
        n = pp*qq
        rp = pp-p
        rq = qq-q
        return n, rp, rq

n, rp, rq = gen_key()
e = 65537
c = pow(bytes_to_long(flag), e, n)
print("n =", n)
print("e =", e)
print("c =", c)
print("=======leak=======")
leak(rp, rq)

'''
n = 3183573836769699313763043722513486503160533089470716348487649113450828830224151824106050562868640291712433283679799855890306945562430572137128269318944453041825476154913676849658599642113896525291798525533722805116041675462675732995881671359593602584751304602244415149859346875340361740775463623467503186824385780851920136368593725535779854726168687179051303851797111239451264183276544616736820298054063232641359775128753071340474714720534858295660426278356630743758247422916519687362426114443660989774519751234591819547129288719863041972824405872212208118093577184659446552017086531002340663509215501866212294702743
e = 65537
c = 48433948078708266558408900822131846839473472350405274958254566291017137879542806238459456400958349315245447486509633749276746053786868315163583443030289607980449076267295483248068122553237802668045588106193692102901936355277693449867608379899254200590252441986645643511838233803828204450622023993363140246583650322952060860867801081687288233255776380790653361695125971596448862744165007007840033270102756536056501059098523990991260352123691349393725158028931174218091973919457078350257978338294099849690514328273829474324145569140386584429042884336459789499705672633475010234403132893629856284982320249119974872840
=======leak=======
122146249659110799196678177080657779971
90846368443479079691227824315092288065

p p = n e x t p r i m e ( p + r p ) q q = n e x t p r i m e ( q + r q ) n = p p ∗ q q r p 、 r q = 24 b i t l e a k 2 = r p e + r q e + 0 x d e a d b e e f ( m o d l e a k 1 ) l e a k 1 已知 pp=nextprime(p+rp)\\qq=nextprime(q+rq)\\n=pp*qq\\rp、rq =24bit\\leak2=rp^e + rq^e + 0xdeadbeef \pmod {leak_1}\\leak_1已知 pp=nextprime(p+rp)qq=nextprime(q+rq)n=ppqqrprq=24bitleak2=rpe+rqe+0xdeadbeef(modleak1)leak1已知

题解:

leak→爆破出rp,rq

image-20230916175136104

  • 中间相遇攻击

    假设 E 和 D 分别是加密函数和解密函数,k1 和 k2 分别是两次加密使用的密钥,则我们有

    P ⟶ 加密 ( k 1 ) t ⟶ 加密 ( k 2 ) C P\stackrel{加密(k_1)}{\longrightarrow}t\stackrel{加密(k_2)}{\longrightarrow}C P加密(k1)t加密(k2)C

    E k 1 ( P ) = D k 2 ( C ) E_{k_1}(P)=D_{k_2}(C) Ek1(P)=Dk2(C)

    则我们可以推出

    P ⟶ 加密 ( k 1 ) t C ⟶ 解密 ( k 2 ) t P\stackrel{加密(k_1)}{\longrightarrow}t\\ C\stackrel{解密(k_2)}{\longrightarrow}t P加密(k1)tC解密(k2)t

    那么,当用户知道一对明文和密文时

    1. 攻击者可以枚举所有的 k1,将 P 所有加密后的结果存储起来,并按照密文的大小进行排序。
    2. 攻击者进一步枚举所有的k2,将密文 C 进行解密得到 C1,在第一步加密后的结果中搜索 C1,如果搜索到,则我们在一定程度上可以认为我们找到了正确的 k1 和 k2。
    3. 如果觉得第二步中得到的结果不保险,则我们还可以再找一些明密文对进行验证。

    假设 k1 和 k2 的密钥长度都为 n,则原先我们暴力枚举需要 O ( n 2 ) O(n^2) O(n2),现在我们只需要 O ( n l o g 2 n ) O(n log_2n) O(nlog2n)

l e a k 2 = r p e + r q e + 0 x d e a d b e e f ( m o d l e a k 1 ) l e a k 2 = r p e + r q e + 0 x d e a d b e e f ( m o d n 1 ) r q e = l e a k 2 − 0 x d e a d b e e f − r p e ( m o d n 1 ) leak2=rp^e + rq^e + 0xdeadbeef \pmod {leak_1}\\leak2=rp^e + rq^e + 0xdeadbeef \pmod {n_1}\\rq^e=leak2- 0xdeadbeef-rp^e \pmod {n_1} leak2=rpe+rqe+0xdeadbeef(modleak1)leak2=rpe+rqe+0xdeadbeef(modn1)rqe=leak20xdeadbeefrpe(modn1)

输入的rp,rq都只有24位,这里就可以进行爆破,爆破的条件是长度要小于24位

中间相遇爆破:(复杂度降低了)

代码1

image-20230916175318166

代码2

dict={}
    for rp in tqdm(range(1,2**24)):
        tmp=(c-pow(rp,e,n))%n
        dict[tmp]=rp
    for rq in tqdm(range(1,2**24)):
        tmp=pow(rq,e,n)
        if tmp in dict.keys():
            print(rq,dict[tmp])
            break

求p,q

p p = n e x t p r i m e ( p + r p ) q q = n e x t p r i m e ( q + r q ) n = p p ∗ q q = ( p + r p + k 1 ) ∗ ( q + r q + k 2 ) = ( a 4 + r p + k 1 ) ∗ ( b 4 + r q + k 2 ) = ( a b ) 4 + a 4 ∗ ( r q + k 2 ) + b 4 ∗ ( r p + k 1 ) + r p ∗ q q + k 2 + r q ∗ k 1 + k 1 ∗ k 2 ( a b ) 4 特别大 = ( a ∗ b ) 4 + O ( t ) pp=nextprime(p+rp)\\qq=nextprime(q+rq)\\n=pp*qq=(p+rp+k_1)*(q+rq+k_2)\\=(a^4+rp+k_1)*(b^4+rq+k_2)\\=(ab)^4+a^4*(rq+k_2)+b^4*(rp+k_1)+rp*qq+k_2+rq*k_1+k1*k_2\\(ab)^4特别大\\=(a*b)^4+O(t) pp=nextprime(p+rp)qq=nextprime(q+rq)n=ppqq=(p+rp+k1)(q+rq+k2)=(a4+rp+k1)(b4+rq+k2)=(ab)4+a4(rq+k2)+b4(rp+k1)+rpqq+k2+rqk1+k1k2(ab)4特别大=(ab)4+O(t)

t = (gmpy2.iroot(n,4)[0])**4

记 p*q=t,求pp,qq

pp=nextprime(p+rp)

qq=nextprime(q+rq)

n = p p ∗ q q = ( p + r p + k 1 ) ∗ ( q + r q + k 2 ) = p ∗ q + p ∗ r q + p ∗ k 2 + r p ∗ q + r p ∗ r q + r p + k 2 + k 1 ∗ q + k 1 ∗ r q + k 1 ∗ k 2 n=pp*qq=(p+rp+k_1)*(q+rq+k_2)\\ =p*q+p*rq+p*k_2+rp*q+rp*rq+rp+k_2+k_1*q+k_1*rq+k_1*k_2 n=ppqq=(p+rp+k1)(q+rq+k2)=pq+prq+pk2+rpq+rprq+rp+k2+k1q+k1rq+k1k2

两边同时乘以p,消掉q

n ∗ p = p ∗ t + p 2 ∗ r q + p 2 ∗ k 2 + r p ∗ t + p ∗ r p ∗ r q + r p ∗ k 2 ∗ p + k 1 ∗ t + k 1 ∗ r q ∗ p + k 1 ∗ k 2 ∗ p \\n*p=p*t+p^2*rq+p^2*k_2+rp*t+p*rp*rq+rp*k_2*p+k_1*t+k_1*rq*p+k_1*k_2*p np=pt+p2rq+p2k2+rpt+prprq+rpk2p+k1t+k1rqp+k1k2p

k1,k2爆破,利用求根公式求解关于p的一元二次方程

from Crypto.Util.number import inverse
from tqdm import tqdm

n1=122146249659110799196678177080657779971
e = 65537
#分解n1

p1 = 8949458376079230661
q1 = 13648451618657980711
phi=(p1-1)*(q1-1)
d1=inverse(e,phi)

c1=90846368443479079691227824315092288065
c=(c1-0xdeadbeef)%n1

#爆破
for rp in tqdm(range(2**24)):
    t=(c-pow(rp,e,n1))%n1
    # print(t)
    rq=pow(t,d1,n1)
    if( len(bin(rq))<=26):
        print(rp)
        print(rq)
        break'''

# #爆破2,太复杂
# for i in tqdm(range(2**24)):
#     for j in range(2**24):
#         if (pow(i,e,n1)+pow(j,e,n1)+0xdeadbeef)%n1==c1:
#             rp=i
#             rq=j
#             print(i)
#             print(j)
#             break
#

import gmpy2
from Crypto.Util.number import *

n = 3183573836769699313763043722513486503160533089470716348487649113450828830224151824106050562868640291712433283679799855890306945562430572137128269318944453041825476154913676849658599642113896525291798525533722805116041675462675732995881671359593602584751304602244415149859346875340361740775463623467503186824385780851920136368593725535779854726168687179051303851797111239451264183276544616736820298054063232641359775128753071340474714720534858295660426278356630743758247422916519687362426114443660989774519751234591819547129288719863041972824405872212208118093577184659446552017086531002340663509215501866212294702743
e = 65537
flag = 48433948078708266558408900822131846839473472350405274958254566291017137879542806238459456400958349315245447486509633749276746053786868315163583443030289607980449076267295483248068122553237802668045588106193692102901936355277693449867608379899254200590252441986645643511838233803828204450622023993363140246583650322952060860867801081687288233255776380790653361695125971596448862744165007007840033270102756536056501059098523990991260352123691349393725158028931174218091973919457078350257978338294099849690514328273829474324145569140386584429042884336459789499705672633475010234403132893629856284982320249119974872840

rp = 405771
rq = 11974933

t = pow(gmpy2.iroot(n, 4)[0], 4)
for k1 in range(1000):
    for k2 in range(1000):
        a = rq + k2
        b = t + rp*rq + rp*k2 + k1*rq + k1*k2 - n
        c = (rp + k1) * t
        delta = pow(b,2) - 4*a*c
        roots = gmpy2.iroot(delta, 2)
        if roots[1]:
            p = (-b + roots[0])//(2*a)
            pp = p+rp+k1
            if isPrime(pp):
                print(f"{k1 = }")
                print(f"{k2 = }")
                qq = n//pp
                phi = (pp-1)*(qq-1)
                d = gmpy2.invert(e, phi)
                m = pow(flag, d, n)
                print(long_to_bytes(int(m)))
                exit()
#ACTF{lsb_attack_in_RSA|a32d7f}

GKCTF 2021 RRRRsa

from Crypto.Util.number import *
from gmpy2 import gcd

flag = b'xxxxxxxxxxxxx'
p = getPrime(512)
q = getPrime(512)
m = bytes_to_long(flag)
n = p*q
e = 65537
c = pow(m,e,n)
print('c={}'.format(c))

p1 = getPrime(512)
q1 = getPrime(512)
n1 = p1*q1
e1 = 65537
assert gcd(e1,(p1-1)*(q1-1)) == 1
c1 = pow(p,e1,n1)
print('n1={}'.format(n1))
print('c1={}'.format(c1))
hint1 = pow(2020 * p1 + q1, 202020, n1)
hint2 = pow(2021 * p1 + 212121, q1, n1)
print('hint1={}'.format(hint1))
print('hint2={}'.format(hint2))

p2 = getPrime(512)
q2 = getPrime(512)
n2 = p2*q2
e2 = 65537
assert gcd(e1,(p2-1)*(q2-1)) == 1
c2 = pow(q,e2,n2)
hint3 = pow(2020 * p2 + 2021 * q2, 202020, n2)
hint4 = pow(2021 * p2 + 2020 * q2, 212121, n2)
print('n2={}'.format(n2))
print('c2={}'.format(c2))
print('hint3={}'.format(hint3))
print('hint4={}'.format(hint4))

题解

{ h i n t 1 = ( 2020 ∗ p 1 + q 1 ) 202020 ( m o d n 1 ) h i n t 2 = ( 2021 ∗ p 1 + 212121 ) q 1 ( m o d n 1 ) h i n t 3 = ( 2020 ∗ p 2 + 2021 ∗ q 2 ) 202020 ( m o d n 2 ) h i n t 4 = ( 2021 ∗ p 2 + 2020 ∗ q 2 ) 212121 ( m o d n 2 ) \begin{cases}hint1=(2020∗p1+q1)^{202020} \pmod {n_1}\\hint2=(2021∗p1+212121)^{q1} \pmod {n_1}\\hint3=(2020∗p2+2021∗q2) ^{202020} \pmod {n_2}\\hint4=(2021∗p2+2020∗q2)^{212121 }\pmod {n_2}\\\end{cases} hint1=(2020p1+q1)202020(modn1)hint2=(2021p1+212121)q1(modn1)hint3=(2020p2+2021q2)202020(modn2)hint4=(2021p2+2020q2)212121(modn2)

c1 = pow(p,e1,n1),求p

利用二项式定理展开hint1,可将含p*q的项消除。

image-20230916190149763

而hint2的化简可利用费马定理:

p 为素数,则对任意 a 有 a p = a ( m o d p ) p 为 素 数 , 则 对 任 意 a 有\\ a^p = a \pmod p p为素数,则对任意aap=a(modp)

可得

{ h i n t 1 = ( 2020 ∗ p 1 ) 202020 + q 1 202020 ( m o d n 1 ) h i n t 2 = 2021 ∗ p 1 + 212121 ( m o d q 1 ) \begin{cases}hint1=(2020∗p1)^{202020}+q1^{202020}\pmod {n_1}\\hint2=2021∗p1+212121\pmod {q_1}\end{cases} \\ {hint1=(2020p1)202020+q1202020(modn1)hint2=2021p1+212121(modq1)

模q1

{ h i n t 1 = ( 2020 ∗ p 1 ) 202020 ( m o d q 1 ) h i n t 2 − 212121 = 2021 ∗ p 1 ( m o d q 1 ) { h i n t 1 ∗ 202 0 − 202020 = p 1 202020 ( m o d q 1 ) ( h i n t 2 − 212121 ) 202020 ∗ 202 1 − 202020 = p 1 202020 ( m o d q 1 ) \begin{cases}hint1=(2020∗p1)^{202020}\pmod {q_1}\\hint2-212121=2021∗p1\pmod {q_1}\end{cases}\\ \begin{cases}hint1*2020^{-202020}=p1^{202020}\pmod {q_1}\\ (hint2-212121)^{202020}*2021^{-202020}=p1^{202020}\pmod {q_1}\\ \end{cases}\\ {hint1=(2020p1)202020(modq1)hint2212121=2021p1(modq1){hint12020202020=p1202020(modq1)(hint2212121)2020202021202020=p1202020(modq1)

消元,消p1

( h i n t 2 − 212121 ) 202020 ∗ 202 1 − 202020 − ( 2020 ∗ p 1 ) 202020 = k ∗ q 1 q 1 = g c d ( k ∗ q 1 , n ) (hint2-212121)^{202020}*2021^{-202020}-(2020∗p1)^{202020}=k*q1\\q1=gcd(k*q1,n) (hint2212121)2020202021202020(2020p1)202020=kq1q1=gcd(kq1,n)

c2= pow(q,e2,n2),求q

202 1 202020 ∗ h i n t 3 = ( 2021 ∗ 2020 ∗ p 2 ) 202020 + ( 202 1 2 ∗ q 2 ) 202020 ( m o d n 2 ) 202 0 212121 ∗ h i n t 4 = ( 2021 ∗ 2020 ∗ p 2 ) 212121 + ( 20202 ∗ q 2 ) 212121 ( m o d n 2 ) 2021^{202020} ∗hint3=(2021∗2020∗p2) ^{202020} +(2021^ 2 ∗q2)^{202020}\pmod {n_2}\\2020^{212121} ∗hint4=(2021∗2020∗p2)^{212121} +(2020 2 ∗q2)^{212121} \pmod {n_2}\\ 2021202020hint3=(20212020p2)202020+(20212q2)202020(modn2)2020212121hint4=(20212020p2)212121+(20202q2)212121(modn2)

{ ① ( 202 1 202020 ∗ h i n t 3 ) 212121 = ( 2021 ∗ 2020 ∗ p 2 ) 202020 ∗ 212121 + ( 202 1 2 ∗ q 2 ) 202020 ∗ 212121 ( m o d n 2 ) ② ( 202 0 212121 ∗ h i n t 4 ) 202020 = ( 2021 ∗ 2020 ∗ p 2 ) 202020 ∗ 212121 + ( 202 0 2 ∗ q 2 ) 202020 ∗ 212121 ( m o d n 2 ) \begin{cases}① ( 2021^{202020} ∗ h i n t 3 )^{ 212121} = ( 2021 ∗ 2020 ∗ p 2 )^{ 202020 ∗ 212121} + ( 202 1^2 ∗ q 2 ) ^{202020 ∗ 212121} \pmod{n_2} \\② ( 2020^{212121} ∗ h i n t 4 )^{ 202020} = ( 2021 ∗ 2020 ∗ p 2 )^{ 202020 ∗ 212121} + ( 2020^2 ∗ q 2 ) ^{202020 ∗ 212121} \pmod{n_2} \end{cases} {(2021202020hint3)212121=(20212020p2)202020212121+(20212q2)202020212121(modn2)(2020212121hint4)202020=(20212020p2)202020212121+(20202q2)202020212121(modn2)

② − ① = k 1 ∗ q 2 ( m o d n 2 ) ② − ① = k 1 ∗ q 2 + k 2 ∗ n 2 = k ∗ q 2 q 2 = g c d ( ② − ① , n 2 ) ②−①=k1∗q2\pmod {n_2}\\②−①=k1∗q2+k2∗n2=k∗q2\\q2=gcd(②−①,n2) =k1q2(modn2)=k1q2+k2n2=kq2q2=gcd(,n2)

from gmpy2 import gcd
from Crypto.Util.number import *
import gmpy2
c=13492392717469817866883431475453770951837476241371989714683737558395769731416522300851917887957945766132864151382877462142018129852703437240533684604508379950293643294877725773675505912622208813435625177696614781601216465807569201380151669942605208425645258372134465547452376467465833013387018542999562042758
n1=75003557379080252219517825998990183226659117019770735080523409561757225883651040882547519748107588719498261922816865626714101556207649929655822889945870341168644508079317582220034374613066751916750036253423990673764234066999306874078424803774652754587494762629397701664706287999727238636073466137405374927829
c1=68111901092027813007099627893896838517426971082877204047110404787823279211508183783468891474661365139933325981191524511345219830693064573462115529345012970089065201176142417462299650761299758078141504126185921304526414911455395289228444974516503526507906721378965227166653195076209418852399008741560796631569
hint1=23552090716381769484990784116875558895715552896983313406764042416318710076256166472426553520240265023978449945974218435787929202289208329156594838420190890104226497263852461928474756025539394996288951828172126419569993301524866753797584032740426259804002564701319538183190684075289055345581960776903740881951
hint2=52723229698530767897979433914470831153268827008372307239630387100752226850798023362444499211944996778363894528759290565718266340188582253307004810850030833752132728256929572703630431232622151200855160886614350000115704689605102500273815157636476901150408355565958834764444192860513855376978491299658773170270
n2=114535923043375970380117920548097404729043079895540320742847840364455024050473125998926311644172960176471193602850427607899191810616953021324742137492746159921284982146320175356395325890407704697018412456350862990849606200323084717352630282539156670636025924425865741196506478163922312894384285889848355244489
c2=67054203666901691181215262587447180910225473339143260100831118313521471029889304176235434129632237116993910316978096018724911531011857469325115308802162172965564951703583450817489247675458024801774590728726471567407812572210421642171456850352167810755440990035255967091145950569246426544351461548548423025004
hint3=25590923416756813543880554963887576960707333607377889401033718419301278802157204881039116350321872162118977797069089653428121479486603744700519830597186045931412652681572060953439655868476311798368015878628002547540835719870081007505735499581449077950263721606955524302365518362434928190394924399683131242077
hint4=104100726926923869566862741238876132366916970864374562947844669556403268955625670105641264367038885706425427864941392601593437305258297198111819227915453081797889565662276003122901139755153002219126366611021736066016741562232998047253335141676203376521742965365133597943669838076210444485458296240951668402513
e=65537
# q1 = gcd(n1,pow(hint2-212121,202020,n1)*pow(2020,202020,n1)-hint1*pow(2021,202020,n1))
# print(q1)
i1=inverse(pow(2021,202020,n1),n1)
i2=inverse(pow(2020,202020,n1),n1)
q1= gcd(n1,pow(hint2-212121,202020,n1)*i1-hint1*i2)
print(q1)
p1 = n1//q1
q2 = gcd(n2,pow(hint3,212121,n2)*pow(2021,202020*212121,n2)-pow(hint4,202020,n2)*pow(2020,202020*212121,n2))
p2 = n2//q2
d2 = gmpy2.invert(e,(q2-1)*(p2-1))
q = pow(c2,d2,n2)
d1 = gmpy2.invert(e,(q1-1)*(p1-1))
p = pow(c1,d1,n1)
d = gmpy2.invert(e,(q-1)*(p-1))
m = pow(c,d,p*q)
print(long_to_bytes(m))
#b'GKCTF{f64310b5-d5e6-45cb-ae69-c86600cdf8d8}

东华杯fermat’s revenge

这道题和上面这道可以说结构很像

from Crypto.Util.number import *
f = open('flag.txt', 'rb')
m = bytes_to_long(f.read())
f.close()
e = 65537
p = getPrime(1024)
q = getPrime(1024)
n = p * q
c = pow(m, e, n)
hint = pow(1010 * p + 1011, q, n)
f = open('cipher.txt', 'w')
f.write(f'n={n}\\n')
f.write(f'c={c}\\n')
f.write(f'hint={hint}\\n')
f.close()

这里只有一个hint

p = getPrime(1024)

q = getPrime(1024)

h i n t ≡ ( 1010 ∗ p + 1011 ) q ( m o d n ) h i n t ≡ ( 1010 ∗ p + 1011 ) q ( m o d p ) h i n t ≡ ( 1011 ) q ( m o d p ) ( 1011 ) n ≡ ( 1011 ) q ∗ p ≡ ( ( 1011 ) q ) p ≡ ( 1011 ) q ( m o d p ) h i n t ≡ ( 1011 ) n ( m o d p ) h i n t − ( 1011 ) n ≡ 0 ( m o d p ) h i n t − ( 1011 ) n = k ∗ p n = q ∗ p p = g c d ( n , h i n t − ( 1011 ) n ) hint \equiv (1010 * p + 1011)^ q \pmod n\\ hint \equiv(1010 * p + 1011)^ q \pmod p\\ hint \equiv( 1011)^ q \pmod p\\( 1011)^ n\equiv ( 1011)^ {q* p}\equiv (( 1011)^ {q})^ {p}\equiv( 1011)^ {q}\pmod p\\hint\equiv (1011)^ n\pmod p\\hint-( 1011)^ n\equiv 0 \pmod p\\hint-( 1011)^ n=k* p\\n=q*p\\p=gcd(n,hint-( 1011)^ n) hint(1010p+1011)q(modn)hint(1010p+1011)q(modp)hint(1011)q(modp)(1011)n(1011)qp((1011)q)p(1011)q(modp)hint(1011)n(modp)hint(1011)n0(modp)hint(1011)n=kpn=qpp=gcd(n,hint(1011)n)

h i n t = 101 1 q ( m o d   p ) ↔ h i n t ≡ ( 1011 ) n ( m o d p ) hint=1011^{q}(mod\ p)\leftrightarrow hint\equiv (1011)^ n\pmod p\\ hint=1011q(mod p)hint(1011)n(modp)

from Crypto.Util.number import *
e = 65537
# hint = pow(1010 * p + 1011, q, n)
n=17329555687339057933030881774167606066714011664369940819755094697939414110116183129515036417930928381309923593306884879686961969722610261114896200690291299753284120079351636102685226435454462581742248968732979816910255384339882675593423385529925794918175056364069416358095759362865710837992174966213332948216626442765218056059227797575954980861175262821459941222980957749720949816909119263643425681517545937122980872133309062049836920463547302193585676588711888598357927574729648088370609421283416559346827315399049239357814820660913395553316721927867556418628117971385375472454118148999848258824753064992040468588511
c=2834445728359401954509180010018035151637121735110411504246937217024301211768483790406570069340718976013805438660602396212488675995602673107853878297024467687865600759709655334014269938893756460638324659859693599161639448736859952750381592192404889795107146077421499823006298655812398359841137631684363428490100792619658995661630533920917942659455792050032138051272224911869438429703875012535681896010735974555495618216882831524578648074539796556404193333636537331833807459066576022732553707927018332334884641370339471969967359580724737784159811992637384360752274204462169330081579501038904830207691558009918736480389
hint=2528640120640884291705022551567142949735065756834488816429783990402901687493207894594113717734719036126087363828359113769238235697788243950392064194097056579105620723640796253143555383311882778423540515270957452851097267592400001145658904042191937942341842865936546187498072576943297002184798413336701918670376291021190387536660070933700475110660304652647893127663882847145502396993549034428649569475467365756381857116208029508389607872560487325166953770793357700419069480517845456083758105937644350450559733949764193599564499133714282286339445501435278957250603141596679797055178139335763901195697988437542180256184

h2 = pow(1011, n, n)
q = GCD(hint-h2, n)
print(q)
p = n // q

d = inverse(e, (p-1)*(q-1))
m = pow(c, d, n)
print(long_to_bytes(m))
#b'flag{1d2f28834ecbd1983b62d30f4723476e}'

2022 zer0pts CTF Anti-Fermat

from Crypto.Util.number import isPrime, getStrongPrime
from gmpy import next_prime
from secret import flag

# Anti-Fermat Key Generation
p = getStrongPrime(1024)
q = next_prime(p ^ ((1<<1024)-1))
n = p * q
e = 65537

# Encryption
m = int.from_bytes(flag, 'big')
assert m < n
c = pow(m, e, n)

print('n = {}'.format(hex(n)))
print('c = {}'.format(hex(c)))
#n = 0x1ffc7dc6b9667b0dcd00d6ae92fb34ed0f3d84285364c73fbf6a572c9081931be0b0610464152de7e0468ca7452c738611656f1f9217a944e64ca2b3a89d889ffc06e6503cfec3ccb491e9b6176ec468687bf4763c6591f89e750bf1e4f9d6855752c19de4289d1a7cea33b077bdcda3c84f6f3762dc9d96d2853f94cc688b3c9d8e67386a147524a2b23b1092f0be1aa286f2aa13aafba62604435acbaa79f4e53dea93ae8a22655287f4d2fa95269877991c57da6fdeeb3d46270cd69b6bfa537bfd14c926cf39b94d0f06228313d21ec6be2311f526e6515069dbb1b06fe3cf1f62c0962da2bc98fa4808c201e4efe7a252f9f823e710d6ad2fb974949751
#c = 0x60160bfed79384048d0d46b807322e65c037fa90fac9fd08b512a3931b6dca2a745443a9b90de2fa47aaf8a250287e34563e6b1a6761dc0ccb99cb9d67ae1c9f49699651eafb71a74b097fc0def77cf287010f1e7bd614dccfb411cdccbb84c60830e515c05481769bd95e656d839337d430db66abcd3a869c6348616b78d06eb903f8abd121c851696bd4cb2a1a40a07eea17c4e33c6a1beafb79d881d595472ab6ce3c61d6d62c4ef6fa8903149435c844a3fab9286d212da72b2548f087e37105f4657d5a946afd12b1822ceb99c3b407bb40e21163c1466d116d67c16a2a3a79e5cc9d1f6a1054d6be6731e3cd19abbd9e9b23309f87bfe51a822410a62

题解

q = next_prime(p ^ ((1<<1024)-1))

如果a>b,,且a为0b1111111111(二进制全为1),那么a^b=a-b

所以((1<<1024)-1)^p=(1<<1024-1)-p

设p((1<<1024)-1)的下一个素数与p((1<<1024)-1)相差r(nextprime影响的是非常低位的数据)

q = ( 1 < < 1024 − 1 ) − p + r q=(1<<1024-1)-p+r q=(1<<10241)p+r

得到

p + q = 1 < < 1024 − 1 + r n = p ∗ q = ( p + q 2 ) 2 − ( p − q 2 ) 2 ( p − q ) 2 = ( p + q ) 2 − 4 ∗ n ( p − q ) = ( p + q ) 2 − 4 ∗ n p+q=1<<1024-1+r\\n=p*q=(\frac{p+q}{2})^2-(\frac{p-q}{2})^2\\(p-q)^2=(p+q)^2-4*n\\(p-q)=\sqrt{(p+q)^2-4*n}\\ p+q=1<<10241+rn=pq=(2p+q)2(2pq)2(pq)2=(p+q)24n(pq)=(p+q)24n

得到t=p-q

p = ( p + q ) + ( p − q ) 2 p ≈ ( 1 < < 1024 ) + ( 1 < < 1024 ) 2 − 4 ∗ n 2 p=\frac{(p+q)+(p-q)}{2}\\ p\approx \frac{(1<<1024)+\sqrt{(1<<1024)^2-4*n}}{2} p=2(p+q)+pq)p2(1<<1024)+(1<<1024)24n

爆破P,条件n%p==0

import gmpy2
from Crypto.Util.number import long_to_bytes, inverse
from ecdsa.numbertheory import next_prime

n = 0x1ffc7dc6b9667b0dcd00d6ae92fb34ed0f3d84285364c73fbf6a572c9081931be0b0610464152de7e0468ca7452c738611656f1f9217a944e64ca2b3a89d889ffc06e6503cfec3ccb491e9b6176ec468687bf4763c6591f89e750bf1e4f9d6855752c19de4289d1a7cea33b077bdcda3c84f6f3762dc9d96d2853f94cc688b3c9d8e67386a147524a2b23b1092f0be1aa286f2aa13aafba62604435acbaa79f4e53dea93ae8a22655287f4d2fa95269877991c57da6fdeeb3d46270cd69b6bfa537bfd14c926cf39b94d0f06228313d21ec6be2311f526e6515069dbb1b06fe3cf1f62c0962da2bc98fa4808c201e4efe7a252f9f823e710d6ad2fb974949751
c = 0x60160bfed79384048d0d46b807322e65c037fa90fac9fd08b512a3931b6dca2a745443a9b90de2fa47aaf8a250287e34563e6b1a6761dc0ccb99cb9d67ae1c9f49699651eafb71a74b097fc0def77cf287010f1e7bd614dccfb411cdccbb84c60830e515c05481769bd95e656d839337d430db66abcd3a869c6348616b78d06eb903f8abd121c851696bd4cb2a1a40a07eea17c4e33c6a1beafb79d881d595472ab6ce3c61d6d62c4ef6fa8903149435c844a3fab9286d212da72b2548f087e37105f4657d5a946afd12b1822ceb99c3b407bb40e21163c1466d116d67c16a2a3a79e5cc9d1f6a1054d6be6731e3cd19abbd9e9b23309f87bfe51a822410a62
n=int(n)
c=int(c)
# q = next_prime(p ^ ((1<<1024)-1))
t=1<<1024
p=(t+int(gmpy2.iroot(t**2-4*n,2)[0]))//2
while(n%p!=0):
    p=next_prime(p)
q=n//p
print(p)
phi=(p-1)*(q-1)
e=65537
d=inverse(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
#153456316755201256456077648680293404551531181234956990242779099773886170192558263224753907666532907469313954439789378399786631549347700474488574017322863270205683350905558827922567834954626909259763623105532668671134932118937640401627676913585506492102157561689678418157863742997375967679975824876706628973287
# b'Good job! Here is the flag:\n+-----------------------------------------------------------+\n| zer0pts{F3rm4t,y0ur_m3th0d_n0_l0ng3r_w0rks.y0u_4r3_f1r3d} |\n+-----------------------------------------------------------+'
# zer0pts{F3rm4t,y0ur_m3th0d_n0_l0ng3r_w0rks.y0u_4r3_f1r3d}

*2022 ctf crypto Ezrsa

from Crypto.Util.number import getStrongPrime
from gmpy import next_prime
from random import getrandbits
from flag import flag

p=getStrongPrime(1024)
q=next_prime(p^((1<<900)-1)^getrandbits(300))
n=p*q
e=65537

m=int(flag.encode('hex'),16)
assert m<n
c=pow(m,e,n)

print(hex(n))
#0xe78ab40c343d4985c1de167e80ba2657c7ee8c2e26d88e0026b68fe400224a3bd7e2a7103c3b01ea4d171f5cf68c8f00a64304630e07341cde0bc74ef5c88dcbb9822765df53182e3f57153b5f93ff857d496c6561c3ddbe0ce6ff64ba11d4edfc18a0350c3d0e1f8bd11b3560a111d3a3178ed4a28579c4f1e0dc17cb02c3ac38a66a230ba9a2f741f9168641c8ce28a3a8c33d523553864f014752a04737e555213f253a72f158893f80e631de2f55d1d0b2b654fc7fa4d5b3d95617e8253573967de68f6178f78bb7c4788a3a1e9778cbfc7c7fa8beffe24276b9ad85b11eed01b872b74cdc44959059c67c18b0b7a1d57512319a5e84a9a0735fa536f1b3

print(hex(c))
#0xd7f6c90512bc9494370c3955ff3136bb245a6d1095e43d8636f66f11db525f2063b14b2a4363a96e6eb1bea1e9b2cc62b0cae7659f18f2b8e41fca557281a1e859e8e6b35bd114655b6bf5e454753653309a794fa52ff2e79433ca4bbeb1ab9a78ec49f49ebee2636abd9dd9b80306ae1b87a86c8012211bda88e6e14c58805feb6721a01481d1a7031eb3333375a81858ff3b58d8837c188ffcb982a631e1a7a603b947a6984bd78516c71cfc737aaba479688d56df2c0952deaf496a4eb3f603a46a90efbe9e82a6aef8cfb23e5fcb938c9049b227b7f15c878bd99b61b6c56db7dfff43cd457429d5dcdb5fe314f1cdf317d0c5202bad6a9770076e9b25b1

p = k 1 ∗ ( 2 900 ) + k 2 q = k 1 ∗ ( 2 900 ) + ( 2 900 − k 2 ) + k 3 n = p ∗ q = k 1 2 ∗ ( 2 1800 ) + 2 k 1 k 2 ∗ ( 2 900 ) + k 1 ∗ ( 2 1800 ) + L ( 可忽略不计 ) p = k1 * (2^{900}) + k2\\q = k1 * (2^{900}) + (2^{900} - k2) +k3\\n = p*q = k1^2 * (2^{1800}) + 2k1k2 * (2^{900}) + k1 * (2^{1800}) + L(可忽略不计) p=k1(2900)+k2q=k1(2900)+(2900k2)+k3n=pq=k12(21800)+2k1k2(2900)+k1(21800)+L(可忽略不计)

对N开方得到p的高位,异或关系得到p中间几位,coppersmith得到p的低位。

image-20230916190227922

p的高位

🤭方法一:

p,q很接近,直接对n开方求的P的高位

将n的前248位开方

import gmpy2
n = 0xe78ab40c343d4985c1de167e80ba2657c7ee8c2e26d88e0026b68fe400224a3bd7e2a7103c3b01ea4d171f5cf68c8f00a64304630e07341cde0bc74ef5c88dcbb9822765df53182e3f57153b5f93ff857d496c6561c3ddbe0ce6ff64ba11d4edfc18a0350c3d0e1f8bd11b3560a111d3a3178ed4a28579c4f1e0dc17cb02c3ac38a66a230ba9a2f741f9168641c8ce28a3a8c33d523553864f014752a04737e555213f253a72f158893f80e631de2f55d1d0b2b654fc7fa4d5b3d95617e8253573967de68f6178f78bb7c4788a3a1e9778cbfc7c7fa8beffe24276b9ad85b11eed01b872b74cdc44959059c67c18b0b7a1d57512319a5e84a9a0735fa536f1b3
top_bits = int(gmpy2.iroot(n>>(2048-248),2)[0])
print(top_bits)

对n开方,取高124位

tph=int(gmpy2.iroot(n,2)[0])
ph=tph>>900
print(ph)

🤭方法二:

p = p h ∗ 2 900 + p l q = q h ∗ 2 900 + q l p h = q h = x n = p ∗ q = ( p h ∗ 2 900 + p l ) ∗ ( q h ∗ 2 900 + q l ) = x 2 ∗ 2 1800 + x ∗ 2 900 ∗ ( q l + p l ) + p l ∗ q l = x 2 ∗ 2 1800 + x ∗ 2 1800 + s m a l l ( 可忽略) n 1800 = x 2 + x p=ph*2^{900}+pl\\q=qh*2^{900}+ql\\ph=qh=x\\n=p*q=(ph*2^{900}+pl)*(qh*2^{900}+ql)\\=x^2*2^{1800}+x*2^{900}*(ql+pl)+pl*ql\\=x^2*2^{1800}+x*2^{1800}+small(可忽略)\\ \frac{n}{1800}=x^2+x p=ph2900+plq=qh2900+qlph=qh=xn=pq=(ph2900+pl)(qh2900+ql)=x221800+x2900(ql+pl)+plql=x221800+x21800+small(可忽略)1800n=x2+x

n=0xe78ab40c343d4985c1de167e80ba2657c7ee8c2e26d88e0026b68fe400224a3bd7e2a7103c3b01ea4d171f5cf68c8f00a64304630e07341cde0bc74ef5c88dcbb9822765df53182e3f57153b5f93ff857d496c6561c3ddbe0ce6ff64ba11d4edfc18a0350c3d0e1f8bd11b3560a111d3a3178ed4a28579c4f1e0dc17cb02c3ac38a66a230ba9a2f741f9168641c8ce28a3a8c33d523553864f014752a04737e555213f253a72f158893f80e631de2f55d1d0b2b654fc7fa4d5b3d95617e8253573967de68f6178f78bb7c4788a3a1e9778cbfc7c7fa8beffe24276b9ad85b11eed01b872b74cdc44959059c67c18b0b7a1d57512319a5e84a9a0735fa536f1b3
x=sympy.Symbol('x')
f1=x**2+x-n//2**1800
result=sympy.solve([f1],[x])
print(result)
#x=20226195070633070235386534147535171929

p的中间几位

方法一:

  • 测试

    p = '101011'
    q = '010100'
    print(int(p, 2)*int(q, 2))  # 860
    
    # p和q赋值如下
    p = '111111'
    q = '000001'
    
    # 第一位异或后
    p = '011111'
    q = '100001'
    print(int(p, 2)*int(q, 2))  # 1023
    '''
    大于原先值,那么该位不用改,即
    p = '111111'
    q = '000001'
    '''
    
    # 第二位异或后
    p = '101111'
    q = '010001'
    print(int(p, 2)*int(q, 2))  # 799
    '''
    小于原先值,那么该位要改,进行异或,即
    p = '101111'
    q = '010001'
    '''
    

因为异或随机数是在最后300位上,所以125-900位的p,q之和为一个定值,而这一段上p,q的每一位是相反的,因此可以将这一段设为极端情况——p全为1,q全为0。根据基本不等式,p、q的差值越大,积就越大,而最后300位还要继续将q增大。根据这几点可以爆破125-924位,当p*q<n 时,表示这个位置的数正确

pm=tph>>900
print(pm)
p = (1<<900)-1
q = 1<<300-1
p+=pm*(1<<900)
q+=pm*(1<<900)
#in the rest place, '1' either belong to p or q
for i in range(898, 301, -1):
    cur = 1<<i
    if (p^^cur) * (q^^cur) < n:
	    p^^= cur
	    q^^= cur

方法二:

设 p = h b + y 设p=hb+y\\ p=hb+y

根据异或的性质,由于异或1,可以得出p,q 的中间600bit的二进制是相反的,所以中间位p+q是固定的(二进制和为1)

q = h b + 2 900 − 1 − y + z ( 300 b i t 随机数) p + q = 2 h b + 2 900 − 1 + z q=hb+2^{900}-1-y+z(300bit随机数)\\p+q=2hb+2^{900}-1+z q=hb+29001y+z(300bit随机数)p+q=2hb+29001+z

在这里插入图片描述

{ p + q = 2 h b + 2 900 − 1 + z p − q = 2 ∗ y − 2 900 + 1 − z p − q = ( p + q ) 2 − 4 ∗ n y = ( p − q ) + 2 900 + ( z − 1 ) ( 可忽略) 2 \begin{cases}p+q=2hb+2^{900}-1+z\\p-q=2*y-2^{900}+1-z \\p-q=\sqrt{(p+q)^2-4*n} \end{cases}\\y=\frac{(p-q)+2^{900}+(z-1)(可忽略)}{2} p+q=2hb+29001+zpq=2y2900+1zpq=(p+q)24n y=2(pq)+2900+(z1)(可忽略)

from Crypto.Util.number import *
import gmpy2
n=0xe78ab40c343d4985c1de167e80ba2657c7ee8c2e26d88e0026b68fe400224a3bd7e2a7103c3b01ea4d171f5cf68c8f00a64304630e07341cde0bc74ef5c88dcbb9822765df53182e3f57153b5f93ff857d496c6561c3ddbe0ce6ff64ba11d4edfc18a0350c3d0e1f8bd11b3560a111d3a3178ed4a28579c4f1e0dc17cb02c3ac38a66a230ba9a2f741f9168641c8ce28a3a8c33d523553864f014752a04737e555213f253a72f158893f80e631de2f55d1d0b2b654fc7fa4d5b3d95617e8253573967de68f6178f78bb7c4788a3a1e9778cbfc7c7fa8beffe24276b9ad85b11eed01b872b74cdc44959059c67c18b0b7a1d57512319a5e84a9a0735fa536f1b3

c=0xd7f6c90512bc9494370c3955ff3136bb245a6d1095e43d8636f66f11db525f2063b14b2a4363a96e6eb1bea1e9b2cc62b0cae7659f18f2b8e41fca557281a1e859e8e6b35bd114655b6bf5e454753653309a794fa52ff2e79433ca4bbeb1ab9a78ec49f49ebee2636abd9dd9b80306ae1b87a86c8012211bda88e6e14c58805feb6721a01481d1a7031eb3333375a81858ff3b58d8837c188ffcb982a631e1a7a603b947a6984bd78516c71cfc737aaba479688d56df2c0952deaf496a4eb3f603a46a90efbe9e82a6aef8cfb23e5fcb938c9049b227b7f15c878bd99b61b6c56db7dfff43cd457429d5dcdb5fe314f1cdf317d0c5202bad6a9770076e9b25b1

prefix=gmpy2.iroot(n,2)[0]
prefix=(prefix>>900)<<900
hb=gmpy2.iroot(n,2)[0]
hb=(hb>>900)<<900
paq=2*hb+2**900

psq=gmpy2.iroot(paq**2-4*n,2)[0]
y=(psq+2**900)//2
p=hb+y
print(p)
# 170966211863977623201944075700366958395158791305775637137148430402719914596268969449870561801896130406088025694634815584789789278534177858182071449441084789053688828370314062664371506437683672869879650195774368524468044540434185235653504063937932618450991608706715382905688880285112977572901480973791888259637

方法三:

二分法逼近p,q

在这里插入图片描述

from Crypto.Util.number import *
import gmpy2
n=0xe78ab40c343d4985c1de167e80ba2657c7ee8c2e26d88e0026b68fe400224a3bd7e2a7103c3b01ea4d171f5cf68c8f00a64304630e07341cde0bc74ef5c88dcbb9822765df53182e3f57153b5f93ff857d496c6561c3ddbe0ce6ff64ba11d4edfc18a0350c3d0e1f8bd11b3560a111d3a3178ed4a28579c4f1e0dc17cb02c3ac38a66a230ba9a2f741f9168641c8ce28a3a8c33d523553864f014752a04737e555213f253a72f158893f80e631de2f55d1d0b2b654fc7fa4d5b3d95617e8253573967de68f6178f78bb7c4788a3a1e9778cbfc7c7fa8beffe24276b9ad85b11eed01b872b74cdc44959059c67c18b0b7a1d57512319a5e84a9a0735fa536f1b3

c=0xd7f6c90512bc9494370c3955ff3136bb245a6d1095e43d8636f66f11db525f2063b14b2a4363a96e6eb1bea1e9b2cc62b0cae7659f18f2b8e41fca557281a1e859e8e6b35bd114655b6bf5e454753653309a794fa52ff2e79433ca4bbeb1ab9a78ec49f49ebee2636abd9dd9b80306ae1b87a86c8012211bda88e6e14c58805feb6721a01481d1a7031eb3333375a81858ff3b58d8837c188ffcb982a631e1a7a603b947a6984bd78516c71cfc737aaba479688d56df2c0952deaf496a4eb3f603a46a90efbe9e82a6aef8cfb23e5fcb938c9049b227b7f15c878bd99b61b6c56db7dfff43cd457429d5dcdb5fe314f1cdf317d0c5202bad6a9770076e9b25b1

hb=gmpy2.iroot(n,2)[0]
hb=(hb>>900)<<900
paq=2*hb+2**900

l=1
r=int(gmpy2.iroot(n,2)[0])

while abs(r-l)>1:
    m=(r+l)//2
    x=m+n//m
    if x>paq:
        l=m
    else:
        r=m

print(r)

p的低位

coppersmith攻击

在这里插入图片描述

已知p的高(124+600)bit

# PR.<x> = PolynomialRing(Zmod(n))
# f=x+q
# roots=f.small_roots(X=2**450,beta=0.4)
# q=q+roots[0]
# p=n//int(q)

p=170966211863977623201944075700366958395158791305775637137148430402719914596268969449870561801896130406088025694634815584789789278534177858182071449441084789053688828370314062664371527964357773254659131885022323526864655742577256932209187678896131068422973326545184343697783650940422950445390573562429093050687
q=170966211863977623201944075700366958393004619503764097699771516857862770135235397782599591014026733542308689997522855822788108026355476250633633402693487971215224188430679737025882802309022607681575250753960315394407312741086850962379910401529197519289967419289495492616818534528352393107250012092986104141453

phi=(p-1)*(q-1)
d=inverse(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
# *CTF{St.Diana_pls_take_me_with_you!}'
  • 拓展

    def adlit(x):
        l = len(bin(x)[2:])
        return (2 ** l - 1) ^ x
    
    a=616161
    print(bin(a))
    print(bin(adlit(a)))
    #0b10010110011011100001
    #0b01101001100100011110
    

    补上bin(adlit(a))函数前的那个0,不难看出两个二进制数是相反的,adlit函数就是对一个数的二进制数进行取反。跟*CTF中间的600位一样。

    p+adlit(p)=2^(nbit)-1

羊城杯 2020 RRRRRRRSA

from Crypto.Util.number import *
from secret import flag
import random

m1 = bytes_to_long(flag[:len(flag) // 2])
m2 = bytes_to_long(flag[len(flag) // 2:])

def gen(pbits, qbits):
    p1, q1 = getPrime(pbits), getPrime(qbits)
    n1 = p1**4*q1
    q2 = getPrime(qbits)
    bound = p1 // (8*q1*q2) + 1
    p2 = random.randrange(p1, p1 + bound)
    while not isPrime(p2):
        p2 = random.randrange(p1, p1 + bound)
    n2 = p2**4*q2
    return (n1, n2), (p1, q1), (p2, q2)

e = 0x10001
pbits = int(360)
qbits = int(128)
pk, sk1, sk2 = gen(pbits, qbits)
c1 = pow(m1, e, pk[0])
c2 = pow(m2, e, pk[1])
print(f'pk = {pk}')
print(f'c1, c2 = {c1, c2}')

"""
pk = (1150398070565459492080597718626032792435556703413923483458704675295997646493249759818468321328556510074044954676615760446708253531839417036997811506222349194302791943489195718713797322878586379546657275419261647635859989280700191441312691274285176619391539387875252135478424580680264554294179123254566796890998243909286508189826458854346825493157697201495100628216832191035903848391447704849808577310612723700318670466035077202673373956324725108350230357879374234418393233, 1242678737076048096780023147702514112272319497423818488193557934695583793070332178723043194823444815153743889740338870676093799728875725651036060313223096288606947708155579060628807516053981975820338028456770109640111153719903207363617099371353910243497871090334898522942934052035102902892149792570965804205461900841595290667647854346905445201396273291648968142608158533514391348407631818144116768794595226974831093526512117505486679153727123796834305088741279455621586989)
c1, c2 = (361624030197288323178211941746074961985876772079713896964822566468795093475887773853629454653096485450671233584616088768705417987527877166166213574572987732852155320225332020636386698169212072312758052524652761304795529199864805108000796457423822443871436659548626629448170698048984709740274043050729249408577243328282313593461300703078854044587993248807613713896590402657788194264718603549894361488507629356532718775278399264279359256975688280723740017979438505001819438, 33322989148902718763644384246610630825314206644879155585369541624158380990667828419255828083639294898100922608833810585530801931417726134558845725168047585271855248605561256531342703212030641555260907310067120102069499927711242804407691706542428236208695153618955781372741765233319988193384708525251620506966304554054884590718068210659709406626033891748214407992041364462525367373648910810036622684929049996166651416565651803952838857960054689875755131784246099270581394)
"""

n 1 = p 1 4 ∗ q 1 n 2 = p 2 4 ∗ q 2 n1=p1^4*q1\\n2=p2^4*q2\\ n1=p14q1n2=p24q2

p2 = random.randrange(p1, p1 + bound) , 说明p1,p2相差很小

n 1 n 2 = p 1 4 ∗ q 1 p 2 4 ∗ q 2 ≈ q 1 q 2 \frac{n1}{n2}=\frac{p1^4*q1}{p2^4*q2}\approx\frac{q1}{q2}\\ n2n1=p24q2p14q1q2q1

连分数展开 n 1 n 2 \frac{n1}{n2} n2n1,可以找到q1,q2

import gmpy2
N1=1150398070565459492080597718626032792435556703413923483458704675295997646493249759818468321328556510074044954676615760446708253531839417036997811506222349194302791943489195718713797322878586379546657275419261647635859989280700191441312691274285176619391539387875252135478424580680264554294179123254566796890998243909286508189826458854346825493157697201495100628216832191035903848391447704849808577310612723700318670466035077202673373956324725108350230357879374234418393233
c1=361624030197288323178211941746074961985876772079713896964822566468795093475887773853629454653096485450671233584616088768705417987527877166166213574572987732852155320225332020636386698169212072312758052524652761304795529199864805108000796457423822443871436659548626629448170698048984709740274043050729249408577243328282313593461300703078854044587993248807613713896590402657788194264718603549894361488507629356532718775278399264279359256975688280723740017979438505001819438
E1=0x10001
N2=1242678737076048096780023147702514112272319497423818488193557934695583793070332178723043194823444815153743889740338870676093799728875725651036060313223096288606947708155579060628807516053981975820338028456770109640111153719903207363617099371353910243497871090334898522942934052035102902892149792570965804205461900841595290667647854346905445201396273291648968142608158533514391348407631818144116768794595226974831093526512117505486679153727123796834305088741279455621586989
c2=33322989148902718763644384246610630825314206644879155585369541624158380990667828419255828083639294898100922608833810585530801931417726134558845725168047585271855248605561256531342703212030641555260907310067120102069499927711242804407691706542428236208695153618955781372741765233319988193384708525251620506966304554054884590718068210659709406626033891748214407992041364462525367373648910810036622684929049996166651416565651803952838857960054689875755131784246099270581394
E2=0x10001
def continuedFra(x, y):
    cF = []
    while y:
        cF += [x // y]
        x, y = y, x % y
    return cF
def Simplify(ctnf):
    numerator = 0
    denominator = 1
    for x in ctnf[::-1]:
        numerator, denominator = denominator, x * denominator + numerator
    return (numerator, denominator)
def getit(c):
    cf=[]
    for i in range(1,len(c)):
        cf.append(Simplify(c[:i]))
    return cf
#求渐进分数
def wienerAttack(e, n):
    cf=continuedFra(e,n)
    for (p2,p1) in getit(cf):
        if p1 == 0:
            continue
        if N1%p1==0 and p1!=1:
            return p1,p2
    print('not find!')
q1,q2 = wienerAttack(N1,N2)
p1 = gmpy2.iroot(N1//q1,4)[0]
p2 = gmpy2.iroot(N2//q2,4)[0]
phi1=p1**3*(p1-1)*(q1-1)
phi2=p2**3*(p2-1)*(q2-1)
d1=gmpy2.invert(E1,phi1)
d2=gmpy2.invert(E2,phi2)
from Crypto.Util import number
m1=number.long_to_bytes(gmpy2.powmod(c1,d1,N1))
m2=number.long_to_bytes(gmpy2.powmod(c2,d2,N2))
print((m1+m2))

🍹总结

  • q = inverse(e, p)

  • 数据小的数要进行爆破;

  • 通过对等式两边同时进行加减乘除等变化,使得等式除了可爆破的变量外,只有一个变量的方程

  • 利用求根公式求解方程的根

  • 中间相遇爆破可缩短爆破时间

  • 二分法逼近

  • 当a=bt+c,bt特别大时,可以直接开方求出b

  • 通过自己生成几个样例来测试数据,有些小数可以直接忽略

  • 给一个hint,它和p和q之间有直接关系。尝试mod p或者mod q看一下,利用已知的条件,在同余式中消去另一个因数(消元),建议把题目给的条件组合组合,在我们规定的mod p或者mod q的条件下,看看都是什么结果。
    h i n t = 101 1 q ( m o d   p ) ↔ h i n t ≡ ( 1011 ) n ( m o d p ) hint=1011^{q}(mod\ p)\leftrightarrow hint\equiv (1011)^ n\pmod p\\ hint=1011q(mod p)hint(1011)n(modp)

📎 参考

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值