Buuctf Crypto 刷題記錄
寫在前面
- 實習入職,要求繼續做比賽
crypto
方向賽題,由於長時間未接觸了,所以現在不得不好好復習一下
[V&N2020 公開賽]easy_RSA
考點
- 平滑大素數分解:使用
primefac
庫可以選取威爾遜定理分解
- rabbin算法
- legendre算法
- tonelli算法
分析
def getprime(bits):
while 1:
n = 1
while n.bit_length() < bits:
n *= next_prime(randint(1,1000))
if isPrime(n - 1):
return n - 1
- “題如其名”,真是夠
easy
的
- 先看素數生成部分函數定義,大素數
n
是由較小的素數進行連乘后減一所得,這個處理方式和之前有一道用到Williams’p+1 algorithm
的題目很相似,這次在參考網上的wp
時發現了可以直接調用庫分解,這給我們這種數學菜雞終於有了一條活路
- 首先使用
primefac
庫選擇Williams’p+1 algorithm
分解,命令如下:
python -m primefac -vs -m=p+1 7941371739956577280160664419383740967516918938781306610817149744988379280561359039016508679365806108722198157199058807892703837558280678711420411242914059658055366348123106473335186505617418956630780649894945233345985279471106888635177256011468979083320605103256178446993230320443790240285158260236926519042413378204298514714890725325831769281505530787739922007367026883959544239568886349070557272869042275528961483412544495589811933856131557221673534170105409
參數詳解:
-m : python使用命令行直接執行模塊參數
-vs : 可選參數 [ -v | --verbose ] [ -s | --summary ] ,-v和-s標志可被組合成以任何順序單個標志
-m=p+1 : 選用威爾遜定理 -m =標志控,期間使用的功能多因素相。選項分別是prb,p-1,p + 1,ecm和mpqs,分別表示Pollard的rho,Pollard的p -1,Williams的p +1,橢圓曲線法和多項式二次篩。
詳細用法見:https://pypi.org/project/primefac/
d = invert(q ** 2, p ** 2)
- 這里解出
p
之后,可以就可以根據給出的d
,直接求逆算出q
,但由於q>p
的所以應是還要加上p
的倍數
q2=gmpy2.invert(d,p**2)
for i in range(10000):
q=gmpy2.iroot(q2+i*p**2,2)
if(q[1]==1): # iroot()返回的是一個tuple,(mpz(xxx),true),若能開方出來則會返回true
print(q[0],i)
break
q=q[0]
- 對於
r
直接用n
除一下就行了
- 至此所有參數都可以獲得了,再看
flag
的加密方式可以發現是先有加密生成參數c
,而后再由c
加密生成給出的密文chiper
- 這里先解決
c
,c
用rsa
加密形成給出的chiper
,這里直接用正常的rsa
思路算出c
就行
phi = (p-1)*(q-1)*(r-1)
d1=gmpy2.invert(e,phi)
c1 = pow(chiper,d1,n)
- 三數連乘的歐拉函數,參考
nsctf-2019-techworld
,ϕ(p*q*r)=ϕ(N)=ϕ(q)*ϕ(p)*ϕ(r)=(p−1)*(q−1)*(r−1)
即可
- 算出
c1
之后即可根據托內利-克斯算法:用於解決合數模問題 即r ** 2 = n mod p => pow(r,2,p)
還原出flag
- 算法參考
https://blog.csdn.net/weixin_44617902/article/details/112785051
- 完整代碼
# coding:utf-8
from gmpy2 import *
from Crypto.Util.number import long_to_bytes'
p=102634610559478918970860957918259981057327949366949344137104804864768237961662136189827166317524151288799657758536256924609797810164397005081733039415393
n=7941371739956577280160664419383740967516918938781306610817149744988379280561359039016508679365806108722198157199058807892703837558280678711420411242914059658055366348123106473335186505617418956630780649894945233345985279471106888635177256011468979083320605103256178446993230320443790240285158260236926519042413378204298514714890725325831769281505530787739922007367026883959544239568886349070557272869042275528961483412544495589811933856131557221673534170105409
e = 0x10001
d=7515987842794170949444517202158067021118454558360145030399453487603693522695746732547224100845570119375977629070702308991221388721952258969752305904378724402002545947182529859604584400048983091861594720299791743887521228492714135449584003054386457751933095902983841246048952155097668245322664318518861440
chiper=1618155233923718966393124032999431934705026408748451436388483012584983753140040289666712916510617403356206112730613485227084128314043665913357106301736817062412927135716281544348612150328867226515184078966397180771624148797528036548243343316501503364783092550480439749404301122277056732857399413805293899249313045684662146333448668209567898831091274930053147799756622844119463942087160062353526056879436998061803187343431081504474584816590199768034450005448200
q2=invert(d,p**2)
for i in range(10000):
q=iroot(q2+i*p**2,2)
if(q[1]==1): # iroot()返回的是一個tuple,(mpz(xxx),true),若能開方出來則會返回true
print(q[0],i)
break
q=q[0]
r=n//p//q
phi = (p-1)*(q-1)*(r-1)
d1=invert(e,phi)
c1 = pow(chiper,d1,n)
def legendre(a, p): # 勒讓德符號 a ** ((p-1)//2) mod p ,解決平方剩余問題
return pow(a, (p - 1) // 2, p)
def tonelli(n, p): # 托內利-克斯算法:用於解決合數模問題 即r ** 2 = n mod p => pow(r,2,p)
assert legendre(n, p) == 1
q = p - 1
s = 0
while q % 2 == 0:
q //= 2
s += 1
if s == 1:
return pow(n, (p + 1) // 4, p)
for z in range(2, 10000):
# for z in range(2, p):
if p - 1 == legendre(z, p):
break
c = pow(z, q, p)
r = pow(n, (q + 1) // 2, p)
t = pow(n, q, p)
m = s
t2 = 0
while (t - 1) % p != 0:
t2 = (t * t) % p
for i in range(1, m):
if (t2 - 1) % p == 0:
break
t2 = (t2 * t2) % p
b = pow(c, 1 << (m - i - 1), p)
r = (r * b) % p
c = (b * b) % p
t = (t * c) % p
m = i
return r
m = tonelli(c1,r)
print(''.join(long_to_bytes(m)))
[GKCTF2020]babycrypto
考點
- Factoring with high bits known Attack
分析
- 密文除了
p
給出的方式有些奇怪,其余的都比較正常,百度直接搜,發現是已知高位攻擊,根據https://github.com/Zui-Qing-Feng/RSA/blob/master/03.Factoring%20with%20high%20bits%20known%20Attack
修改位數為128即可解出p
sage:n=0xb119849bc4523e49c6c038a509a74cda628d4ca0e4d0f28e677d57f3c3c7d0d876ef07d7581fe05a060546fedd7d061d3bc70d679b6c5dd9bc66c5bdad8f2ef898b1e785496c4989daf716a1c89d5c174da494eee7061bcb6d52cafa337fc2a7bba42c918bbd3104dff62ecc9d3704a455a6ce282de0d8129e26c840734ffd302bec5f0a66e0e6d00b5c50fa57c546cff9d7e6a978db77997082b4cb927df9847dfffef55138cb946c62c9f09b968033745b5b6868338c64819a8e92a827265f9abd409359a9471d8c3a2631b80e5b462ba42336717700998ff38536c2436e24ac19228cd2d7a909ead1a8494ff6c3a7151e888e115b68cc6a7a8c6cf8a6c005L
sage:p_fake=0xe4e4b390c1d201dae2c00a4669c0865cc5767bc444f5d310f3cfc75872d96feb89e556972c99ae20753e3314240a52df5dccd076a47c6b5d11b531b92d901b2b512aeb0b263bbfd624fe3d52e5e238beeb581ebe012b2f176a4ffd1e0d2aa8c4d3a2656573b727d4d3136513a931428b00000000000000000000000000000000L
sage: pbits=1024
sage: kbits=128
sage: pbar=p_fake & (2^pbits-2^kbits)
sage: print("upper %d bits (of %d bits) is given" % (pbits-kbits,pbits))
upper 896 bits (of 1024 bits) is given
sage: PR.<x> = PolynomialRing(Zmod(n))
sage: f=x+pbar
sage: x0=f.small_roots(X=2^kbits,beta=0.4)[0]
sage: print(hex(int(x0+pbar)))
0xe4e4b390c1d201dae2c00a4669c0865cc5767bc444f5d310f3cfc75872d96feb89e556972c99ae20753e3314240a52df5dccd076a47c6b5d11b531b92d901b2b512aeb0b263bbfd624fe3d52e5e238beeb581ebe012b2f176a4ffd1e0d2aa8c4d3a2656573b727d4d3136513a931428b92826225b6d0e735440b613a8336ffa3L
import gmpy2
from Crypto.Util.number import *
p1=160734387026849747944319274262095716650717626398118440194223452208652532694713113062084219512359968722796763029072117463281356654614167941930993838521563406258263299846297499190884495560744873319814150988520868951045961906000066805136724505347218275230562125457122462589771119429631727404626489634314291445667L
p2=0xe4e4b390c1d201dae2c00a4669c0865cc5767bc444f5d310f3cfc75872d96feb89e556972c99ae20753e3314240a52df5dccd076a47c6b5d11b531b92d901b2b512aeb0b263bbfd624fe3d52e5e238beeb581ebe012b2f176a4ffd1e0d2aa8c4d3a2656573b727d4d3136513a931428b92826225b6d0e735440b613a8336ffa3
n2=0xb119849bc4523e49c6c038a509a74cda628d4ca0e4d0f28e677d57f3c3c7d0d876ef07d7581fe05a060546fedd7d061d3bc70d679b6c5dd9bc66c5bdad8f2ef898b1e785496c4989daf716a1c89d5c174da494eee7061bcb6d52cafa337fc2a7bba42c918bbd3104dff62ecc9d3704a455a6ce282de0d8129e26c840734ffd302bec5f0a66e0e6d00b5c50fa57c546cff9d7e6a978db77997082b4cb927df9847dfffef55138cb946c62c9f09b968033745b5b6868338c64819a8e92a827265f9abd409359a9471d8c3a2631b80e5b462ba42336717700998ff38536c2436e24ac19228cd2d7a909ead1a8494ff6c3a7151e888e115b68cc6a7a8c6cf8a6c005L
e=65537
q2=n2//p2
d=gmpy2.invert(e,(p2-1)*(q2-1))
m2=pow(c,d,n)
print(long_to_bytes(m2))
[GKCTF2020]Backdoor
考點
分析
- 給出三個文件,一個
flag
密文,一個公玥文件,源碼
- 常規題,直接用
openssl
提取n
和e
openssl rsa -pubin -text -modulus -in warmip -in pub.pem
RSA Public-Key: (443 bit)
Modulus:
05:77:47:96:b3:01:e1:c7:f4:0b:49:45:05:68:8b:
1f:de:21:f6:d5:ff:ce:63:6f:f1:67:d8:5e:37:d7:
a7:b7:49:3e:33:c1:7d:44:17:a2:5c:a2:4a:67:16:
31:4c:f1:86:e1:69:96:dc:fc:67:9b
Exponent: 65537 (0x10001)
Modulus=5774796B301E1C7F40B494505688B1FDE21F6D5FFCE636FF167D85E37D7A7B7493E33C17D4417A25CA24A6716314CF186E16996DCFC679B
writing RSA key
-----BEGIN PUBLIC KEY-----
MFMwDQYJKoZIhvcNAQEBBQADQgAwPwI4BXdHlrMB4cf0C0lFBWiLH94h9tX/zmNv
8WfYXjfXp7dJPjPBfUQXolyiSmcWMUzxhuFpltz8Z5sCAwEAAQ==
-----END PUBLIC KEY-----
n=5774796B301E1C7F40B494505688B1FDE21F6D5FFCE636FF167D85E37D7A7B7493E33C17D4417A25CA24A6716314CF186E16996DCFC679B
e=65537
import gmpy2
from Crypto.Util.number import *
n=15518961041625074876182404585394098781487141059285455927024321276783831122168745076359780343078011216480587575072479784829258678691739L
p=3386619977051114637303328519173627165817832179845212640767197001941
q=4582433561127855310805294456657993281782662645116543024537051682479
c=5902102609936183530036413041949205016072856184947596155784933422689438216690059498706287388882989673839294236821030261398121787376802
e=65537
d=gmpy2.invert(e,(p-1)*(q-1))
m=pow(c,d,n)
print(long_to_bytes(m))