[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

解题思路

  1. 先算 p、q、r,得到 n 和 phi_n
  2. 根据RSA生成私钥 d_inv,解密 cipher 得到 c
  3. 求解二次同余方程,得到 m

询问大模型,生成 p 的方法存在安全漏洞。p = n - 1,其中 n 是由多个小素数(不超过1009)的乘积构成,因此 p + 1 = n 是光滑的(即所有素因子都很小)。这使得 RSA 模数 N = p * q * r 容易受到 Williams 的 p+1 分解算法 的攻击,攻击者可以利用 p+1 的光滑性快速分解 N。而 qr 是随机生成的强素数,没有此问题,但整体安全性被 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))
posted @ 2026-03-07 23:05  geyashi  阅读(1)  评论(0)    收藏  举报