[MRCTF2020]Easy_RSA 1 利用到的不等式

  • 题目
import sympy
from gmpy2 import gcd, invert
from random import randint
from Crypto.Util.number import getPrime, isPrime, getRandomNBitInteger, bytes_to_long, long_to_bytes
import base64

from zlib import *
flag = b"MRCTF{XXXX}"
base = 65537

def gen_prime(N):
    A = 0
    while 1:
        A = getPrime(N)
        if A % 8 == 5:
            break
    return A

def gen_p():
    p = getPrime(1024)
    q = getPrime(1024)
    assert (p < q)
    n = p * q
    print("P_n = ", n)
    F_n = (p - 1) * (q - 1)
    print("P_F_n = ", F_n)
    factor2 = 2021 * p + 2020 * q
    if factor2 < 0:
        factor2 = (-1) * factor2
    return sympy.nextprime(factor2)


def gen_q():
    p = getPrime(1024)
    q = getPrime(1024)
    assert (p < q)
    n = p * q
    print("Q_n = ", n)
    e = getRandomNBitInteger(53)
    F_n = (p - 1) * (q - 1)
    while gcd(e, F_n) != 1:
        e = getRandomNBitInteger(53)
    d = invert(e, F_n)
    print("Q_E_D = ", e * d)
    factor2 = 2021 * p - 2020 * q
    if factor2 < 0:
        factor2 = (-1) * factor2
    return sympy.nextprime(factor2)


if __name__ == "__main__":
    _E = base
    _P = gen_p()
    _Q = gen_q()
    assert (gcd(_E, (_P - 1) * (_Q - 1)) == 1)
    _M = bytes_to_long(flag)
    _C = pow(_M, _E, _P * _Q)
    print("Ciphertext = ", _C)
'''
P_n =  14057332139537395701238463644827948204030576528558543283405966933509944444681257521108769303999679955371474546213196051386802936343092965202519504111238572269823072199039812208100301939365080328518578704076769147484922508482686658959347725753762078590928561862163337382463252361958145933210306431342748775024336556028267742021320891681762543660468484018686865891073110757394154024833552558863671537491089957038648328973790692356014778420333896705595252711514117478072828880198506187667924020260600124717243067420876363980538994101929437978668709128652587073901337310278665778299513763593234951137512120572797739181693
P_F_n =  14057332139537395701238463644827948204030576528558543283405966933509944444681257521108769303999679955371474546213196051386802936343092965202519504111238572269823072199039812208100301939365080328518578704076769147484922508482686658959347725753762078590928561862163337382463252361958145933210306431342748775024099427363967321110127562039879018616082926935567951378185280882426903064598376668106616694623540074057210432790309571018778281723710994930151635857933293394780142192586806292968028305922173313521186946635709194350912242693822450297748434301924950358561859804256788098033426537956252964976682327991427626735740
Q_n =  20714298338160449749545360743688018842877274054540852096459485283936802341271363766157976112525034004319938054034934880860956966585051684483662535780621673316774842614701726445870630109196016676725183412879870463432277629916669130494040403733295593655306104176367902352484367520262917943100467697540593925707162162616635533550262718808746254599456286578409187895171015796991910123804529825519519278388910483133813330902530160448972926096083990208243274548561238253002789474920730760001104048093295680593033327818821255300893423412192265814418546134015557579236219461780344469127987669565138930308525189944897421753947
Q_E_D =  100772079222298134586116156850742817855408127716962891929259868746672572602333918958075582671752493618259518286336122772703330183037221105058298653490794337885098499073583821832532798309513538383175233429533467348390389323225198805294950484802068148590902907221150968539067980432831310376368202773212266320112670699737501054831646286585142281419237572222713975646843555024731855688573834108711874406149540078253774349708158063055754932812675786123700768288048445326199880983717504538825498103789304873682191053050366806825802602658674268440844577955499368404019114913934477160428428662847012289516655310680119638600315228284298935201
Ciphertext =  40855937355228438525361161524441274634175356845950884889338630813182607485910094677909779126550263304194796000904384775495000943424070396334435810126536165332565417336797036611773382728344687175253081047586602838685027428292621557914514629024324794275772522013126464926990620140406412999485728750385876868115091735425577555027394033416643032644774339644654011686716639760512353355719065795222201167219831780961308225780478482467294410828543488412258764446494815238766185728454416691898859462532083437213793104823759147317613637881419787581920745151430394526712790608442960106537539121880514269830696341737507717448946962021
'''
  • 题目分析

