buu(前三页第二弹) RSA习题与相关知识总结

文章目录

  • buu [ACTF新生赛2020]crypto-rsa3 1
      • 题目描述:
      • 题目分析:
      • 收获与体会:
  • buu [WUSTCTF2020]情书 1
      • 题目描述:
      • 题目分析:
      • 收获与体会:
  • buu [NCTF2019]babyRSA 1
      • 题目描述:
      • 题目分析:
      • 收获与体会:
  • buu [RoarCTF2019]babyRSA 1
      • 题目描述:
      • 题目分析:
      • 收获与体会:
  • buu [RoarCTF2019]RSA 1
      • 题目描述:
      • 题目分析:
      • 收获与体会:
  • buu [MRCTF2020]babyRSA 1
      • 题目描述:
      • 题目分析:
  • buu [GWCTF 2019]BabyRSA 1
      • 题目描述:
      • 题目分析:
      • decrypt(解密)
  • buu [GUET-CTF2019]BabyRSA 1
      • 题目描述:
      • 题目分析:
  • 以上知识总结:
      • 1.
      • 2.
      • 3.
      • 4.
      • 5.

buu [ACTF新生赛2020]crypto-rsa3 1

题目描述:

from flag import FLAG
from Cryptodome.Util.number import *
import gmpy2
import random
e=65537
p = getPrime(512)
q = int(gmpy2.next_prime§)
n = p*q
m = bytes_to_long(FLAG)
c = pow(m,e,n)
print(n)
print( c )
n = 177606504836499246970959030226871608885969321778211051080524634084516973331441644993898029573612290095853069264036530459253652875586267946877831055147546910227100566496658148381834683037366134553848011903251252726474047661274223137727688689535823533046778793131902143444408735610821167838717488859902242863683
c = 1457390378511382354771000540945361168984775052693073641682375071407490851289703070905749525830483035988737117653971428424612332020925926617395558868160380601912498299922825914229510166957910451841730028919883807634489834128830801407228447221775264711349928156290102782374379406719292116047581560530382210049

题目分析:

  • 这题已知量:n,c,e
  • 利用 分解n得p,q的在线网站 即可得到 p 与 q
  • 此时便可得到 d = gmpy2.invert(e,(p-1)*(q-1))
  • 然后便可得到明文 m = pow(c,d,n)
  • 最后在转化为字符串即可
  • 代码如下:
import gmpy2
import libnum
n = 177606504836499246970959030226871608885969321778211051080524634084516973331441644993898029573612290095853069264036530459253652875586267946877831055147546910227100566496658148381834683037366134553848011903251252726474047661274223137727688689535823533046778793131902143444408735610821167838717488859902242863683
c = 1457390378511382354771000540945361168984775052693073641682375071407490851289703070905749525830483035988737117653971428424612332020925926617395558868160380601912498299922825914229510166957910451841730028919883807634489834128830801407228447221775264711349928156290102782374379406719292116047581560530382210049
e = 65537
p = 13326909050357447643526585836833969378078147057723054701432842192988717649385731430095055622303549577233495793715580004801634268505725255565021519817179231
q = 13326909050357447643526585836833969378078147057723054701432842192988717649385731430095055622303549577233495793715580004801634268505725255565021519817179293
phi = (p-1)*(q-1)
d = gmpy2.invert(e,phi)
m = pow(c,d,n)
print(libnum.n2s(int(m)))

收获与体会:

这是很基础也很简单的一道题,但重点是要记得公式 (我一开始便有个字母记错了,然后怎么也找不到正确的答案)

buu [WUSTCTF2020]情书 1

题目描述:

buu(前三页第二弹) RSA习题与相关知识总结_第1张图片

题目分析:

  • 翻译一下可知:

前提:用0、1、2、……枚举字母表25
使用RSA系统
加密:0156 0821 1616 0041 0140 2130 1616 0793
公钥:2537和13
私钥:2537和937

  • 从提示可以得知 n = 2537 , e = 13 , d = 937
  • 分解 n ,可知 p = 43 , q = 59
  • 做过 buu RSAROLL 1 便可知道此题大致考的什么
  • 里面的 “ 0156 0821 1616 0041 0140 2130 1616 0793 ” 即是 c ,只不过是多个 c ,将解出来的明文拼接在一起便可得到 flag
  • 代码如下:
a = 'abcdefghigklmnopqrstuvwxyz'
p = 43
q = 59
e = 13
d = 937
c = '0156 0821 1616 0041 0140 2130 1616 0793'.split(' ')
flag = ''
n = p*q
for i in c:
    flag += a[pow(int(i),d,n)]
print(flag)
  • 得到 flag{iloveyou}

收获与体会:

  • 此题有一个特殊之处,即里面的 c , e , n 都很小,很反常!
  • 如果按 buu RSAROLL 1 这道题来写的话,得不到答案,因为打印 pow(int(i),d,n) 后会得到

8
11
14
21
4
24
14
20

一串很小的数字,对应ascii码后会得到一些 特别的东西,没有字母也没有数字

  • 所以就会想到可能是按照26个字母表进行转换,位置一一对应即可转化成功得到 flag
  • 所以数字在1~26之间就转字母便,大于26就转 ascii 码

buu [NCTF2019]babyRSA 1

题目描述:

buu(前三页第二弹) RSA习题与相关知识总结_第2张图片

题目分析:

  • 首先明确两个公式:
