RSA攻击:模数分解

news2024/11/17 10:05:01

目录

一、模数分解总览

        1.1直接分解法

        1.2费马分解与Pollard_rho分解

        1.3公约数分解

        1.4其他模数分解

二、实战特训

        2.1[黑盾杯 2020]Factor

       2.2[GWCTF 2019]babyRSA

      2.3[LitCTF 2023]yafu (中级)

        2.4[RoarCTF 2019]RSA

      2.5[CISCN 2022 西南]rsa

三、总结


一、模数分解总览

        1.1直接分解法

           在RSA的通信流程中,对外保密的是私钥,但是究其本质对外隐藏的是大素数P,Q。而正是大数分解难题的原因,使得即使暴露N,即PQ之积的值暴露,破解难度也依旧很大。所以,我们只需要掌握缺失的信息P,Q即可完成解密

          但是如果N值取的很小,我们通常可以进行暴力分解,从而获取P,Q。顺带一提,在工业中我们认为2048bit以上的N是安全的。但是,在CTF竞赛中,我们几乎不会遇到2048bit以上的素数分解。所以,这里我们可以放心使用。稍后,笔者会给处自己对与N很小的理解。

          使用条件:在阅读部分书籍的密码学(crypto)部分的解析,以及一些题目经验,大部分适合直接数模分解的N一般小于512bit。该使用条件,是笔者的拙见,欢迎大家在评论区讨论。

        1.2费马分解与Pollard_rho分解

          在1.1中我们提及了,如果N值很小,那么我们可以直接分解。但是如果N值大,我们将寸步难行。可是,这种难度在于直接分解,而不是利用部分数学技巧与原理。

          例如在费马分解中,当P,Q两个值过于接近,也就是P-Q的值很小。此时,我们就可以令A = (P + Q) / 2, B = (P - Q) / 2 则 N = A^2 - B^2。其中,在具体算法实现的过程中,因为P - Q很小,所以我们可以枚举爆破。而且根据 N = PQ,且N值一般已知,就有 A^2 = B^2 + N。

          而在Pollard_rho分解中,则恰恰相反。该分解说明当P,Q相差过大时,可以被暴力分解。从费马分解的角度说,如果P - Q过大,那么P + Q就会过小。因此可以枚举P + Q暴力破解。然而该分解方式有一定的数学原理(本菜狗没学原理,赶比赛就停在应用层面先)。

          Pollard算法的原理大体是通过某一种方式获取得到A,B值。计算p = gcd(a - b, n),直到p不为1,或者a,b出现循环。返回一个“因子”p。接着,我们可以递归的计算Pollard(p)与Pollard(n/p),值得一提得是我们p == n时,返回的就是n是一个质数退出。一般我们认为B = A^2 + 1。

          这个方法很美好,但是显示很骨感。这种分解方式建立于我们知道P - Q的状态。然而,现实和比赛中,P、Q都是被隐藏的,所以我们很难判断是否可以使用这种方式破解。SO!我们只能抱着尝试的方法使用该方法

        1.3公约数分解

          公约数分解一般是建立在多组信息(密文)在加密过程中,采取了相同的大素数P。因此,我们可以通过gcd来获取一个因此P,进而得知另外一个因子。

          使用条件:出现多组密文。

        1.4其他模数分解

          一般这种分解方式也是最难的,因为会考察选手的数学能力。也就是题目会给出一些额外的数学表达式,选手根据表达式合理爆破。或者我们可以使用factordb.com进行分解。但是当数字过大时,网站会显示补全,hhh。

          使用条件:当上述方式失效,或者题目给出额外的数学式子

二、实战特训

        2.1[黑盾杯 2020]Factor

          点击这里,跳转至题目

          在本道题中,我们获取得到了一下信息,如图所示。

          这道题有许多的尝试方法,如下:

          1.因为n比较小,可以直接分解n

          2. 因为e比较小以及给出了其他的数学关系,我们可以使用小加密明文爆破+数学关系判断。

          相对来讲,分解n更为简单。所以,我们优先尝试。注意:密码学更多的是尝试,而不是一眼定方法。使用yafu工具,我们获取一下因子。

          因此,我们可以编写一下代码段。