题目分为三部分
定义 p 、 q p{、}q pq求法,加密,打印提示

  • 第一步,对 p p p进行求值
def gen_p():
    p = getPrime(1024)
    q = getPrime(1024)
    assert (p < q)
    n = p * q
    print("P_n = ", n)
    F_n = (p - 1) * (q - 1)
    print("P_F_n = ", F_n)
    factor2 = 2021 * p + 2020 * q
    if factor2 < 0:
        factor2 = (-1) * factor2
    return sympy.nextprime(factor2)

用解方程组的方式求出 p p p的值,这里用到了sympy库的symbols、solve和next函数
求解也比较简单,需要注意的是正负号和解的大小,代码如下:

from sympy import symbols, solve, nextprime
from gmpy2 import mpz
'''
solve p script 
'''

P_n = mpz(14057332139537395701238463644827948204030576528558543283405966933509944444681257521108769303999679955371474546213196051386802936343092965202519504111238572269823072199039812208100301939365080328518578704076769147484922508482686658959347725753762078590928561862163337382463252361958145933210306431342748775024336556028267742021320891681762543660468484018686865891073110757394154024833552558863671537491089957038648328973790692356014778420333896705595252711514117478072828880198506187667924020260600124717243067420876363980538994101929437978668709128652587073901337310278665778299513763593234951137512120572797739181693)
P_F_n = mpz(14057332139537395701238463644827948204030576528558543283405966933509944444681257521108769303999679955371474546213196051386802936343092965202519504111238572269823072199039812208100301939365080328518578704076769147484922508482686658959347725753762078590928561862163337382463252361958145933210306431342748775024099427363967321110127562039879018616082926935567951378185280882426903064598376668106616694623540074057210432790309571018778281723710994930151635857933293394780142192586806292968028305922173313521186946635709194350912242693822450297748434301924950358561859804256788098033426537956252964976682327991427626735740)

p, q = symbols("p, q")
exp_p = [p * q - P_n, (p - 1) * (q - 1) - P_F_n]
solve_p = solve(exp_p, [p, q])

if solve_p[0][0] < 0:
    solve_p[0][0] = - solve_p[0][0]
if solve_p[0][1] < 0:
    solve_p[0][1] = - solve_p[0][1]
assert solve_p[0][0] > 0 and solve_p[0][1] > 0

if solve_p[0][0] > solve_p[0][1]:
    temp = solve_p[0][0]
    solve_p[0][0] = solve_p[0][1]
    solve_p[0][1] = temp
assert solve_p[0][0] < solve_p[0][1]

result_num = nextprime(int(2021 * solve_p[0][0] + 2020 * solve_p[0][1]))
print(f"p = {result_num}")
root@1ad9c6992813:~# python solve_p20230909.py 
p = 479118055465195802861076643662451975441788371634793637145996217181496941123528933189555924873955626144432796811508165808623238468622989137235172879429170575533130989283494729924111842069786350352207565492494839924066840359984054733935671743878254997948119056311916492118488857415958325161799871082194782809717073
  • 第二步,对 q q q进行求值
def gen_q():
    p = getPrime(1024)
    q = getPrime(1024)
    assert (p < q)
    n = p * q
    print("Q_n = ", n)
    e = getRandomNBitInteger(53)
    F_n = (p - 1) * (q - 1)
    while gcd(e, F_n) != 1:
        e = getRandomNBitInteger(53)
    d = invert(e, F_n)
    print("Q_E_D = ", e * d)
    factor2 = 2021 * p - 2020 * q
    if factor2 < 0:
        factor2 = (-1) * factor2
    return sympy.nextprime(factor2)

这里要注意getRandomNBitInteger()函数

>>> from Crypto.Util.number import getRandomNBitInteger
>>> help(getRandomNBitInteger)
Help on function getRandomNBitInteger in module Crypto.Util.number:

getRandomNBitInteger(N, randfunc=None)
    Return a random number with exactly N-bits,
    i.e. a random number between 2**(N-1) and (2**N)-1.
    
    If :data:`randfunc` is omitted, then :meth:`Random.get_random_bytes` is used.
    
    .. deprecated:: 3.0
        This function is for internal use only and may be renamed or removed in
        the future.

