NSSCTF_crypto_[SWPUCTF 2023 秋季新生赛]dpdp

题目:

python 复制代码
from Crypto.Util.number import *
from libnum import *

flag = b'NSSCTF{******}' + b'1010101010101010101010101010101010101010100010101010101010101010101101'
p = getPrime(512)
q = getPrime(512)
n = p*q
e = 65537
d = inverse(e, (p-1)*(q-1))
dp = d % (p-1)
m = s2n(flag)
c = pow(m, e, n)
print(f'n = {n}')
print(f'c = {c}')
print(f'dp = {dp}')

'''
n = 62950660589752377241535942010457460675378335694404721223426371627802159493655570041534480026979837056215567303530448462076388942749116962945931432723672826148999814815864738069663127706046027850586024555861960247057288826014343547293035737544457656904257388300461848219257240252715837662741274235378360898441
c = 26392919777656338278184497106215581599692023606797351841011065350738534402079717897589592521000832026751736045905247050532819571969784687491977953157313304550096179520376626220816081159472339787295872214912587497324709488986746768994907107727184468228540635002062232484115731701648311946527233449512543132274
dp = 7088497034630351463006975624795947102639056977565074157092915907376477955247769847204254053775159112398217033648894620506901638351932922911273150932128973
'''

题目分析

题目提供了以下参数:

  • n: RSA 模数

  • c: 密文

  • dp: 私钥指数 d 对 (p-1) 取模的结果,即 dp = d mod (p-1)

  • e: 公钥指数,值为 65537

这是一个典型的 dp 泄露攻击,当我们知道 dp 时,可以恢复出私钥并解密密文。

数学原理

根据 RSA 定义:

  1. d * e ≡ 1 mod φ(n),其中 φ(n) = (p-1)(q-1)

  2. dp = d mod (p-1)

  3. 由 (2) 可得:d = dp + k*(p-1),其中 k 是一个整数

  4. 将 (3) 代入 (1):e * (dp + k*(p-1)) ≡ 1 mod (p-1)

  5. 化简得:e * dp ≡ 1 mod (p-1),即 e * dp - 1 ≡ 0 mod (p-1)

这意味着 e*dp - 1(p-1) 的倍数。我们可以通过遍历 k 来寻找 p 的值。

解题步骤

步骤 1:寻找 p

根据上述推导,我们有:

python 复制代码
e * dp = 1 + k * (p-1)

其中 k 是 1 到 e 之间的整数(因为 dp < p-1)。

我们可以遍历所有可能的 k,检查 (e*dp - 1) 是否能被 k 整除,从而得到候选的 p:

python 复制代码
p = (e*dp - 1)/k + 1

步骤 2:验证并计算 q

找到候选的 p 后,检查:

  1. p 是否为整数

  2. n 是否能被 p 整除

  3. p 是否为素数(这里简化检查:n % p == 0)

如果满足条件,则:

python 复制代码
q = n // p

步骤 3:计算私钥 d

使用公式:

python 复制代码
φ(n) = (p-1) * (q-1)
d = e^(-1) mod φ(n)  # 即 e 关于 φ(n) 的模逆元

步骤 4:解密密文

使用 RSA 解密公式:

python 复制代码
m = c^d mod n

完整代码

python 复制代码
from Crypto.Util.number import *

# 题目给出的参数
n = 62950660589752377241535942010457460675378335694404721223426371627802159493655570041534480026979837056215567303530448462076388942749116962945931432723672826148999814815864738069663127706046027850586024555861960247057288826014343547293035737544457656904257388300461848219257240252715837662741274235378360898441
c = 26392919777656338278184497106215581599692023606797351841011065350738534402079717897589592521000832026751736045905247050532819571969784687491977953157313304550096179520376626220816081159472339787295872214912587497324709488986746768994907107727184468228540635002062232484115731701648311946527233449512543132274
dp = 7088497034630351463006975624795947102639056977565074157092915907376477955247769847204254053775159112398217033648894620506901638351932922911273150932128973
e = 65537

# 步骤1:遍历 k 寻找 p
print("开始寻找素数 p...")
for k in range(2, e):  # k 从 2 开始,因为 k=1 时 p 可能太大
    # 检查 (e*dp - 1) 是否能被 k 整除
    if (e * dp - 1) % k == 0:
        # 计算候选的 p
        p = (e * dp - 1) // k + 1
        
        # 步骤2:验证 p
        # 检查1: p 是否能整除 n
        if n % p == 0:
            print(f"找到可能的 k = {k}")
            print(f"p = {p}")
            
            # 计算 q
            q = n // p
            print(f"q = {q}")
            
            # 验证 p 和 q 的乘积是否等于 n
            if p * q == n:
                print("验证成功: p * q == n")
                
                # 步骤3:计算私钥 d
                phi = (p - 1) * (q - 1)
                d = inverse(e, phi)  # 计算 e 关于 φ(n) 的模逆元
                print(f"d = {d}")
                
                # 步骤4:解密密文
                m = pow(c, d, n)
                print(f"解密得到的整数 m = {m}")
                
                # 转换为字节串
                flag = long_to_bytes(m)
                print(f"解密得到的 flag = {flag}")
                
                # 由于我们可能找到多个解,这里只取第一个有效的解
                break
            else:
                print("验证失败: p * q != n")
        else:
            continue  # 继续尝试下一个 k

print("\n解密完成!")

最后flag为

NSSCTF{CTFCTFNSSNSS}

总结

  1. 漏洞点:dp 泄露是 RSA 中常见的侧信道攻击,当攻击者知道 dp = d mod (p-1) 时,可以恢复私钥。

  2. 关键步骤 :利用关系式 e*dp ≡ 1 mod (p-1),通过遍历 k 来找到 p。

  3. 防御措施:在实际应用中,需要保护所有私钥参数,包括 d、dp、dq 等,避免信息泄露。

相关推荐
地平线开发者12 小时前
SparseDrive 模型导出与性能优化实战
算法·自动驾驶
董董灿是个攻城狮12 小时前
大模型连载2:初步认识 tokenizer 的过程
算法
地平线开发者13 小时前
地平线 VP 接口工程实践(一):hbVPRoiResize 接口功能、使用约束与典型问题总结
算法·自动驾驶
罗西的思考13 小时前
AI Agent框架探秘:拆解 OpenHands(10)--- Runtime
人工智能·算法·机器学习
孟健15 小时前
Karpathy 用 200 行纯 Python 从零实现 GPT:代码逐行解析
python
HXhlx16 小时前
CART决策树基本原理
算法·机器学习
码路飞16 小时前
写了个 AI 聊天页面,被 5 种流式格式折腾了一整天 😭
javascript·python
Wect16 小时前
LeetCode 210. 课程表 II 题解:Kahn算法+DFS 双解法精讲
前端·算法·typescript
颜酱17 小时前
单调队列:滑动窗口极值问题的最优解(通用模板版)
javascript·后端·算法
曲幽19 小时前
FastAPI压力测试实战:Locust模拟真实用户并发及优化建议
python·fastapi·web·locust·asyncio·test·uvicorn·workers