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))