buuctf的RSA(五)

[RoarCTF2019]RSA

     一看到题目,我就有些蒙了,A是代表了什么,

先来分解n

接下来可以暴力破解e了,因为e没有给出来,应该不会太大,猜测是四位数字


import gmpy2
import libnum
from Crypto.Util.number import long_to_bytes

A = 2683349182678714524247469512793476009861014781004924905484127480308161377768192868061561886577048646432382128960881487463427414176114486885830693959404989743229103516924432512724195654425703453612710310587164417035878308390676612592848750287387318129424195208623440294647817367740878211949147526287091298307480502897462279102572556822231669438279317474828479089719046386411971105448723910594710418093977044179949800373224354729179833393219827789389078869290217569511230868967647963089430594258815146362187250855166897553056073744582946148472068334167445499314471518357535261186318756327890016183228412253724
n = 117930806043507374325982291823027285148807239117987369609583515353889814856088099671454394340816761242974462268435911765045576377767711593100416932019831889059333166946263184861287975722954992219766493089630810876984781113645362450398009234556085330943125568377741065242183073882558834603430862598066786475299918395341014877416901185392905676043795425126968745185649565106322336954427505104906770493155723995382318346714944184577894150229037758434597242564815299174950147754426950251419204917376517360505024549691723683358170823416757973059354784142601436519500811159036795034676360028928301979780528294114933347127
c = 41971850275428383625653350824107291609587853887037624239544762751558838294718672159979929266922528917912189124713273673948051464226519605803745171340724343705832198554680196798623263806617998072496026019940476324971696928551159371970207365741517064295956376809297272541800647747885170905737868568000101029143923792003486793278197051326716680212726111099439262589341050943913401067673851885114314709706016622157285023272496793595281054074260451116213815934843317894898883215362289599366101018081513215120728297131352439066930452281829446586562062242527329672575620261776042653626411730955819001674118193293313612128

print(len(str(A)))

q = 842868045681390934539739959201847552284980179958879667933078453950968566151662147267006293571765463137270594151138695778986165111380428806545593588078365331313084230014618714412959584843421586674162688321942889369912392031882620994944241987153078156389470370195514285850736541078623854327959382156753458569
p = 139916095583110895133596833227506693679306709873174024876891023355860781981175916446323044732913066880786918629089023499311703408489151181886568535621008644997971982182426706592551291084007983387911006261442519635405457077292515085160744169867410973960652081452455371451222265819051559818441257438021073941183

phi = (p - 1) * (q - 1)
# ed=k*phi+1
for e in range(100000):
    if gmpy2.gcd(e, phi) == 1:
        d = gmpy2.invert(e, phi)
        m = gmpy2.powmod(c, d, n)
        m = libnum.n2s(int(m))      #libnum.n2s 函数用于将整数转换为字节串
        if 'CTF' in str(m):
            print(m)
            break


 

根据以上,似乎没有发挥A的作用,没有直接参与RSA的解密过程

看了其他大神的wp,似乎常规解法是根据A来推测x,y的范围,解出x,y,根据q与iroot(n/(x*y),2)的值相接近.从而可以得出p,q的值.

import gmpy2

count = 0
min_gap = 99999
max_gap = 0
p = 21679967315669523832823488086602270908640556452221643267343405142715107120582778258062778680925402382895255206278432676733248308929062714997512704088603667
for i in range(1000):
    pn = gmpy2.next_prime(p)
    count = count + pn - p
    max_gap = max(max_gap, pn - p)
    min_gap = min(min_gap, pn - p)
    p = pn

print(count / 1000)
print(min_gap)
print(max_gap)

这是

155位(10进制)左右素数之间gap的大小,然后确定爆破的范围,

分析x,y的关系

      A转化为2进制后是2017位,而说明第一项只能为1,相比于第二项,第三项可以忽略,所以对A开316次根,得到y的估计值为83,考虑忽略项,实际y的值小于等于83

明显可以知道,x=2,y=83