from Crypto.Util.number import *
import sympy
import primefac
from libnum import n2s
import gmpy2
import wienerAttack

n = 3454083680130687060405946528826790951695785465926614724373
e = 3
c = 1347530713288996422676156069761604101177635382955634367208
# gcd(m, n) = 1

p = 17100682436035561357
q = 17172929050033177661
r = 11761833764528579549

phi = (q - 1) * (r - 1) * (p - 1)
d = primefac.modinv(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))

           但是,我们在运行时,发现代码报错。别急不是因为你错了,可能是因为出现了“假素数”,即(某一大素数 - 1) 是 e 的倍数。因此经过排查,发现(p - 1) % e == 0。因此剔除p。修改代码得到。

from Crypto.Util.number import *
import sympy
import primefac
from libnum import n2s
import gmpy2
import wienerAttack

n = 3454083680130687060405946528826790951695785465926614724373
e = 3
c = 1347530713288996422676156069761604101177635382955634367208
# gcd(m, n) = 1

p = 17100682436035561357
q = 17172929050033177661
r = 11761833764528579549

phi = (q - 1) * (r - 1)
d = primefac.modinv(e, phi)
m = pow(c, d, q * r)
print(long_to_bytes(m))

          最后获取旗帜FLAG{3_RSA}。

       2.2[GWCTF 2019]babyRSA

          点击这里,跳转至题目

          根据题目附件,我们可以获取得到以下信息(未全部显示)。

          以及以下数学式:c1 = F1 + F2, c2 = F1^3 + F2^3。以及p < q。

          在这里我们获取到的信息是n值大概在2048bit。而且给出其他表达式,所以我们尝试其他数模分解法。

          首先,我们明确思路。我们需要获取c1, c2来计算得到F1、F2。然后,将F1、F2转职为字符串即可。而获取c1、c2我们需要获取p,q。所以,现在最大的难题在于p,q。在这里说明两种方式。

          方法1:关注到p,q是相邻的两个素数,如果你知道素数分布规律,即他们之间相差lnx。所以我们可以判断出 q - p 大约在1000。所以我们可以使用费马分解

          使用yafu分解得到以下结果。

         方法2(推荐掌握): 根据p < q的关系,我们可以判断出 n > p^2,所以sqrt(n) > p。所以,我们可以猜想 nextprime(sqrt(n)) == nextprime(p) == q。证明如下:

          n = n'^2 = pq = (n''^2 - d^2) ==> n'' = (p + q) / 2 > n' > p,也就是说 n' - p < q - p.建议画一个数轴理解。

import gmpy2
import sympy

N=636585149594574746909030160182690866222909256464847291783000651837227921337237899651287943597773270944384034858925295744880727101606841413640006527614873110651410155893776548737823152943797884729130149758279127430044739254000426610922834573094957082589539445610828279428814524313491262061930512829074466232633130599104490893572093943832740301809630847541592548921200288222432789208650949937638303429456468889100192613859073752923812454212239908948930178355331390933536771065791817643978763045030833712326162883810638120029378337092938662174119747687899484603628344079493556601422498405360731958162719296160584042671057160241284852522913676264596201906163

n = gmpy2.iroot(N, 2)[0]
q = sympy.nextprime(n)
p = n // q

          运行结果如下:其中1038 == q - p --> 验证素数分布,方法1

 

          两个方法没有优劣之分,知识方法二更贴合题意。方法一更快,但是需要我们判断p,q对应的数字。所以,按需对应选择。

          接下来获取c1,c2就简单了。

imoprt primefac

phi = (p-1)*(q-1)
d = primefac.modinv(e, phi)

c1 = powmod(m1, d, N)
c2 = powmod(m2, d, N)

        接下来获取F1,F2。构造二次方程x^2 - (F1 + F2)x + F1F2 = 0。使用c1,c2表示就为x^2 - c1x + (c1^2 - c2/c1)/3 = 0

