[V&N2020 公开赛]easy_RSA
[V&N2020 公开赛]easy_RSA
crpyto #rsa #p+1光滑 #二次同余方程
相关博客:https://www.cnblogs.com/lordtianqiyi/articles/17069463.html
基本信息
题目标题:[V&N2020 公开赛]easy_RSA
题目链接:https://buuoj.cn/challenges#[V&N2020 公开赛]easy_RSA
考点清单:crpyto,rsa,p+1光滑,二次同余方程
工具清单:python3,primefac,gmpy2,libnum,sympy,pycryptodome
题目内容
task.py
from random import randint
from gmpy2 import *
from Crypto.Util.number import *
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
m = bytes_to_long(b'flag{************************************}')
p = getprime(505)
q = getPrime(512)
r = getPrime(512)
assert m < q
n = p * q * r
e = 0x10001
d = invert(q ** 2, p ** 2)
c = pow(m, 2, r)
cipher = pow(c, e, n)
print(n)
print(d)
print(cipher)
'''
7941371739956577280160664419383740967516918938781306610817149744988379280561359039016508679365806108722198157199058807892703837558280678711420411242914059658055366348123106473335186505617418956630780649894945233345985279471106888635177256011468979083320605103256178446993230320443790240285158260236926519042413378204298514714890725325831769281505530787739922007367026883959544239568886349070557272869042275528961483412544495589811933856131557221673534170105409
7515987842794170949444517202158067021118454558360145030399453487603693522695746732547224100845570119375977629070702308991221388721952258969752305904378724402002545947182529859604584400048983091861594720299791743887521228492714135449584003054386457751933095902983841246048952155097668245322664318518861440
1618155233923718966393124032999431934705026408748451436388483012584983753140040289666712916510617403356206112730613485227084128314043665913357106301736817062412927135716281544348612150328867226515184078966397180771624148797528036548243343316501503364783092550480439749404301122277056732857399413805293899249313045684662146333448668209567898831091274930053147799756622844119463942087160062353526056879436998061803187343431081504474584816590199768034450005448200
'''
writeup
解题思路
- 先算 p、q、r,得到 n 和 phi_n
- 根据RSA生成私钥 d_inv,解密 cipher 得到 c
- 求解二次同余方程,得到 m
询问大模型,生成 p 的方法存在安全漏洞。p = n - 1,其中 n 是由多个小素数(不超过1009)的乘积构成,因此 p + 1 = n 是光滑的(即所有素因子都很小)。这使得 RSA 模数 N = p * q * r 容易受到 Williams 的 p+1 分解算法 的攻击,攻击者可以利用 p+1 的光滑性快速分解 N。而 q 和 r 是随机生成的强素数,没有此问题,但整体安全性被 p 的生成方式破坏。
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
p = getprime(505)
q = getPrime(512)
r = getPrime(512)
先利用 primefac 分解 n,求解 p,然后计算 q、r。
d = gmpy2.invert(q ** 2, p ** 2) 就是 \(d \equiv (q^2)^{-1} \pmod{p^2}\),
当且仅当 \(gcd(q^2, p^2)=1\) 时,等价于 \(d \cdot q^2 \equiv 1 \pmod{p^2}\),等价于 \(q^2 \equiv d^{-1} \pmod{p^2}\),即 a = gmpy2.invert(d, p ** 2)
设 q 为 x,求解二次同余方程 \(x^2 \equiv a \pmod{p^2}\)
import primefac
import sympy
import gmpy2
n=7941371739956577280160664419383740967516918938781306610817149744988379280561359039016508679365806108722198157199058807892703837558280678711420411242914059658055366348123106473335186505617418956630780649894945233345985279471106888635177256011468979083320605103256178446993230320443790240285158260236926519042413378204298514714890725325831769281505530787739922007367026883959544239568886349070557272869042275528961483412544495589811933856131557221673534170105409
d=7515987842794170949444517202158067021118454558360145030399453487603693522695746732547224100845570119375977629070702308991221388721952258969752305904378724402002545947182529859604584400048983091861594720299791743887521228492714135449584003054386457751933095902983841246048952155097668245322664318518861440
p = primefac.williams_pp1(n)
p2 = p ** 2
a = gmpy2.invert(d, p2)
# 求解二次同余方程 x^2 \equiv a \pmod{p^2}
q = sympy.ntheory.sqrt_mod(a, p2)
r = n // p // q
计算 phi_n、c。
\(\varphi(n) = \varphi(pqr) = \varphi(p) \varphi(q) \varphi(r) = (p-1)(q-1)(r-1)\)
计算c,其实就是 rsa 解密公式。
先根据 $ e \cdot d \equiv 1 \pmod{\varphi(n)}$,把 私钥 \(d\) 算出来,记作 d_inv。
然后根据 cipher = pow(c, e, n),计算 c = pow(cipher, d_inv, n)
n=7941371739956577280160664419383740967516918938781306610817149744988379280561359039016508679365806108722198157199058807892703837558280678711420411242914059658055366348123106473335186505617418956630780649894945233345985279471106888635177256011468979083320605103256178446993230320443790240285158260236926519042413378204298514714890725325831769281505530787739922007367026883959544239568886349070557272869042275528961483412544495589811933856131557221673534170105409
p=102634610559478918970860957918259981057327949366949344137104804864768237961662136189827166317524151288799657758536256924609797810164397005081733039415393
q=7534810196420932552168708937019691994681052660068275906973480617604535381306041583841106383688654426129050931519275383386503174076258645141589911492908993
r=10269028767754306217563721664976261924407940883784193817786660413744866184645984238866463711873380072803747092361041245422348883639933712733051005791543841
cipher=1618155233923718966393124032999431934705026408748451436388483012584983753140040289666712916510617403356206112730613485227084128314043665913357106301736817062412927135716281544348612150328867226515184078966397180771624148797528036548243343316501503364783092550480439749404301122277056732857399413805293899249313045684662146333448668209567898831091274930053147799756622844119463942087160062353526056879436998061803187343431081504474584816590199768034450005448200
e = 0x10001
phi_n = (p-1)*(q-1)*(r-1)
d_inv = gmpy2.invert(e, phi_n)
c = pow(cipher, d_inv, n)
print(c)
c = pow(m, 2, r) 就是 \(c = m^2 \mod r\) 等价于二次同余方程 \(m^2 \equiv c \pmod{r}\)
设 m 为 x,则 \(x^2 \equiv c \pmod{r}\),使用下面其中一个函数求解二次同余方程
-
sympy.ntheory.sqrt_mod -
sympy.ntheory.nthroot_mod
c=8081092455112516397361105816900490085355315574087538340788309885334106796325593823678787887569920404814986643819898763828872716522338864714182757065213683
#m=56006392793430016468251971646527328995718100207125432393433900875091739391190683811783574991236326013
m = sympy.ntheory.sqrt_mod(c, r)
# m = sympy.ntheory.nthroot_mod(c, 2, r)
# b'flag{fd462593-25e4-4631-a96a-0cd5c72b2d1b}'
plaintext = libnum.n2s(m)
flag{fd462593-25e4-4631-a96a-0cd5c72b2d1b}
完整代码如下:
import primefac
import sympy
import gmpy2
import libnum
from Crypto.Util.number import long_to_bytes
n=7941371739956577280160664419383740967516918938781306610817149744988379280561359039016508679365806108722198157199058807892703837558280678711420411242914059658055366348123106473335186505617418956630780649894945233345985279471106888635177256011468979083320605103256178446993230320443790240285158260236926519042413378204298514714890725325831769281505530787739922007367026883959544239568886349070557272869042275528961483412544495589811933856131557221673534170105409
d=7515987842794170949444517202158067021118454558360145030399453487603693522695746732547224100845570119375977629070702308991221388721952258969752305904378724402002545947182529859604584400048983091861594720299791743887521228492714135449584003054386457751933095902983841246048952155097668245322664318518861440
p = primefac.williams_pp1(n)
p2 = p ** 2
a = gmpy2.invert(d, p2)
q = sympy.ntheory.sqrt_mod(a, p2)
r = n // p // q
cipher=1618155233923718966393124032999431934705026408748451436388483012584983753140040289666712916510617403356206112730613485227084128314043665913357106301736817062412927135716281544348612150328867226515184078966397180771624148797528036548243343316501503364783092550480439749404301122277056732857399413805293899249313045684662146333448668209567898831091274930053147799756622844119463942087160062353526056879436998061803187343431081504474584816590199768034450005448200
e=0x10001
phi_n = (p-1)*(q-1)*(r-1)
d_inv = gmpy2.invert(e, phi_n)
c = pow(cipher, d_inv, n)
m = sympy.ntheory.sqrt_mod(c, r)
# m = sympy.ntheory.nthroot_mod(c, 2, r)
# b'flag{fd462593-25e4-4631-a96a-0cd5c72b2d1b}'
# print(libnum.n2s(m))
print(long_to_bytes(m))

浙公网安备 33010602011771号