import math
A = 2683349182678714524247469512793476009861014781004924905484127480308161377768192868061561886577048646432382128960881487463427414176114486885830693959404989743229103516924432512724195654425703453612710310587164417035878308390676612592848750287387318129424195208623440294647817367740878211949147526287091298307480502897462279102572556822231669438279317474828479089719046386411971105448723910594710418093977044179949800373224354729179833393219827789389078869290217569511230868967647963089430594258815146362187250855166897553056073744582946148472068334167445499314471518357535261186318756327890016183228412253724
for y in range(2, 85):
    for x in range(2, 100):
        try:
            a=(((y%x)**5)%(x%y))**2019+y**316+(y+1)//x
            if a-A <= 1000 and a- A>= -1000:
                print(x, y, a-A)
        except:
            pass

暴力破解了x,y,

后面就可以根据x,y推出p,q了

import gmpy2

n = 117930806043507374325982291823027285148807239117987369609583515353889814856088099671454394340816761242974462268435911765045576377767711593100416932019831889059333166946263184861287975722954992219766493089630810876984781113645362450398009234556085330943125568377741065242183073882558834603430862598066786475299918395341014877416901185392905676043795425126968745185649565106322336954427505104906770493155723995382318346714944184577894150229037758434597242564815299174950147754426950251419204917376517360505024549691723683358170823416757973059354784142601436519500811159036795034676360028928301979780528294114933347127