A = gmpy2.mpz(1)
B = gmpy2.mpz(-c1)
C = gmpy2.mpz((c1*c1 - c2//c1)//3)
delta = gmpy2.mpz(gmpy2.iroot(B*B - 4*A*C,2)[0])
F1 = (-B - delta) // 2
F2 = (-B + delta) // 2

flag1 = long_to_bytes(F1)
flag2 = long_to_bytes(F2)
print(flag1 + flag2, flag2 + flag1)

          得到旗帜FLAG{f709e0e2cfe7e530ca8972959a1033b2}

          当然你也可以使用sympy.solve来获取根。

      2.3[LitCTF 2023]yafu (中级)

        点击这里,跳转至题目

        这道题比较简单,题目就提示了使用yafu。一共会获取15个因子,这道题额外考察了欧拉函数的性质问题。解决代码如下。

p1=2151018733
p2=2201440207
p3=2315495107
p4=2585574697
p5=2719600579
p6=2758708999
p7=2767137487
p8=2906576131
p9=2923522073
p10=3354884521
p11=3355651511
p12=3989697563
p13=4021078331
p14=4044505687
p15=4171911923


phi = (p1 - 1) * (p2 - 1) * (p3 - 1) * (p4 - 1) * (p5 - 1) * (p6 - 1) * (p7 - 1) * (p8 - 1) * (p9 - 1) * (p10 - 1) * (p11 - 1) * (p12 - 1) * (p13 - 1) * (p14 - 1) * (p15 - 1)
d = gmpy2.invert(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))

        2.4[RoarCTF 2019]RSA

          点击这里,跳转至题目

         我们可以获取信息如下。

          在这里,我们知道P、Q可能相差过大,同时我们也获取了额外信息。所以我们可以尝试使用Pollard和其他数模分解法。

          尝试Pollard,发现预估等待时间 >= 1h。果断停止尝试。

          开始尝试其他数模分解。关注到有2019次方,所以枚举x,y的范围不会特别大,我们可以接受。

A =  2683349182678714524247469512793476009861014781004924905484127480308161377768192868061561886577048646432382128960881487463427414176114486885830693959404989743229103516924432512724195654425703453612710310587164417035878308390676612592848750287387318129424195208623440294647817367740878211949147526287091298307480502897462279102572556822231669438279317474828479089719046386411971105448723910594710418093977044179949800373224354729179833393219827789389078869290217569511230868967647963089430594258815146362187250855166897553056073744582946148472068334167445499314471518357535261186318756327890016183228412253724

for x in range(1, 1000):
    for y in range(1, 1000):
        D = x % y
        if (D != 0) :
            f=(((y%x)**5)%D)**2019+y**316+(y+1)//x
            if (f == A) :
                print(x, y)
                break

        获得x = 2, y = 83

        然后我们关注到以下两个表达式:

          因此n = p * q > x*y*z^2, 也就是 n / x / y > z^2,那我们可以像2.2那样,获取q

n =  117930806043507374325982291823027285148807239117987369609583515353889814856088099671454394340816761242974462268435911765045576377767711593100416932019831889059333166946263184861287975722954992219766493089630810876984781113645362450398009234556085330943125568377741065242183073882558834603430862598066786475299918395341014877416901185392905676043795425126968745185649565106322336954427505104906770493155723995382318346714944184577894150229037758434597242564815299174950147754426950251419204917376517360505024549691723683358170823416757973059354784142601436519500811159036795034676360028928301979780528294114933347127

x = 2
y = 83

n1 = n // 166 #可以存放
q = sympy.nextprime(gmpy2.iroot(n1, 2)[0])
p = n // q
assert isPrime(q) and isPrime(p)

print("OK") #确认步骤2正确
print(p, q)

        获得p,q后,我们就可以开始正是解码

c =  41971850275428383625653350824107291609587853887037624239544762751558838294718672159979929266922528917912189124713273673948051464226519605803745171340724343705832198554680196798623263806617998072496026019940476324971696928551159371970207365741517064295956376809297272541800647747885170905737868568000101029143923792003486793278197051326716680212726111099439262589341050943913401067673851885114314709706016622157285023272496793595281054074260451116213815934843317894898883215362289599366101018081513215120728297131352439066930452281829446586562062242527329672575620261776042653626411730955819001674118193293313612128

e = 0x10001 # e = 65537
phi = (p - 1) * (q - 1)
d = primefac.modinv(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))

          获取旗帜FLAG{wm-l1l1ll1l1l1l111ll}

      2.5[CISCN 2022 西南]rsa

          点击这里,跳转至题目

          题目附件内容如下:

from Crypto.Util.number import *
import gmpy2

flag = b'XXXXXXXX'
p1 = getPrime(700)
r1 = getPrime(700)
for i in range(10):
    q1 = 5*p1+i
n = p1*q1*r1
p3 = pow(p1,3,n)
q3 = pow(q1,3,n)

print(p3)
print(q3)
'''
p3 = 29914513810588158800677413177910972738704129106546850855032986405861482276089830788972187432277517348644647399654780884571794069905291936470934226328931651386658328163535027343107140438177837479649822914209171476632450951930287641742344330471734177295804718555774395704231261550376220154493373703096062950390869299905383682611063374747752091585836452902373843865043412096365874638466683035848817858586173172058756256354758712684819253211761289032789542371351760915771791997388241121078055468403109260493642435791152671979552597191217179672328555740595434990908530985477314228867209314472001848844089467987561661918366232980944933533
q3 = 66208618374366130551979192465001581263127328176551695213970812805980115496523825511250542987452691413485117902772315362811067501379171731387904074565035353566976164797769439898266222919741874340315356585585077141595328441423323822407738375537476582506440045835592730211502035261968878999959340204806442390319739977816872969200022096331677277225467021553564212725120939434924481787524609852608476848761521446441776154400518315701988027274150425936061679275540502720782853648148897480117033152064922234451671636288396704170234613549011854618414776342798740690128675106027908639984431432591397555541420243824539205614036979987830125678
'''
P = getPrime(1024)
Q = getPrime(1024)
N = P * Q
E = 65537
lcm = gmpy2.lcm(P-1, Q-1)
e1 = gmpy2.invert(p1, lcm)
e2 = gmpy2.invert(r1, lcm)
m = bytes_to_long(flag)
c = pow(m, E, N)

print(lcm)
print(c)
print(N)
'''
lcm = 4292158730589770192682795435047249488185453170529228019750042608688907718268448193363838203887391025871515871000364259326343790645215256385842265899206372365402431198699714374850409466996627163968391249416054093529090485677808301343590811445080871279796162536469847469761747058736980603093722710824453312207182881241846080117790728778291633761198069016865260030288832065807438020772711645648333908622890343009942617559434851450007195025869850769670769715654662127278293639938359741401336592219730356884542179574372134014927006215640945952229142436595334916765255426954857520777553915330597952622785359222832224632624
c = 4288727484183191191687364666620023549392656794153112764357730676861570386983002380982803054964588111708662498647767438881892355599604826306427809017097724346976778230464708540600157055782723189971534549543664668430013171469625043063261219462210251726207552819381767396148632877168530609902046293626355744288863460554297860696918890189350721960355460410677203131993419723440382095665713164422367291153108363066159712951217816814873413423853338021627653555202253351957999686659021298525147460016557904084617528199284448056532965033560516083489693334373695545423561715471204868795248569806148395196572046378679014697206
N  = 17168634922359080770731181740188997952741812682116912079000170434755630873073792773455352815549564103486063484001457037305375162580861025543369063596825489461609724794798857499401637867986508655873564997664216374116361942711233205374363245780323485119184650145879389879046988234947922412374890843297813248828996855478005656041814919367820336728271583686844991928889831691815821365423570311291064846736832327637944358854661523107817781673029406341843040857813841671405147146887291204140157388049394514390098066284975682117038362207142272098796924412602725857521665773622056312191400612944442008222587867782281556388669
'''

          这道题纯吓人,因为密文跟p3,q3没关系。所以我们不需要用到它。注意的是,这里phi用lcm来表示了。