e*d = 1 mod (p-1)(q-1)
ed1 = e*d - 1 = k(p-1)(q-1)
  • 想要解出此题,我们必须知道n,而要知道n,我们要知道p和q的值
  • 通过 e*d 的计算,我们知道其长度为2064位,而生成p的条件为 getPrime(1024),所以(p-1)(q-1)应该为2048位

此处所说的位数长度是以Bit为单位,加一减一都不影响位数,相乘的话即为位数相加,这些性质记住就好,以下是计算代码:

from Crypto.Util.number import *
e = 65537 # 转二进 e = 0b10000000000000001,直接数得到长度为17
d = 19275778946037899718035455438175509175723911466127462154506916564101519923603308900331427601983476886255849200332374081996442976307058597390881168155862238533018621944733299208108185814179466844504468163200369996564265921022888670062554504758512453217434777820468049494313818291727050400752551716550403647148197148884408264686846693842118387217753516963449753809860354047619256787869400297858568139700396567519469825398575103885487624463424429913017729585620877168171603444111464692841379661112075123399343270610272287865200880398193573260848268633461983435015031227070217852728240847398084414687146397303110709214913
print(gmpy2.bit_length(e*d))
# 2064
p = getPrime(1024)
print(gmpy2.bit_length(p))
# 1024
print(gmpy2.bit_length(p-1))
# 1024
  • 又 ed1 = e*d - 1 = k(p-1)(q-1),2064-2048 = 16,所以k值必在 pow(2,15)至pow(2,16)之间 (想知道为什么看结尾的知识总结,此处专注解题,不深层探究)
  • 所以,我们可以利用此条件暴力求解k值,从而求出(p-1)*(q-1),间接求出 p 和 q 的值
  • 那如何间接法呢?
  • 首先我们求得了(p-1)(q-1),而p和q是两个相邻的质数,所以我们可以使用sympy库对p,q进行求解。思路为先对(p-1)(q-1)开方,再求得大于开方所得数和小于开方所得数的质数