>>> 

表示e的取值范围在 2 ∗ ∗ 52 2 ** 52 252 ( 2 ∗ ∗ 53 ) − 1 (2 ** 53) - 1 (253)1之间。

>>> 2 ** 52
4503599627370496
>>> 2 ** 53 -1
9007199254740991
>>> 

没看到上面两个数字的时候,我尝试用爆破e的方式去解方程,结果在听到cpu风扇疯狂输出的时候,我知道我错了,马上来查看e的取值范围。
问题要回到数论知识来解决,首先,我们知道了 n n n的值和 e ∗ d e*d ed的值,
e ∗ d e*d ed意味着逆元 d d d可以求出来
e ∗ d ≡ 1 ( m o d φ ( n ) ) e ∗ d − 1 = k ∗ φ ( n ) k = e ∗ d − 1 φ ( n ) φ ( n ) = ( p − 1 ) ∗ ( q − 1 ) k = e ∗ d − 1 ( p − 1 ) ∗ ( q − 1 ) \begin{align} e*d&\equiv 1 \pmod {\varphi(n)}\\ e*d-1&=k*\varphi(n)\\ k &= \cfrac{e*d-1}{\varphi(n)}\\ \varphi(n)&=(p-1)*(q-1)\\ k&=\cfrac{e*d-1}{(p-1)*(q-1)}\\ \end{align} eded1kφ(n)k1(modφ(n))=kφ(n)=φ(n)ed1=(p1)(q1)=(p1)(q1)ed1
这里要建立一个已知数的不等式出来
∵ p ∗ q > ( p − 1 ) ∗ ( q − 1 ) ∴ e ∗ d − 1 p ∗ q < e ∗ d − 1 ( p − 1 ) ∗ ( q − 1 ) ( 5 ) 、 ( 7 ) 两式可得: e ∗ d − 1 p ∗ q < k \begin{align} \because& p*q>(p-1)*(q-1) \\ \therefore& \cfrac{e*d-1}{p*q}<\cfrac{e*d-1}{(p-1)*(q-1)}\\ &{(5)、(7)两式可得:}\\ &\cfrac{e*d-1}{p*q}<k \end{align} pq>(p1)(q1)pqed1<(p1)(q1)ed1(5)(7)两式可得:pqed1<k
这里求出了一个 k k k的取值范围,目测可以爆破 k k k
k ∣ ( e ∗ d − 1 ) ( e ∗ d − 1 )   %   k   = =   0 \begin{align} k\mid{(e*d-1)}\\ {(e*d-1)}\ \%\ k\ ==\ 0 \end{align} k(ed1)(ed1) % k == 0
代码如下:

from sympy import symbols, solve, nextprime
from gmpy2 import mpz
'''
solve p script for 
'''

Q_n = mpz(20714298338160449749545360743688018842877274054540852096459485283936802341271363766157976112525034004319938054034934880860956966585051684483662535780621673316774842614701726445870630109196016676725183412879870463432277629916669130494040403733295593655306104176367902352484367520262917943100467697540593925707162162616635533550262718808746254599456286578409187895171015796991910123804529825519519278388910483133813330902530160448972926096083990208243274548561238253002789474920730760001104048093295680593033327818821255300893423412192265814418546134015557579236219461780344469127987669565138930308525189944897421753947)
Q_E_D = mpz(100772079222298134586116156850742817855408127716962891929259868746672572602333918958075582671752493618259518286336122772703330183037221105058298653490794337885098499073583821832532798309513538383175233429533467348390389323225198805294950484802068148590902907221150968539067980432831310376368202773212266320112670699737501054831646286585142281419237572222713975646843555024731855688573834108711874406149540078253774349708158063055754932812675786123700768288048445326199880983717504538825498103789304873682191053050366806825802602658674268440844577955499368404019114913934477160428428662847012289516655310680119638600315228284298935201)

p, q,= symbols("p, q")
k = (Q_E_D - 1) // Q_n
print(f"origin_k = {k}")

for i in range(1000):
    temp = k
    if (Q_E_D - 1) % temp == 0:
        print(f"k = {k}")
        break
    else:
        k += 1