d = primefac.modinv(E, lcm)
m = pow(c, d, n)
primt(long_to_bytes(m))

          获得FLAG{h3ll0_wo21d!}

三、总结

          在这里,涵盖了大部分的模数分解法的题目做法。我们分析了如何判断以及尝试的优先级。如何根据代码报错,进行实时的调整、排错。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1060201.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

进程调度的时机,切换与过程以及方式

1.进程调度的时机 进程调度&#xff08;低级调度〉&#xff0c;就是按照某种算法从就绪队列中选择一个进程为其分配处理机。 1.需要进行进程调度与切换的情况 1.当前运行的进程主动放弃处理机 进程正常终止运行过程中发生异常而终止进程主动请求阻塞&#xff08;如等待l/O)…

(粗糙的笔记)动态规划

动态规划算法框架&#xff1a; 问题结构分析递推关系建立自底向上计算最优方案追踪 背包问题 输入&#xff1a; n n n个商品组成的集合 O O O&#xff0c;每个商品有两个属性 v i v_i vi​和 p i p_i pi​&#xff0c;分别表示体积和价格背包容量 C C C 输出&#xff1a; …

【C语言】函数的定义、传参与调用(二)

&#x1f497;个人主页&#x1f497; ⭐个人专栏——C语言初步学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读&#xff1a; 1. 函数的嵌套调用 1.1 什么是嵌套调用 1.2 基础实现 1.3 调用流程解析 2. 函数的链式访问 2.1 …

算法通过村第十二关-字符串|青铜笔记|隐形的王者

文章目录 前言转换成小写字母字符串转换整数总结 前言 提示&#xff1a;为别人而活着&#xff0c;其实是最简单的一种活法。 --蔡崇达《命运》 字符串本身并不是一种数据结构&#xff0c;但是由于其本身的特殊性&#xff0c;额可以产生很多特殊的算法问题。另外&#xff0c;字符…

Java之并发工具类的详细解析

3. 并发工具类 3.1 并发工具类-Hashtable Hashtable出现的原因 : 在集合类中HashMap是比较常用的集合对象&#xff0c;但是HashMap是线程不安全的(多线程环境下可能会存在问题)。为了保证数据的安全性我们可以使用Hashtable&#xff0c;但是Hashtable的效率低下。 代码实现 …

数据源报表

1.新建报表 2.新建数据集 3.维护数据源 支持的数据库还是蛮多哈 4.选择数据源表 5.编写sql 编码&#xff1a;SQL数据集的标识 注&#xff1a;避免特殊字符和_名称&#xff1a;SQL数据集的名称是否集合&#xff1a;否为单数据&#xff1b;是为多数据列表&#xff0c;如果多条数据…

MapStruct初窥门径

一、介绍 MapStruct相比于BeanUtils性能更高&#xff0c;能够实现DO&#xff0c;DTO&#xff0c;VO之间的转换&#xff0c;达到解耦合的目的 二、使用前提 添加依赖 <dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifa…

第八章 Linux文件系统权限

目录 8.1 文件的一般权限 1.修改文件或目录的权限---chmod命令 2.对于文件和目录&#xff0c;r&#xff0c;w&#xff0c;x有不同的作用&#xff1a; 3.修改文件或目录的所属主和组---chown,chgrp 8.2 文件和目录的特殊权限 三种通过字符描述文件权限 8.3 ACL 权限 1.A…

基于Java的药店管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

1500*A. Boredom(DP)

Problem - 455A - Codeforces Boredom - 洛谷 解析&#xff1a; 首先统计每个数的个数&#xff0c;并且统计出最大值mx。 问题转换为&#xff0c;从1-mx 中选择任意个数字&#xff0c;使其都不相邻&#xff0c;求最大的总和。 开始没有思路&#xff0c;以为直接选取偶数位和奇…

项目进展(七)-焊接ADS1285及其外围电路,学习芯片的SPI部分

