rsa1
rsa.py
1 | from flag import FLAG |
enc
1 | 16396023285324039009558195962852040868243807971027796599580351414803675753933120024077886501736987010658812435904022750269541456641256887079780585729054681025921699044139927086676479128232499416835051090240458236280851063589059069181638802191717911599940897797235038838827322737207584188123709413077535201099325099110746196702421778588988049442604655243604852727791349351291721230577933794627015369213339150586418524473465234375420448340981330049205933291705601563283196409846408465061438001010141891397738066420524119638524908958331406698679544896351376594583883601612086738834989175070317781690217164773657939589691476539613343289431727103692899002758373929815089904574190511978680084831183328681104467553713888762965976896013404518316128288520016934828176674482545660323358594211794461624622116836 |
参考:Ashen师兄的比赛wp,以及https://github.com/7feilee/ctf_writeup/tree/master/2019/%E9%AB%98%E6%A0%A1%E7%BD%91%E7%BB%9C%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8%E7%AE%A1%E7%90%86%E8%BF%90%E7%BB%B4%E6%8C%91%E6%88%98%E8%B5%9B_2019
方法一
参考Ashen
1 | p = int(gmpy2.next_prime(random.randint(10**399, 10**400-1))) |
n=p×qn=p×qn=[a×(10200)+b]×[b×(10200)+a]n=[a×(10200)+b]×[b×(10200)+a]p q为质数,400位,q为p的高200位和低200位互换
令p = a(10**200)+b;q = b(10**200)+a (a和b分别为200位)
展开得到
n=ab×10400+10200(a2+b2)+ab (1)n=ab×10400+10200(a2+b2)+ab (1)接下来就是数学认识吧,n的数值是和ab有关的,可以知道两个200位的整数相乘,最多为400位,也就是(1)式中最后一项和n的最后若干位有关,而且最多400位;而第一项和n的前若干位有关,而且至多400位,若是没有中间那项,我们就可以直接提取ab了,但是这是在扯蛋,有了中间那一项其实方便了我们提取ab,我们知道中间那一项影响了n的中间位,而且同样最多400位,也就是:
所以如果我们想要构造ab项,我们可以提取出n的最后200位,因为要保证不和中间的部分产生进位关系。
但是前200位不能直接提取,因为中间部分可能产生了进位,而我们知道前若干位是没有进位的,产生进位的只有后几位,所以
1 | ab = int(str(n)[:197]+str(i)+str(n)[-200:]) |
爆破可能产生进位的那几项
1 | import gmpy2 |
但其实再怎么进位也不可能影响这么多位的,所以我觉得不用range(1000),range(10)就可以了
1 | import gmpy2 |
0.3s出结果,虽然师兄那个脚本也很快出(0.5s)
方法二
说是双变量的Coppersmith’s求解
1 | def coron(pol, X, Y, k=2, debug=False): |
1 | from Crypto.Util.number import * |
套用的是https://github.com/ubuntor/coppersmith-algorithm/blob/master/coppersmith.sage 的脚本,原脚本有两个例程,第一个是恢复p、q,在给了n和p的低位的值;第二个是恢复p、q,在给了n和p的高位的值。
1 | def main(): |
里面还有三变量的求解脚本,值得备注一下
算法没有去了解,目前对我来说实在是难以下咽…
本机没有sage,可以到:https://sagecell.sagemath.org/ 运行第一段代码,但是网站没有Crypto库,连n2s也用不了…所以先求出m的整数形式,再转成字符串
使用这个脚本,大概是需要能将p和q带换成x和y的表达式,然后x和y又要有位数上的联系
rsa2
参考:http://soreatu.com/ctf/writeups/Writeup%20for%20EIS%202019.html
1 | from flag import FLAG |
显然就是要从q入手,因为构造起来有猫腻
如果我们令x = os.urandom(32),那么q实际上等于x + (x<<256) + (x<<512) + … + (x<<1792) + b,其中b就是由next_prime产生的一个很小的正数。
根据素数定理,b大概在ln(2**2048) = 1420左右。
素数定理:
定义 π(x)π(x) 为素数计数函数,也就是小于等于xx 的素数个数。例如 π(10)=4π(10)=4,因为共有 4 个素数小于等于 10,分别是 2、3、5、7。素数定理的叙述为:当 xx 趋近无限,π(x)π(x) 和 xlnxxlnx 的比值趋近 1。其数学式写做
${\displaystyle \lim {x\to \infty }{\frac {\;\pi (x)\;}{\frac {x}{\ln(x)}}}=1}浅白的说,当x很大的时候,浅白的说,当x很大的时候,π(x)差不多等于差不多等于{\displaystyle {\frac {x}{\ln x}}}。该定理被认为是素数的渐进分布定律,以渐进符号可简化为。该定理被认为是素数的渐进分布定律,以渐进符号可简化为{\displaystyle \pi (x)\sim {\frac {x}{\ln x}}}。注意到,上式并不是说指随着。注意到,上式并不是说指随着 x 趋近无限,趋近无限,{\displaystyle \pi (x)}与与{\displaystyle {\frac {x}{\ln x}}}的差趋近于0。而是随着的差趋近于0。而是随着x 趋近无限,趋近无限,{\displaystyle \pi (x)}与与{\displaystyle {\frac {x}{\ln x}}}的相对误差趋近于0。素数定理有一个等价数是关于第n个素数的相对误差趋近于0。素数定理有一个等价数是关于第n个素数{\displaystyle p{n}}的渐近估计式的渐近估计式{\displaystyle p_{n}\sim n\ln \,n}$
关于怎么得知b大概在ln(2**2048) = 1420还有待思考
我觉得知不知道b大约的值问题不大
sage脚本1:
1 | n = 120807710153113702551615579080626349972702435654213602643278178850601270671946229285821528380336690426317604059622034599839001416930715968066016772516322170847232613450387418879151680919583407733398280475244970196660246303755390654445483988806163997943960045202300170321033632884706732013873256539789027552900587666422370948750842536533923935656875965991272731558533581897633592458155859972323709278905289729445241014357315813048740496355157322217479024997808766708783034169626351658483634985294355975778256304622956911622334081421352132051371869608818591717661111189285407351900021893457439899221542567630909004930602528901255429064258255953091799356807896508016798627878778491866567622281528441807056062152648122769596905617532839645811871242955534491003544450002957748265702306031022676181061669831693628120952508570252446308607118097142440911574131249381253267168309302968966178203572103064042325655007707720847432033652545364390235670894288288369956445797446648862192044259720010703057599068467348014822871417162946598110099990800849922664801383108437169282005803013729663209291895365964487113632471631243676196750054390014101920098216264290734689252677221687512705895162185620154778448467145374612676883160397044672382343419867 |
算的挺慢,之后求得x(当i=1452),根据q = s*x + b可以算出q,成功分解n。
(但是我在网上的sage跑到478就卡住了)
接下来就是正常的解密:
1 | from Crypto.Util.number import * |
p 256 bit重复多次,构造LLL求解
sage脚本2:
1 | e = 65537 |
无关信息
N=pq φ(n)=(p−1)(q−1)=pq−(p+q)+1=N−(p+q)+1 $$$$∵p,q非常大,∴pq≫p+q,∴φ(n)≈N $$$$∵ed≡1modφ(n),∴ed−1=kφ(n),这个式子两边同除dφ(n)可得:$$$$ eφ(n)−kd=1dφ(n) $$$$∵φ(n)≈N,∴eN−kd=1dφ(n),同样dφ(n)是一个很大的数,所以eN略大于kdN=pq φ(n)=(p−1)(q−1)=pq−(p+q)+1=N−(p+q)+1 $$$$∵p,q非常大,∴pq≫p+q,∴φ(n)≈N $$$$∵ed≡1modφ(n),∴ed−1=kφ(n),这个式子两边同除dφ(n)可得:$$$$ eφ(n)−kd=1dφ(n) $$$$∵φ(n)≈N,∴eN−kd=1dφ(n),同样dφ(n)是一个很大的数,所以eN略大于kd
Wiener’s Attack