F_n = (Q_E_D - 1) // k
exp_q = [(p - 1) * (q - 1) - F_n, p * q - Q_n]
solve_q = sovle(exp_q, [p, q])

if solve_q[0][0] < 0:
    solve_q[0][0] = - solve_q[0][0]
if solve_q[0][1] < 0:
    solve_q[0][1] = - solve_q[0][1]
assert solve_q[0][0] > 0 and solve_q[0][1] > 0

if solve_p[0][0] > solve_p[0][1]:
    temp = solve_p[0][0]
    solve_p[0][0] = solve_p[0][1]
    solve_p[0][1] = temp
assert solve_p[0][0] < solve_p[0][1]

test_num = int(2021 * solve_p[0][0] - 2020 * solve_p[0][1])

if test_num < 0:
    test_num = - test_num
assert test_num > 0

result_num = nextprime(test_num)

print(f"q = {result_num}")    
  • 这里可以看出所求的 k k k值比我们所爆破的 k k k取值范围 ( o r i g i n _ k < k ) (origin\_k<k) (origin_k<k)第一个值,也许只需要第一个值就可以吗,或许型改变后有别的值,暂时无法证明。
root@1ad9c6992813:~# python solve_q20230909.py 
origin_k = 4864856032156929
k = 4864856032156930
q = 103522908254080567893731908833394744488888808537035795737806298690667500329637779495333978590640235970136224577411196764442973344806294490943711807196503524248389571078345895360591904238447631800263183886834890874869994569137132568744715109230815151947999678985103201991854037190640567921343350745689008509490943
  • 答案
root@1ad9c6992813:~# python
Python 3.10.1 (main, Dec 21 2021, 09:01:08) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from gmpy2 import mpz, invert, powmod
>>> p = mpz(479118055465195802861076643662451975441788371634793637145996217181496941123528933189555924873955626144432796811508165808623238468622989137235172879429170575533130989283494729924111842069786350352207565492494839924066840359984054733935671743878254997948119056311916492118488857415958325161799871082194782809717073)
>>> q = mpz(103522908254080567893731908833394744488888808537035795737806298690667500329637779495333978590640235970136224577411196764442973344806294490943711807196503524248389571078345895360591904238447631800263183886834890874869994569137132568744715109230815151947999678985103201991854037190640567921343350745689008509490943)
>>> n = p * q
>>> phi_n = (p - 1) * (q - 1)
>>> e = mpz(65537)
>>> d = invert(e, phi_n)
>>> d
mpz(25619104604708417410320050530458034881600150797111063130768379814346454150671629646972653124949838220770761566801654921374186802824984507668463275780289290158483725589244523686524717462293228565604264232483295037449621276240030334223746568888207906585502690130520837378424044937400893594155562181585253037324650899305810951037961882947649166156170916206109282830877172012022926663978309814289645192403667255021702101606086348424070667948870606925663243489137252361613551633679779244536361140592813592882525095001572792576499174631148250245656269881147598790445875148296374657296186149866846454279941083071765309086328923425)
>>> c = mpz(40855937355228438525361161524441274634175356845950884889338630813182607485910094677909779126550263304194796000904384775495000943424070396334435810126536165332565417336797036611773382728344687175253081047586602838685027428292621557914514629024324794275772522013126464926990620140406412999485728750385876868115091735425577555027394033416643032644774339644654011686716639760512353355719065795222201167219831780961308225780478482467294410828543488412258764446494815238766185728454416691898859462532083437213793104823759147317613637881419787581920745151430394526712790608442960106537539121880514269830696341737507717448946962021)
>>> m = powmod(c, d, n)
>>> m
mpz(2084579198913972005798444900653791375947108611599538184307769554792061)
>>> flag = bytes.fromhex(hex(int(m))[2:])
>>> flag
b'MRCTF{Ju3t_@_31mp13_que3t10n}'
  • 脚本
from sympy import symbols, solve, nextprime
from gmpy2 import mpz, invert, powmod, isprime

def set_cmp(a, b):
    if a < 0:
        a = - a
    if b < 0:
        b = - b
    assert a > 0 and b > 0
    
    if a > b:
        temp = a
        a = b
        b = temp
    assert a < b