一、焊接芯片及其外围电路 总体焊接过程没有出现什么大问题&#xff0c;也算顺利&#xff0c;下一步主要是根据SPI来编写代码&#xff0c;配置该芯片。 焊接之后的PCB如下(手工焊接&#xff0c;比较丑陋&#xff0c;哈哈哈哈) 之后测试了4.096V参考电压和晶振输出&#xff0c…

CART算法解密:从原理到Python实现

目录 一、简介CART算法的背景例子&#xff1a;医疗诊断 应用场景例子&#xff1a;金融风控 定义与组成例子&#xff1a;电子邮件分类 二、决策树基础什么是决策树例子&#xff1a;天气预测 如何构建简单的决策树例子&#xff1a;动物分类 决策树算法的类型例子&#xff1a;垃圾…

长时序栅格数据缺失值插补

长时序栅格数据经常会出现一些缺失值&#xff0c;会对后续的分析造成很大的不便。这便需要利用一些插值算法对这些缺失数据进行填补&#xff0c;奇异谱分析&#xff08;SSA&#xff09;便是常用的一种插值方法。更多内容可见公众号GeodataAnalysis。 简介 在时间序列分析中&a…

处理机调度的概念,层次联系以及七状态模型

1.基本概念 当有一堆任务要处理&#xff0c;但由于资源有限&#xff0c;这些事情没法同时处理。 这就需要确定某种规则来决定处理这些任务的顺序&#xff0c;这就是“调度”研究的问题。 2. 三个层次 1.高级调度&#xff08;作业调度&#xff09; 高级调度&#xff08;作业…

websocket逆向【python实现websocket拦截】

python实现websocket拦截 前言一、拦截的优缺点优点:缺点:二、实现方法1.环境配置2.代码三、总结前言 开发者工具F12,筛选ws后,websocket的消息是这样显示的,如何获取这里面的消息呢? 以下是本篇文章正文内容 一、拦截的优缺点 主要讲解一下websocket拦截的实现,现在…

结构和基本尺寸

声明 本文是学习GB-T 586-2015 船用法兰铸钢止回阀. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了法兰连接尺寸和密封面按 CB/T 4196、GB/T 2501 的船用法兰铸钢止回阀(以下简 称止回阀)的分类和标记、要求、试验方法、检验规…

sheng的学习笔记-【中英】【吴恩达课后测验】Course 1 - 神经网络和深度学习 - 第四周测验

课程1_第4周_测验题 目录&#xff1a;目录 第一题 1.在我们的前向传播和后向传播实现中使用的 “缓存” 是什么&#xff1f; A. 【  】它用于在训练期间缓存成本函数的中间值。 B. 【  】我们用它将在正向传播过程中计算的变量传递到相应的反向传播步骤。它包含了反向传…

Linux系统编程系列之条件变量

一、什么是条件变量 条件变量是一种同步互斥机制&#xff0c;通常与互斥锁一起使用以实现线程之间的通信和同步。 二、问题的引入 先来看一个例子:小楠是一名在校学生&#xff0c;每个月都会从父母那里得到一笔生活费。现在她的钱花光了&#xff0c;想要去取钱。但是很显然取钱…

Redis-缓存穿透,缓存击穿,缓存雪崩

缓存穿透&#xff0c;缓存击穿&#xff0c;缓存雪崩 缓存穿透处理方案解决方案1 缓存空数据解决方案2 布隆过滤器 缓存击穿处理方案解决方案 1 互斥锁解决方案2 逻辑过期 缓存雪崩处理方案解决方案 1 给不同的key的过期时间设置添加一个随机值&#xff0c;降低同一个时段大量ke…

柯桥生活口语学习,英语中初次见面,除了Nice to meet you,还能说什么?

第一印象非常重要。所以当你第一次见到某人时&#xff0c;留下一个好印象很重要&#xff0c;尤其是当你面对一个重要的工作或者面对某个对你来说可能非常特别的人时。 下面我列出了一些最常用的说“很高兴见到你”的表达方法&#xff0c;也包括对方的回答&#xff0c;除了nice …