p = sympy.prevprime(gmpy2.iroot((e*d-1)//i,2)[0])
q = sympy.nextprime(p)
  • 其中 sympy.prevprime(x)是求大于x最近的质数,sympy.nextprime(x)是求小于x最近的质数。
  • 解题代码如下:
import gmpy2
from Crypto.Util.number import long_to_bytes
import sympy
# e = 0x10001
e = 65537
d = 19275778946037899718035455438175509175723911466127462154506916564101519923603308900331427601983476886255849200332374081996442976307058597390881168155862238533018621944733299208108185814179466844504468163200369996564265921022888670062554504758512453217434777820468049494313818291727050400752551716550403647148197148884408264686846693842118387217753516963449753809860354047619256787869400297858568139700396567519469825398575103885487624463424429913017729585620877168171603444111464692841379661112075123399343270610272287865200880398193573260848268633461983435015031227070217852728240847398084414687146397303110709214913
c = 5382723168073828110696168558294206681757991149022777821127563301413483223874527233300721180839298617076705685041174247415826157096583055069337393987892262764211225227035880754417457056723909135525244957935906902665679777101130111392780237502928656225705262431431953003520093932924375902111280077255205118217436744112064069429678632923259898627997145803892753989255615273140300021040654505901442787810653626524305706316663169341797205752938755590056568986738227803487467274114398257187962140796551136220532809687606867385639367743705527511680719955380746377631156468689844150878381460560990755652899449340045313521804
p = 0
q = 0

for k in range(pow(2,15),pow(2,16)):
    #  pow(x,y) ---> x 的 y 次方
    #  pow(x,y,z) ---> x 的 y 次方后,取余 z
    if (e*d-1)%k == 0:
        p = sympy.prevprime(gmpy2.iroot((e*d-1)//k,2)[0])
        # sympy.prevprime(x)是求大于x最近的质数
        # iroot(x,n) ---> x开n次根 ,返回值有两个,前一个是开方出来的整数部分,后一个是能否开出来,若能则为true,不能则为flase
        q = sympy.nextprime(p)
        # sympy.nextprime(x)是求小于x最近的质数
        if (p-1)*(q-1) == (e*d-1)//k:
            break

n = p*q
m = pow(c,d,n)
m1 = long_to_bytes(m)
print(m1)
  • 最终得出 flag{70u2_nn47h_14_v3ry_gOO0000000d}

收获与体会:

  • 了解了一些字节的相关知识
  • 知道了函数 sympy.prevprime(x)和sympy.nextprime(x)的相关知识

sympy.prevprime(x)是求大于x最近的质数
sympy.nextprime(x)是求小于x最近的质数

  • 回顾了iroot(x,n) 和 pow(x,y) 的相关知识

iroot(x,n) —> x开n次根,返回值有两个,前一个是开方出来的整数部分,后一个是能否开出来,若能则为true,不能则为flase
pow(x,y) —> x 的 y 次方
pow(x,y,z) —> x 的 y 次方后,取余 z

buu [RoarCTF2019]babyRSA 1

题目描述:

import sympy
import random

def myGetPrime():
    A= getPrime(513)
    print(A)
    B=A-random.randint(1e3,1e5)
    print(B)
    return sympy.nextPrime((B!)%A)
p=myGetPrime()
#A1=21856963452461630437348278434191434000066076750419027493852463513469865262064340836613831066602300959772632397773487317560339056658299954464169264467234407
#B1=21856963452461630437348278434191434000066076750419027493852463513469865262064340836613831066602300959772632397773487317560339056658299954464169264467140596

q=myGetPrime()
#A2=16466113115839228119767887899308820025749260933863446888224167169857612178664139545726340867406790754560227516013796269941438076818194617030304851858418927
#B2=16466113115839228119767887899308820025749260933863446888224167169857612178664139545726340867406790754560227516013796269941438076818194617030304851858351026

r=myGetPrime()

n=p*q*r
#n=85492663786275292159831603391083876175149354309327673008716627650718160585639723100793347534649628330416631255660901307533909900431413447524262332232659153047067908693481947121069070451562822417357656432171870951184673132554213690123308042697361969986360375060954702920656364144154145812838558365334172935931441424096270206140691814662318562696925767991937369782627908408239087358033165410020690152067715711112732252038588432896758405898709010342467882264362733
c=pow(flag,e,n)
#e=0x1001
#c=75700883021669577739329316795450706204502635802310731477156998834710820770245219468703245302009998932067080383977560299708060476222089630209972629755965140317526034680452483360917378812244365884527186056341888615564335560765053550155758362271622330017433403027261127561225585912484777829588501213961110690451987625502701331485141639684356427316905122995759825241133872734362716041819819948645662803292418802204430874521342108413623635150475963121220095236776428
#so,what is the flag?

题目分析:

  • 首先我们先看到 n = p * q * r (n 分解成了三个素数) ,而 e,c 都知道,所以要求明文 m = pow(c,d,n) 先要求出 d 来
  • 而 d = gmpy2.invert(e,phi)
  • 其中欧拉函数 phi = (p-1) * (q-1) * (r-1)
  • 所以要求 d ,那么要求出 p 与 q
  • 代码中 p = myGetPrime() = sympy.nextPrime((B!)%A)

sympy.nextprime(x) 是求小于x最近的质数

  • 所以最终要求 (B!)%A,即B的阶乘模A,其中 A,B 都知道,那么B!(B的阶乘)怎么求呢?
  • 有一个定理可以解决这个问题,即 威尔逊定理

威尔逊定理

当且仅当p为素数时:( p -1 ) ! ≡ -1 ( mod p ) —> (p-1) ! +1=0 (mod p)

  • A = getPrime(513),可知A为素数,又 B=A-random.randint(1e3,1e5),通过威尔逊定理,可知(A-1) ! +1≡0 (mod A),故B!(B+1)(B+2)…(A-1) ≡ -1 (mod A),即B ! * C = ≡ -1 ( mod A ),其中C = (A - 1)! / (B) !,也就是B之后的数字之积
    两边同时乘上C的逆元C1(C * C1 = 1),B ! = -1 * C1(mod A1)
  • B ! 求出来了,那么 p = myGetPrime() = sympy.nextPrime((B!)%A) 也就求出来了
  • 如此,p,q 都求出来了,r = n // (p * q) ,自此p,q,r,都求出来了,最终flag也就出来了
  • 代码如下:
import libnum
import sympy
import gmpy2

A1=21856963452461630437348278434191434000066076750419027493852463513469865262064340836613831066602300959772632397773487317560339056658299954464169264467234407
B1=21856963452461630437348278434191434000066076750419027493852463513469865262064340836613831066602300959772632397773487317560339056658299954464169264467140596
A2=16466113115839228119767887899308820025749260933863446888224167169857612178664139545726340867406790754560227516013796269941438076818194617030304851858418927
B2=16466113115839228119767887899308820025749260933863446888224167169857612178664139545726340867406790754560227516013796269941438076818194617030304851858351026
n=85492663786275292159831603391083876175149354309327673008716627650718160585639723100793347534649628330416631255660901307533909900431413447524262332232659153047067908693481947121069070451562822417357656432171870951184673132554213690123308042697361969986360375060954702920656364144154145812838558365334172935931441424096270206140691814662318562696925767991937369782627908408239087358033165410020690152067715711112732252038588432896758405898709010342467882264362733
# e=0x1001,转十进制
e = 4097
c=75700883021669577739329316795450706204502635802310731477156998834710820770245219468703245302009998932067080383977560299708060476222089630209972629755965140317526034680452483360917378812244365884527186056341888615564335560765053550155758362271622330017433403027261127561225585912484777829588501213961110690451987625502701331485141639684356427316905122995759825241133872734362716041819819948645662803292418802204430874521342108413623635150475963121220095236776428
def mydecryp(A,B):
    C1 = 1
    temp = pow(-1,1,A) # temp=-1 mod A
    for i in range(B+1,A):
        C1 = (C1*gmpy2.invert(i,A))%A # C1是从B+1~A中每个数对A的逆元的乘积
    return sympy.nextprime((C1*temp)%A) # (C1*temp) = B!, (C1*temp)%A = (B!)%A

p = mydecryp(A1,B1)
q = mydecryp(A2,B2)
r = n//p//q
phi = (p-1)*(q-1)*(r-1)
d = gmpy2.invert(e,phi)
m = pow(c,d,n)
print(libnum.n2s(int(m)))
  • 最终flag{wm-CongrAtu1ation4-1t4-ju4t-A-bAby-R4A}

收获与体会:

  • 知道了如何利用代码求阶乘
  • 又了解了一种RSA题型

buu [RoarCTF2019]RSA 1

题目描述:

A=(((y%x)**5)%(x%y))**2019+y**316+(y+1)/x
p=next_prime(z*x*y)
q=next_prime(z)
A =  2683349182678714524247469512793476009861014781004924905484127480308161377768192868061561886577048646432382128960881487463427414176114486885830693959404989743229103516924432512724195654425703453612710310587164417035878308390676612592848750287387318129424195208623440294647817367740878211949147526287091298307480502897462279102572556822231669438279317474828479089719046386411971105448723910594710418093977044179949800373224354729179833393219827789389078869290217569511230868967647963089430594258815146362187250855166897553056073744582946148472068334167445499314471518357535261186318756327890016183228412253724
n =  117930806043507374325982291823027285148807239117987369609583515353889814856088099671454394340816761242974462268435911765045576377767711593100416932019831889059333166946263184861287975722954992219766493089630810876984781113645362450398009234556085330943125568377741065242183073882558834603430862598066786475299918395341014877416901185392905676043795425126968745185649565106322336954427505104906770493155723995382318346714944184577894150229037758434597242564815299174950147754426950251419204917376517360505024549691723683358170823416757973059354784142601436519500811159036795034676360028928301979780528294114933347127
c =  41971850275428383625653350824107291609587853887037624239544762751558838294718672159979929266922528917912189124713273673948051464226519605803745171340724343705832198554680196798623263806617998072496026019940476324971696928551159371970207365741517064295956376809297272541800647747885170905737868568000101029143923792003486793278197051326716680212726111099439262589341050943913401067673851885114314709706016622157285023272496793595281054074260451116213815934843317894898883215362289599366101018081513215120728297131352439066930452281829446586562062242527329672575620261776042653626411730955819001674118193293313612128

题目分析:

  • 这题看了大佬的,知道了两种不同的解题方法
  • 第一种是契合题目所给字母,先通过爆破求出x,y,但奇怪的是我用pycharm重写了一遍他们的代码,都出现了报错:buu(前三页第二弹) RSA习题与相关知识总结_第3张图片buu(前三页第二弹) RSA习题与相关知识总结_第4张图片
  • 上面两种一个是报错,一个是直接结束程序,反正都求不出x,y(我也求不出)
  • 所以尝试了另外一种方法:直接爆破求e,(p,q可以通过n分解得到),所以字母都求出来了,那么最后答案也就差不多了,代码如下:
from Crypto.Util.number import *
A = 2683349182678714524247469512793476009861014781004924905484127480308161377768192868061561886577048646432382128960881487463427414176114486885830693959404989743229103516924432512724195654425703453612710310587164417035878308390676612592848750287387318129424195208623440294647817367740878211949147526287091298307480502897462279102572556822231669438279317474828479089719046386411971105448723910594710418093977044179949800373224354729179833393219827789389078869290217569511230868967647963089430594258815146362187250855166897553056073744582946148472068334167445499314471518357535261186318756327890016183228412253724
n = 117930806043507374325982291823027285148807239117987369609583515353889814856088099671454394340816761242974462268435911765045576377767711593100416932019831889059333166946263184861287975722954992219766493089630810876984781113645362450398009234556085330943125568377741065242183073882558834603430862598066786475299918395341014877416901185392905676043795425126968745185649565106322336954427505104906770493155723995382318346714944184577894150229037758434597242564815299174950147754426950251419204917376517360505024549691723683358170823416757973059354784142601436519500811159036795034676360028928301979780528294114933347127
c = 41971850275428383625653350824107291609587853887037624239544762751558838294718672159979929266922528917912189124713273673948051464226519605803745171340724343705832198554680196798623263806617998072496026019940476324971696928551159371970207365741517064295956376809297272541800647747885170905737868568000101029143923792003486793278197051326716680212726111099439262589341050943913401067673851885114314709706016622157285023272496793595281054074260451116213815934843317894898883215362289599366101018081513215120728297131352439066930452281829446586562062242527329672575620261776042653626411730955819001674118193293313612128
p = 842868045681390934539739959201847552284980179958879667933078453950968566151662147267006293571765463137270594151138695778986165111380428806545593588078365331313084230014618714412959584843421586674162688321942889369912392031882620994944241987153078156389470370195514285850736541078623854327959382156753458569
q = 139916095583110895133596833227506693679306709873174024876891023355860781981175916446323044732913066880786918629089023499311703408489151181886568535621008644997971982182426706592551291084007983387911006261442519635405457077292515085160744169867410973960652081452455371451222265819051559818441257438021073941183

for i in range(2,100000): # 此时的i即为e
    if isPrime(i): # 判断i是否为素数
        try:
            d = gmpy2.invert(i,(p-1)*(q-1))
            m = pow(c,d,n)
            flag = libnum.n2s(int(m)) # 此时 type(flag) = ,所以下面要转字符串,一开始没转字符串报错,所以才会想到这里
            if 'CTF' in str(flag) or 'flag' in str(flag):
                print(flag,'\n',i)
        except ZeroDivisionError:
            continue
  • 最终得到flag{wm-l1l1ll1l1l1l111ll},e = 65537

收获与体会:

  • 真是巧了,e = 65537
  • 所以如果以后要求e来求flag的,我们可以先大胆令e = 65537来试一下,没准就瞎猫碰上死耗子,答案就出来了,省时还省力(但遇上这种题的可能性确实挺小的)
  • 为什么会把e的范围定在1~100000之间?题做多了便知大部分的e的值都处于此范围内。(不排除有特殊情况,到时候有特殊情况再说吧)

buu [MRCTF2020]babyRSA 1

题目描述:

import sympy
import random
from gmpy2 import gcd, invert
from Crypto.Util.number import getPrime, isPrime, getRandomNBitInteger, bytes_to_long, long_to_bytes
from z3 import *
flag = b"MRCTF{xxxx}"
base = 65537


def GCD(A):
    B = 1
    for i in range(1, len(A)):
        B = gcd(A[i-1], A[i])
    return B


def gen_p():
    P = [0 for i in range(17)]
    P[0] = getPrime(128)
    for i in range(1, 17):
        P[i] = sympy.nextprime(P[i-1])
    print("P_p :", P[9])
    n = 1
    for i in range(17):
        n *= P[i]
    p = getPrime(1024)
    factor = pow(p, base, n)
    print("P_factor :", factor)
    return sympy.nextprime(p)


def gen_q():
    sub_Q = getPrime(1024)
    Q_1 = getPrime(1024)
    Q_2 = getPrime(1024)
    Q = sub_Q ** Q_2 % Q_1
    print("Q_1: ", Q_1)
    print("Q_2: ", Q_2)
    print("sub_Q: ", sub_Q)
    return sympy.nextprime(Q)


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_p : 206027926847308612719677572554991143421
P_factor : 213671742765908980787116579976289600595864704574134469173111790965233629909513884704158446946409910475727584342641848597858942209151114627306286393390259700239698869487469080881267182803062488043469138252786381822646126962323295676431679988602406971858136496624861228526070581338082202663895710929460596143281673761666804565161435963957655012011051936180536581488499059517946308650135300428672486819645279969693519039407892941672784362868653243632727928279698588177694171797254644864554162848696210763681197279758130811723700154618280764123396312330032986093579531909363210692564988076206283296967165522152288770019720928264542910922693728918198338839
Q_1:  103766439849465588084625049495793857634556517064563488433148224524638105971161051763127718438062862548184814747601299494052813662851459740127499557785398714481909461631996020048315790167967699932967974484481209879664173009585231469785141628982021847883945871201430155071257803163523612863113967495969578605521
Q_2:  151010734276916939790591461278981486442548035032350797306496105136358723586953123484087860176438629843688462671681777513652947555325607414858514566053513243083627810686084890261120641161987614435114887565491866120507844566210561620503961205851409386041194326728437073995372322433035153519757017396063066469743
sub_Q:  168992529793593315757895995101430241994953638330919314800130536809801824971112039572562389449584350643924391984800978193707795909956472992631004290479273525116959461856227262232600089176950810729475058260332177626961286009876630340945093629959302803189668904123890991069113826241497783666995751391361028949651
Ciphertext =  1709187240516367141460862187749451047644094885791761673574674330840842792189795049968394122216854491757922647656430908587059997070488674220330847871811836724541907666983042376216411561826640060734307013458794925025684062804589439843027290282034999617915124231838524593607080377300985152179828199569474241678651559771763395596697140206072537688129790126472053987391538280007082203006348029125729650207661362371936196789562658458778312533505938858959644541233578654340925901963957980047639114170033936570060250438906130591377904182111622236567507022711176457301476543461600524993045300728432815672077399879668276471832

题目分析:

  • 首先我们分析代码,代码可以说分为3个模块,第一个模块(GCD模块)个人觉得这里不需要看,后面解题并没有用它,重点是下面两模块,即gen_p和gen_q模块(生成p和生成q模块)
  • 生成q模块还好说:
def gen_q():
    sub_Q = getPrime(1024)
    Q_1 = getPrime(1024)
    Q_2 = getPrime(1024)
    Q = sub_Q ** Q_2 % Q_1
    return sympy.nextprime(p)
 其中Q = sympy.nextprime(pow(sub_Q,Q_2,Q_1)),而sub_Q , Q_2 , Q_1都为已知数,那么Q便求出来了
  • 重点是生成p模块,我们先来看生成p的过程:先生成P,P里面有17个质数,且每一个质数之间都有关系
def gen_p():
    P = [0 for i in range(17)]
    P[0] = getPrime(128)
    for i in range(1, 17):
        P[i] = sympy.nextprime(P[i-1])
    print("P_p :", P[9])
    n = 1
    for i in range(17):
        n *= P[i]
    p = getPrime(1024)
    factor = pow(p, base, n)
    print("P_factor :", factor)
    return sympy.nextprime(p)

做此题 必备知识
sympy.prevprime(x)是求大于x最近的质数
sympy.nextprime(x)是求小于x最近的质数

  • 由必备知识可知P中有17个质数,后一个数是大于前一个数最近的质数,并且具有唯一性,这16个质数相乘得到n,然后通过factor = pow(p,base,n)求得factor , (其中base即为e = 65537)。这是一个典型的欧拉函数,我们需要求出的便是这17个(P[i]-1)的乘积,其中P[9]是已知的,然而我在上面也说了,每个质数之间都是相联系的,且每个质数都是唯一的,所以知道其中一个,那么其他的都能知道,然后通过invert求出d1,之后求出p 。以下是求解p的代码:
P = [0 for i in range(17)]
P[9] = 206027926847308612719677572554991143421
for i in range(9,0,-1): # 9 8 7 6 5 4 3 2 1
    P[i-1] = sympy.prevprime(P[i])
for i in range(9,16):
    P[i+1] = sympy.nextprime(P[i]) # i = 16 时,i+1=17
n = 1
phi_n = 1
for i in range(17):
    n *= P[i]
    phi_n *= (P[i]-1)
d1 = gmpy2.invert(base,phi_n)
p = sympy.nextprime(pow(P_factor,d1,n))
  • 完整代码如下:
import libnum
import sympy
import gmpy2
base = 65537
P_p = 206027926847308612719677572554991143421
P_factor = 213671742765908980787116579976289600595864704574134469173111790965233629909513884704158446946409910475727584342641848597858942209151114627306286393390259700239698869487469080881267182803062488043469138252786381822646126962323295676431679988602406971858136496624861228526070581338082202663895710929460596143281673761666804565161435963957655012011051936180536581488499059517946308650135300428672486819645279969693519039407892941672784362868653243632727928279698588177694171797254644864554162848696210763681197279758130811723700154618280764123396312330032986093579531909363210692564988076206283296967165522152288770019720928264542910922693728918198338839
Q_1 = 103766439849465588084625049495793857634556517064563488433148224524638105971161051763127718438062862548184814747601299494052813662851459740127499557785398714481909461631996020048315790167967699932967974484481209879664173009585231469785141628982021847883945871201430155071257803163523612863113967495969578605521
Q_2 = 151010734276916939790591461278981486442548035032350797306496105136358723586953123484087860176438629843688462671681777513652947555325607414858514566053513243083627810686084890261120641161987614435114887565491866120507844566210561620503961205851409386041194326728437073995372322433035153519757017396063066469743
sub_Q = 168992529793593315757895995101430241994953638330919314800130536809801824971112039572562389449584350643924391984800978193707795909956472992631004290479273525116959461856227262232600089176950810729475058260332177626961286009876630340945093629959302803189668904123890991069113826241497783666995751391361028949651
c = 1709187240516367141460862187749451047644094885791761673574674330840842792189795049968394122216854491757922647656430908587059997070488674220330847871811836724541907666983042376216411561826640060734307013458794925025684062804589439843027290282034999617915124231838524593607080377300985152179828199569474241678651559771763395596697140206072537688129790126472053987391538280007082203006348029125729650207661362371936196789562658458778312533505938858959644541233578654340925901963957980047639114170033936570060250438906130591377904182111622236567507022711176457301476543461600524993045300728432815672077399879668276471832

P = [0 for i in range(17)]
P[9] = 206027926847308612719677572554991143421
for i in range(9,0,-1): # 9 8 7 6 5 4 3 2 1
    P[i-1] = sympy.prevprime(P[i])
for i in range(9,16):
    P[i+1] = sympy.nextprime(P[i]) # i = 16 时,i+1=17
n = 1
phi_n = 1
for i in range(17):
    n *= P[i]
    phi_n *= (P[i]-1)
d1 = gmpy2.invert(base,phi_n)
p = sympy.nextprime(pow(P_factor,d1,n))
q = sympy.nextprime(pow(sub_Q,Q_2,Q_1))
phi = (p-1)*(q-1)
n = p * q
d = gmpy2.invert(base,phi)
m = pow(c,d,n)
print(libnum.n2s(int(m)))
  • 最后得到flag{sti11_@_b@by_qu3st10n}

buu [GWCTF 2019]BabyRSA 1

题目描述:

import hashlib
import sympy
from Crypto.Util.number import *

flag = 'GWHT{******}'
secret = '******'

assert(len(flag) == 38)

half = len(flag) / 2

flag1 = flag[:half]
flag2 = flag[half:]

secret_num = getPrime(1024) * bytes_to_long(secret)

p = sympy.nextprime(secret_num)
q = sympy.nextprime(p)

N = p * q

e = 0x10001

F1 = bytes_to_long(flag1)
F2 = bytes_to_long(flag2)

c1 = F1 + F2
c2 = pow(F1, 3) + pow(F2, 3)
assert(c2 < N)

m1 = pow(c1, e, N)
m2 = pow(c2, e, N)

output = open('secret', 'w')
output.write('N=' + str(N) + '\n')
output.write('m1=' + str(m1) + '\n')
output.write('m2=' + str(m2) + '\n')
output.close()
N=636585149594574746909030160182690866222909256464847291783000651837227921337237899651287943597773270944384034858925295744880727101606841413640006527614873110651410155893776548737823152943797884729130149758279127430044739254000426610922834573094957082589539445610828279428814524313491262061930512829074466232633130599104490893572093943832740301809630847541592548921200288222432789208650949937638303429456468889100192613859073752923812454212239908948930178355331390933536771065791817643978763045030833712326162883810638120029378337092938662174119747687899484603628344079493556601422498405360731958162719296160584042671057160241284852522913676264596201906163
m1=90009974341452243216986938028371257528604943208941176518717463554774967878152694586469377765296113165659498726012712288670458884373971419842750929287658640266219686646956929872115782173093979742958745121671928568709468526098715927189829600497283118051641107305128852697032053368115181216069626606165503465125725204875578701237789292966211824002761481815276666236869005129138862782476859103086726091860497614883282949955023222414333243193268564781621699870412557822404381213804026685831221430728290755597819259339616650158674713248841654338515199405532003173732520457813901170264713085107077001478083341339002069870585378257051150217511755761491021553239
m2=487443985757405173426628188375657117604235507936967522993257972108872283698305238454465723214226871414276788912058186197039821242912736742824080627680971802511206914394672159240206910735850651999316100014691067295708138639363203596244693995562780286637116394738250774129759021080197323724805414668042318806010652814405078769738548913675466181551005527065309515364950610137206393257148357659666687091662749848560225453826362271704292692847596339533229088038820532086109421158575841077601268713175097874083536249006018948789413238783922845633494023608865256071962856581229890043896939025613600564283391329331452199062858930374565991634191495137939574539546

题目分析:

对代码进行分析可得大致加密过程为:

  • 首先给了字符串明文flag和secret,然后对flag对半切得到flag1和flag2
  • 随机生成一个1024位(2进制)的素数,并将secret(字符串)类型转化为整数类型,然后将这两个结果相乘得到secret_num

拓展:
bytes_to_long(x) —> 字节转整数 (会将字节x转化为它的ascii码)
long_to_bytes(x) —> 整数转字节
buu(前三页第二弹) RSA习题与相关知识总结_第5张图片

  • 取secret_num的下一个素数作为p,取p的下一个素数作为q,得到N=p*q

必备知识:
sympy.prevprime(x)是求大于x最近的质数
sympy.nextprime(x)是求小于x最近的质数

  • 将flag1和flag2通过bytes_to_long转化为整数得到F1和F2
  • 将F1,F2设计成方程组得到c1,c2,进一步加密得到m1,m2
  • 最后给出运行结果得到 N,m1,m2

decrypt(解密)

  • 题中给出了N,通过以上分析可以得知p,q是两个相邻的素数,所以对N进行开方运算(iroot(N,2))后可以得到一个值x,并且pq
  • 通过sympy.prevprime(x),sympy.nextprime(x) 函数可以得到p,q,从而可以求得d
  • 然后进行RSA解密得出c1和c2

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

  • 至此,我们得到一个方程组:

c1=F1+F2
c2=F13+F23

  • 利用sympy库进行方程组求解:
from sympy import *
F1 = Symbol('F1')
F2 = Symbol('F2')
F1,F2 = solve([F1+F2-c1,(F1)**3+(F2)**3-c2])
print(F1,F2)

得到:

{F1: 1141553212031156130619789508463772513350070909, F2: 1590956290598033029862556611630426044507841845},
{F1: 1590956290598033029862556611630426044507841845, F2: 1141553212031156130619789508463772513350070909} 
  • 得到两组解,但仔细看只是调换的位置而已,两组都试一下,便可得到最终flag
  • 完整代码:
N=636585149594574746909030160182690866222909256464847291783000651837227921337237899651287943597773270944384034858925295744880727101606841413640006527614873110651410155893776548737823152943797884729130149758279127430044739254000426610922834573094957082589539445610828279428814524313491262061930512829074466232633130599104490893572093943832740301809630847541592548921200288222432789208650949937638303429456468889100192613859073752923812454212239908948930178355331390933536771065791817643978763045030833712326162883810638120029378337092938662174119747687899484603628344079493556601422498405360731958162719296160584042671057160241284852522913676264596201906163
m1=90009974341452243216986938028371257528604943208941176518717463554774967878152694586469377765296113165659498726012712288670458884373971419842750929287658640266219686646956929872115782173093979742958745121671928568709468526098715927189829600497283118051641107305128852697032053368115181216069626606165503465125725204875578701237789292966211824002761481815276666236869005129138862782476859103086726091860497614883282949955023222414333243193268564781621699870412557822404381213804026685831221430728290755597819259339616650158674713248841654338515199405532003173732520457813901170264713085107077001478083341339002069870585378257051150217511755761491021553239
m2=487443985757405173426628188375657117604235507936967522993257972108872283698305238454465723214226871414276788912058186197039821242912736742824080627680971802511206914394672159240206910735850651999316100014691067295708138639363203596244693995562780286637116394738250774129759021080197323724805414668042318806010652814405078769738548913675466181551005527065309515364950610137206393257148357659666687091662749848560225453826362271704292692847596339533229088038820532086109421158575841077601268713175097874083536249006018948789413238783922845633494023608865256071962856581229890043896939025613600564283391329331452199062858930374565991634191495137939574539546
e = 65537
import gmpy2
import libnum
import sympy.crypto.crypto
x = gmpy2.iroot(N,2)[0]
p = sympy.nextprime(x)
q = N//p
phi = (p-1)*(q-1)
d = gmpy2.invert(e,phi)
# m1 = pow(c1, e, N)
# m2 = pow(c2, e, N)
c1 = pow(m1,d,N)
c2 = pow(m2,d,N)
from sympy import *
F1 = Symbol('F1')
F2 = Symbol('F2')
print(solve([F1+F2-c1,(F1)**3+(F2)**3-c2]),F1,F2)
F1,F2 = solve([F1+F2-c1,(F1)**3+(F2)**3-c2])
F2 = 1141553212031156130619789508463772513350070909
F1 = 1590956290598033029862556611630426044507841845
print(libnum.n2s(int(F1))+libnum.n2s(int(F2)))
  • 最后得到flag{f709e0e2cfe7e530ca8972959a1033b2}

buu [GUET-CTF2019]BabyRSA 1

题目描述:

p+q : 0x1232fecb92adead91613e7d9ae5e36fe6bb765317d6ed38ad890b4073539a6231a6620584cea5730b5af83a3e80cf30141282c97be4400e33307573af6b25e2ea
(p+1)(q+1) : 0x5248becef1d925d45705a7302700d6a0ffe5877fddf9451a9c1181c4d82365806085fd86fbaab08b6fc66a967b2566d743c626547203b34ea3fdb1bc06dd3bb765fd8b919e3bd2cb15bc175c9498f9d9a0e216c2dde64d81255fa4c05a1ee619fc1fc505285a239e7bc655ec6605d9693078b800ee80931a7a0c84f33c851740
e : 0xe6b1bee47bd63f615c7d0a43c529d219
d : 0x2dde7fbaed477f6d62838d55b0d0964868cf6efb2c282a5f13e6008ce7317a24cb57aec49ef0d738919f47cdcd9677cd52ac2293ec5938aa198f962678b5cd0da344453f521a69b2ac03647cdd8339f4e38cec452d54e60698833d67f9315c02ddaa4c79ebaa902c605d7bda32ce970541b2d9a17d62b52df813b2fb0c5ab1a5
enc_flag : 0x50ae00623211ba6089ddfae21e204ab616f6c9d294e913550af3d66e85d0c0693ed53ed55c46d8cca1d7c2ad44839030df26b70f22a8567171a759b76fe5f07b3c5a6ec89117ed0a36c0950956b9cde880c575737f779143f921d745ac3bb0e379c05d9a3cc6bf0bea8aa91e4d5e752c7eb46b2e023edbc07d24a7c460a34a9a

题目分析:

  • 知道了(p+1)(q+1)与p+q,那么n = p*q便可以知道了,n = (p+1)(q+1) - (p+q) - 1
  • enc_flag便是密文c
  • 所以明文m = pow(c,d,n) 便求出来了
  • 代码如下:
import libnum
a = 0x1232fecb92adead91613e7d9ae5e36fe6bb765317d6ed38ad890b4073539a6231a6620584cea5730b5af83a3e80cf30141282c97be4400e33307573af6b25e2ea
b = 0x5248becef1d925d45705a7302700d6a0ffe5877fddf9451a9c1181c4d82365806085fd86fbaab08b6fc66a967b2566d743c626547203b34ea3fdb1bc06dd3bb765fd8b919e3bd2cb15bc175c9498f9d9a0e216c2dde64d81255fa4c05a1ee619fc1fc505285a239e7bc655ec6605d9693078b800ee80931a7a0c84f33c851740
e = 0xe6b1bee47bd63f615c7d0a43c529d219
d = 0x2dde7fbaed477f6d62838d55b0d0964868cf6efb2c282a5f13e6008ce7317a24cb57aec49ef0d738919f47cdcd9677cd52ac2293ec5938aa198f962678b5cd0da344453f521a69b2ac03647cdd8339f4e38cec452d54e60698833d67f9315c02ddaa4c79ebaa902c605d7bda32ce970541b2d9a17d62b52df813b2fb0c5ab1a5
enc_flag = 0x50ae00623211ba6089ddfae21e204ab616f6c9d294e913550af3d66e85d0c0693ed53ed55c46d8cca1d7c2ad44839030df26b70f22a8567171a759b76fe5f07b3c5a6ec89117ed0a36c0950956b9cde880c575737f779143f921d745ac3bb0e379c05d9a3cc6bf0bea8aa91e4d5e752c7eb46b2e023edbc07d24a7c460a34a9a
n = b - a - 1
m = pow(enc_flag,d,n)
print(libnum.n2s(m))
  • 得到flag{cc7490e-78ab-11e9-b422-8ba97e5da1fd}

以上知识总结:

1.

当出现多个c(并没有多个n)则想到拼接法。若每个c相对偏小,那么就意味着求出的m相对偏小,若m <= 26 则想到对应26个字母表,若m > 26,则直接 flag += chr(m)

2.

sympy.prevprime(x)是求大于x最近的质数
sympy.nextprime(x)是求小于x最近的质数

3.

我们经常会遇到:

p = getPrime(1024)
q = getPrime(1024)

指的是获得1024长度(2进制)的素数p,q

此处所说的长度是以Bit为单位(二进制形式),加一减一都不影响位数,相乘的话即为位数相加,这些性质记住就行(数字逻辑第一章有此知识),以下是举例:

from Crypto.Util.number import *
e = 0x10001 # 转二进 e = 0b10000000000000001,直接数得到长度为17
d = 19275778946037899718035455438175509175723911466127462154506916564101519923603308900331427601983476886255849200332374081996442976307058597390881168155862238533018621944733299208108185814179466844504468163200369996564265921022888670062554504758512453217434777820468049494313818291727050400752551716550403647148197148884408264686846693842118387217753516963449753809860354047619256787869400297858568139700396567519469825398575103885487624463424429913017729585620877168171603444111464692841379661112075123399343270610272287865200880398193573260848268633461983435015031227070217852728240847398084414687146397303110709214913
print(gmpy2.bit_length(e*d))
# 2064
p = getPrime(1024)
print(gmpy2.bit_length(p))
# 1024
print(gmpy2.bit_length(p-1))
# 1024

留个小问题:pow(2,15)至pow(2,16)中的数 位数长度是多少?
解答:问的是处于 2^15 ~ 2^16 中的数的位数长度为多少,想要算位数长度,那么便要将数转为2进制形式,这里就要用到数字逻辑中学到的知识了(这些知识记住即可,方便下次做题):

2^15 转2进制即 1 后面加15个0
2^15 = 1000000000000000 ————>长度为16
同理 2^16 转2进制即 1 后面加16个0
2^16 = 10000000000000000 ————>长度为17
所以处于 2^15 ~ 2^16 中的数的位数长度为 16

4.

若:

p = sympy.nextprime(a_num) # 其中 a_num 未知
q = sympy.nextprime(p)
n = p * q 

n 已知,求 p,q
由代码可知,p,q 是相邻的两个素数,那么直接对 n 开方,求开方得到的数的整数部分,然后对该整数求上一个素数和下一个素数,即可得到 p,q 。如:

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

5.

bytes_to_long(x) 与 long_to_bytes(x) 相关知识:

bytes_to_long(x) —> 字节转整数 (会将字节x转化为它的ascii码)
long_to_bytes(x) —> 整数转字节
buu(前三页第二弹) RSA习题与相关知识总结_第6张图片

你可能感兴趣的:(密码RSA,python,buuctf,python,密码学,安全)