def solve_P(P_n, P_F_n):
    p, q = symbols("p, q")
    exp_p = [p * q - P_n, (p - 1) * (q - 1) - P_F_n]
    solve_p = solve(exp_p, [p, q])
    
    set_cmp(solve_p[0][0], solve_p[0][1])
    
    result_num = nextprime(int(2021 * solve_p[0][0] + 2020 * solve_p[0][1]))
    
    return result_num
    
def solve_Q(Q_n, Q_E_D):
    p, q,= symbols("p, q")
    k = (Q_E_D - 1) // Q_n
    
    for i in range(1000):
        temp = k
        if (Q_E_D - 1) % temp == 0:
            print(f"k = {k}")
            break
        else:
            k += 1
    
    F_n = (Q_E_D - 1) // k
    exp_q = [(p - 1) * (q - 1) - F_n, p * q - Q_n]
    solve_q = solve(exp_q, [p, q])
    
    set_cmp(solve_q[0][0], solve_q[0][1])
    
    test_num = int(2021 * solve_q[0][0] - 2020 * solve_q[0][1])
    
    if test_num < 0:
        test_num = - test_num
    assert test_num > 0
    
    result_num = nextprime(test_num) 
    
    return result_num
    
def decode_rsa(c, e, p, q):
    n = p * q
    phi_n = (p - 1) * (q - 1)
    d = invert(e, phi_n)
    flag = bytes.fromhex(hex(int(powmod(c, d, n)))[2:])
    return flag
    
P_n = mpz(14057332139537395701238463644827948204030576528558543283405966933509944444681257521108769303999679955371474546213196051386802936343092965202519504111238572269823072199039812208100301939365080328518578704076769147484922508482686658959347725753762078590928561862163337382463252361958145933210306431342748775024336556028267742021320891681762543660468484018686865891073110757394154024833552558863671537491089957038648328973790692356014778420333896705595252711514117478072828880198506187667924020260600124717243067420876363980538994101929437978668709128652587073901337310278665778299513763593234951137512120572797739181693)
P_F_n = mpz(14057332139537395701238463644827948204030576528558543283405966933509944444681257521108769303999679955371474546213196051386802936343092965202519504111238572269823072199039812208100301939365080328518578704076769147484922508482686658959347725753762078590928561862163337382463252361958145933210306431342748775024099427363967321110127562039879018616082926935567951378185280882426903064598376668106616694623540074057210432790309571018778281723710994930151635857933293394780142192586806292968028305922173313521186946635709194350912242693822450297748434301924950358561859804256788098033426537956252964976682327991427626735740)
Q_n = mpz(20714298338160449749545360743688018842877274054540852096459485283936802341271363766157976112525034004319938054034934880860956966585051684483662535780621673316774842614701726445870630109196016676725183412879870463432277629916669130494040403733295593655306104176367902352484367520262917943100467697540593925707162162616635533550262718808746254599456286578409187895171015796991910123804529825519519278388910483133813330902530160448972926096083990208243274548561238253002789474920730760001104048093295680593033327818821255300893423412192265814418546134015557579236219461780344469127987669565138930308525189944897421753947)
Q_E_D = mpz(100772079222298134586116156850742817855408127716962891929259868746672572602333918958075582671752493618259518286336122772703330183037221105058298653490794337885098499073583821832532798309513538383175233429533467348390389323225198805294950484802068148590902907221150968539067980432831310376368202773212266320112670699737501054831646286585142281419237572222713975646843555024731855688573834108711874406149540078253774349708158063055754932812675786123700768288048445326199880983717504538825498103789304873682191053050366806825802602658674268440844577955499368404019114913934477160428428662847012289516655310680119638600315228284298935201)
Ciphertext =  mpz(40855937355228438525361161524441274634175356845950884889338630813182607485910094677909779126550263304194796000904384775495000943424070396334435810126536165332565417336797036611773382728344687175253081047586602838685027428292621557914514629024324794275772522013126464926990620140406412999485728750385876868115091735425577555027394033416643032644774339644654011686716639760512353355719065795222201167219831780961308225780478482467294410828543488412258764446494815238766185728454416691898859462532083437213793104823759147317613637881419787581920745151430394526712790608442960106537539121880514269830696341737507717448946962021)

p = solve_P(P_n, P_F_n)
q = solve_Q(Q_n, Q_E_D)
c = Ciphertext
e = mpz(65537)
assert isprime(p) and isprime(q)
flag = decode_rsa(c, e, p, q)
print(flag)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值