def trybomb(t):
    print('when t is ' + str(t) + ' :')
    pv = gmpy2.isqrt(n // t) - 2000
    count = 1
    while count <= 1000:
        p = gmpy2.next_prime(pv)
        count += 1
        if n % p == 0:
            print('p = ', p)
            q = n // p
            break
        else:
            pv = p


trybomb(166)
print('finish')

最后还是暴力破解出来e

[RoarCTF2019]babyRSA

题目看起来很复杂,但是你去将n分解一下,发现了刚好可以分解成三个素数,就变得很简单了

直接得到了flag

import libnum
c=75700883021669577739329316795450706204502635802310731477156998834710820770245219468703245302009998932067080383977560299708060476222089630209972629755965140317526034680452483360917378812244365884527186056341888615564335560765053550155758362271622330017433403027261127561225585912484777829588501213961110690451987625502701331485141639684356427316905122995759825241133872734362716041819819948645662803292418802204430874521342108413623635150475963121220095236776428
e=4097  #将0x1001转化为十进制数
r=1276519424397216455160791032620569392845781005616561979809403385593761615670426423039762716291920053306063214548359656555809123127361539475238435285654851
p=5057572094237208127867754008134739503717927865750318894982404287656747895573075881186030840558129423864679886646066477437020450654848839861455661385205433
q=13242175493583584108411324143773780862426183382017753129633978933213674770487765387985282956574197274056162861584407275172775868763712231230219112670015751
n=p*q*r
phi =(p-1)*(q-1)*(r-1)
d=libnum.invmod(e,phi)
m=pow(c,d,n)
print(libnum.n2s(m))

    维纳攻击:

            e的指数很大(理论上d<N**0.25作为攻击的实现)

实现Wiener攻击,这是一种针对具有较小解密指数d的RSA私钥的恢复

维纳攻击你要先知道以下几个知识点

        连分数:

      连分数的定义

连分数是一种特殊的分数表示法,其形式如下:

  

      其中,a0​是某个整数,而所有其他的数an​(n>0)都是正整数。连分数可以是有限的(即终止于某个an​),也可以是无限的(即不终止)。在数学中,任何一个有理数都可以表示为有限连分数,而任何一个无理数都可以表示为无限连分数。

      连分数在RSA中的应用

  1. 理论基础:连分数在RSA中的应用通常与Wiener攻击有关。Wiener攻击是一种利用RSA私钥的某些性质(如解密指数d较小)来恢复私钥的攻击方法。在这种攻击中,连分数被用来求解与私钥相关的同余方程。
  2. Wiener攻击:Wiener攻击基于一个数学定理,该定理允许我们根据给定的实数a和某个条件来求解整数p和q。在RSA的上下文中,这个实数a可能与私钥的某些属性相关,而p和q则是模数N的质因子。通过求解与a相关的连分数,攻击者可以逐步逼近p和q的值,并最终恢复私钥。
  3. 实际运用:在实际运用中,Wiener攻击需要满足一定的条件才能成功。例如,解密指数d必须小于某个阈值(这个阈值通常与模数N的大小有关)。此外,攻击者还需要能够获取到足够多的关于私钥的信息(如公钥e和模数N)。如果这些条件都得到满足,那么攻击者就可以使用连分数技术来恢复私钥。

        韦达定理

  韦达定理在二次方程 ax^2 + bx + c = 0

      根的和等于系数 b 的相反数除以系数 a,即 x_1 + x_2 = -b/a

       根的积等于常数项 c 除以系数 a,即 x_1 * x_2 = c/a

         来自己出一道题目

import libnum
import random
#生成随机的素数
p=libnum.generate_prime(512)
q=libnum.generate_prime(512)
m="flag{h3ll0-w0rld}"
#字符串转数字
m=libnum.s2n(m)
n=p*q
phi_n=(p-1)*(q-1)
#计算d
while True:
    nbits=1024
    d=random.getrandbits(nbits //4)
    if (libnum.gcd(d,phi_n)  ==1 and 36*pow(d,4) <n):
        break

#计算出e
e=libnum.invmod(d,phi_n)
c=pow(m,e,n)
print("n=",n)
print("e=",e)
print("c=",c)

完整代码:

import gmpy2
import libnum

def continuedFra(x, y):
   # #此函数用于计算x/y的连分数表示。它使用辗转相除法(欧几里得算法)来逐步减少分数,直到分母y变为0。
  
    cf = []
    while y:
        cf.append(x // y)
        x, y = y, x % y
    return cf
def gradualFra(cf):
  # #这个函数接收一个连分数列表cf,并返回列表最后一个元素的渐近分数。它通过逆序遍历连分数列表,并使用特定的公式来计算分子和分母
    numerator = 0
    denominator = 1
    for x in cf[::-1]:
        # 这里的渐进分数分子分母要分开
        numerator, denominator = denominator, x * denominator + numerator
    return numerator, denominator
def solve_pq(a, b, c):
    """使用韦达定理解出pq,x^2−(p+q)∗x+pq=0
    :param a:x^2的系数
    :param b:x的系数
    :param c:pq
    :return:p,q
    """
    par = gmpy2.isqrt(b * b - 4 * a * c)
    return (-b + par) // (2 * a), (-b - par) // (2 * a)
def getGradualFra(cf):
    """计算列表所有的渐近分数
    :param cf: 连分数列表
    :return: 该列表所有的渐近分数
    """
    gf = []
    for i in range(1, len(cf) + 1):
        gf.append(gradualFra(cf[:i]))
    return gf


def wienerAttack(e, n):
   #它首先计算公钥e相对于模数n的连分数表示,然后使用getGradualFra函数生成所有可能的渐近分数。对于每个渐近分数(d, k),它检查是否满足(e * d - 1) % k == 0。如果满足,它尝试使用(e * d - 1) // k作为phi(n)的近似值,并使用solve_pq函数尝试分解n以找到p和q。如果找到了有效的p和q,那么它会计算私钥d并返回
    cf = continuedFra(e, n)
    gf = getGradualFra(cf)
    for d, k in gf:
        if k == 0: continue
        if (e * d - 1) % k != 0:
            continue
        phi = (e * d - 1) // k
        p, q = solve_pq(1, n - phi + 1, n)
        if p * q == n:
            return d
n= 92524912824457455478469479834145192399327339422419976426014024967106017250525784362251809870851330233714073309745926853809722723590007799727853843200857232710763391103522003213039635901415434225633578811817814757637106456030410677721613532510535968977938933636723316561537077411888416685226759599589065857021
e= 54061685907559431614093395962586317025387379705558008571034720802508811703397874391457074838986258081858042924777974376782261530254408986545475988227306300250798769475295193119450403415247506835654081051816773486037227848499432844796357648121686484398862179371192675792796946629089692057399103015987899220553
c= 75914541873509926793052668657170821143574989686045126269695603145212114658529526002484357527707015025922193311737442791537506782543615634954764108902795246498210682486601649383685688201749284019581721635618585026491003845052815757860692633274121793700743169931534720441816541558209434925881957085594022520969


d=wienerAttack(e, n)
m=pow(c, d, n)
print(libnum.n2s(m).decode())

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值