NSSCTF_crypto_[BJDCTF 2020]rsa

NSSCTF_crypto_[BJDCTF 2020]rsa

提示:共享素数   素数分解

题目:

from Crypto.Util.number import getPrime,bytes_to_long

flag=open("flag","rb").read()

p=getPrime(1024)
q=getPrime(1024)
assert(e<100000)
n=p*q
m=bytes_to_long(flag)
c=pow(m,e,n)
print c,n
print pow(294,e,n)

p=getPrime(1024)
n=p*q
m=bytes_to_long("BJD"*32)
c=pow(m,e,n)
print c,n

'''
output:
12641635617803746150332232646354596292707861480200207537199141183624438303757120570096741248020236666965755798009656547738616399025300123043766255518596149348930444599820675230046423373053051631932557230849083426859490183732303751744004874183062594856870318614289991675980063548316499486908923209627563871554875612702079100567018698992935818206109087568166097392314105717555482926141030505639571708876213167112187962584484065321545727594135175369233925922507794999607323536976824183162923385005669930403448853465141405846835919842908469787547341752365471892495204307644586161393228776042015534147913888338316244169120   13508774104460209743306714034546704137247627344981133461801953479736017021401725818808462898375994767375627749494839671944543822403059978073813122441407612530658168942987820256786583006947001711749230193542370570950705530167921702835627122401475251039000775017381633900222474727396823708695063136246115652622259769634591309421761269548260984426148824641285010730983215377509255011298737827621611158032976420011662547854515610597955628898073569684158225678333474543920326532893446849808112837476684390030976472053905069855522297850688026960701186543428139843783907624317274796926248829543413464754127208843070331063037
381631268825806469518166370387352035475775677163615730759454343913563615970881967332407709901235637718936184198930226303761876517101208677107311006065728014220477966000620964056616058676999878976943319063836649085085377577273214792371548775204594097887078898598463892440141577974544939268247818937936607013100808169758675042264568547764031628431414727922168580998494695800403043312406643527637667466318473669542326169218665366423043579003388486634167642663495896607282155808331902351188500197960905672207046579647052764579411814305689137519860880916467272056778641442758940135016400808740387144508156358067955215018
979153370552535153498477459720877329811204688208387543826122582132404214848454954722487086658061408795223805022202997613522014736983452121073860054851302343517756732701026667062765906277626879215457936330799698812755973057557620930172778859116538571207100424990838508255127616637334499680058645411786925302368790414768248611809358160197554369255458675450109457987698749584630551177577492043403656419968285163536823819817573531356497236154342689914525321673807925458651854768512396355389740863270148775362744448115581639629326362342160548500035000156097215446881251055505465713854173913142040976382500435185442521721  12806210903061368369054309575159360374022344774547459345216907128193957592938071815865954073287532545947370671838372144806539753829484356064919357285623305209600680570975224639214396805124350862772159272362778768036844634760917612708721787320159318432456050806227784435091161119982613987303255995543165395426658059462110056431392517548717447898084915167661172362984251201688639469652283452307712821398857016487590794996544468826705600332208535201443322267298747117528882985955375246424812616478327182399461709978893464093245135530135430007842223389360212803439850867615121148050034887767584693608776323252233254261047
'''

题目分析

我们有以下已知信息:

  • 两个RSA模数n1和n2,它们共享一个相同的素数因子q

  • 一个密文c2,其对应的明文是"BJD"重复32次

  • 公钥指数e小于100000

  • 另一个密文c1,需要使用我们找到的信息来解密

解题步骤

第一步:分解n1和n2获取共用素数q

由于n1和n2共享一个素数因子q,我们可以通过计算它们的最大公约数(GCD)来找到q:

q = math.gcd(n1, n2)

验证:计算结果 q 为两个大数的公共素因子

2. 分解 n2 得到 p2

数学关系:n2 = p2·q → p2 = n2 // q

p2 = n2 // q
  • 注意点:确保 p2 为整数且为素数(大数分解验证)

3. 已知明文攻击确定 e

  • 已知条件:明文 m = "BJD"*32 → 转换为长整数 m_this
  • 攻击思路
    • 计算 φ(n2) = (p2-1)(q-1)
    • 暴力枚举 e(1 < e < 100,000)
    • 验证 d = e⁻¹ mod φ(n2) 的正确性
    • 通过 pow (c2, d, n2) == m_this 确认 e

4. 解密 n1 的密文 c1

  • 步骤
    1. 分解 n1 得到 p1 = n1 //q
    2. 计算 φ(n1) = (p1-1)(q-1)
    3. 计算 d1 = e⁻¹ mod φ(n1)
    4. 解密 c1 = pow (c1, d1, n1)
    5. 转换为 ASCII 字符串
  • 关键函数
hex_str = hex(m1)[2:]
bytes_data = binascii.unhexlify(hex_str)
flag = bytes_data.decode('utf-8')

完整代码实现:

import math  # 数学库,提供gcd等函数
import binascii  # 用于二进制与ASCII转换
import gmpy2  # 高性能数学库,处理大数运算
from Crypto.Util.number import bytes_to_long  # 字节转长整数

def main():
    # ======================== 第一步:分解n1和n2获取共用素数q ========================
    # 已知两个不同的RSA模数n1和n2,但共享同一个素数因子q
    # 数学原理:若n1 = p1*q,n2 = p2*q,则gcd(n1, n2) = q
    n1 = 13508774104460209743306714034546704137247627344981133461801953479736017021401725818808462898375994767375627749494839671944543822403059978073813122441407612530658168942987820256786583006947001711749230193542370570950705530167921702835627122401475251039000775017381633900222474727396823708695063136246115652622259769634591309421761269548260984426148824641285010730983215377509255011298737827621611158032976420011662547854515610597955628898073569684158225678333474543920326532893446849808112837476684390030976472053905069855522297850688026960701186543428139843783907624317274796926248829543413464754127208843070331063037
    n2 = 12806210903061368369054309575159360374022344774547459345216907128193957592938071815865954073287532545947370671838372144806539753829484356064919357285623305209600680570975224639214396805124350862772159272362778768036844634760917612708721787320159318432456050806227784435091161119982613987303255995543165395426658059462110056431392517548717447898084915167661172362984251201688639469652283452307712821398857016487590794996544468826705600332208535201443322267298747117528882985955375246424812616478327182399461709978893464093245135530135430007842223389360212803439850867615121148050034887767584693608776323252233254261047
    
    # 计算n1和n2的最大公约数,得到共享素数q
    q = math.gcd(n1, n2)
    print("[DEBUG] q =", q)  # 实际场景建议打印验证
    
    # ======================== 第二步:分解n2得到p2 ========================
    # 已知n2 = p2 * q,因此p2 = n2 // q
    p2 = n2 // q
    print("[DEBUG] p2 =", p2)  # 验证p2是否为整数
    
    # ======================== 第三步:通过已知明文攻击确定e ========================
    # 题目给出线索:e < 100000,且已知明文为"BJD"*32的字节形式
    c2 = 979153370552535153498477459720877329811204688208387543826122582132404214848454954722487086658061408795223805022202997613522014736983452121073860054851302343517756732701026667062765906277626879215457936330799698812755973057557620930172778859116538571207100424990838508255127616637334499680058645411786925302368790414768248611809358160197554369255458675450109457987698749584630551177577492043403656419968285163536823819817573531356497236154342689914525321673807925458651854768512396355389740863270148775362744448115581639629326362342160548500035000156097215446881251055505465713854173913142040976382500435185442521721
    m_this = bytes_to_long(b"BJD"*32)  # 已知明文对应的长整数
    
    # 计算n2的欧拉函数φ(n2) = (p2-1)*(q-1)
    φn2 = (p2-1)*(q-1)
    
    # 暴力遍历e的可能值(1到99999)
    e_final = None
    for e_candidate in range(1, 100000):
        # 打印进度(每1000次输出一次)
        if e_candidate % 1000 == 0:
            print(f"进度: {e_candidate}/99999")
        
        # 尝试计算e的模逆元d = e^-1 mod φn2
        try:
            d_candidate = gmpy2.invert(e_candidate, φn2)
        except ZeroDivisionError:  # e和φn2不互质时无法求逆,跳过
            continue
        
        # 解密密文c2,验证是否得到已知明文m_this
        m_decrypted = pow(c2, d_candidate, n2)
        if m_decrypted == m_this:
            print(f"[成功] 找到e = {e_candidate}")
            e_final = e_candidate
            break
    
    if not e_final:
        print("[错误] 未找到符合条件的e")
        return

    # ======================== 第四步:使用已知e解密n1的密文 ========================
    # 分解n1得到p1 = n1 // q
    p1 = n1 // q
    
    # 计算n1的欧拉函数φ(n1) = (p1-1)*(q-1)
    φn1 = (p1-1)*(q-1)
    
    # 计算私钥d1 = e^-1 mod φ(n1)
    d1 = gmpy2.invert(e_final, φn1)
    
    # 解密密文c1
    c1 = 12641635617803746150332232646354596292707861480200207537199141183624438303757120570096741248020236666965755798009656547738616399025300123043766255518596149348930444599820675230046423373053051631932557230849083426859490183732303751744004874183062594856870318614289991675980063548316499486908923209627563871554875612702079100567018698992935818206109087568166097392314105717555482926141030505639571708876213167112187962584484065321545727594135175369233925922507794999607323536976824183162923385005669930403448853465141405846835919842908469787547341752365471892495204307644586161393228776042015534147913888338316244169120
    m1 = pow(c1, d1, n1)  # m1 = c1^d1 mod n1
    
    # 将解密后的长整数转换为字节,再解码为字符串
    hex_str = hex(m1)[2:]  # 去除十六进制前缀'0x'
    bytes_data = binascii.unhexlify(hex_str)
    flag = bytes_data.decode('utf-8')
    print("最终Flag:", flag)

if __name__ == '__main__':
    main()

总结

这道题目展示了RSA中共享素数因子的安全问题。当两个不同的模数共享一个素数因子时,攻击者可以通过计算GCD轻松分解模数。此外,当已知明文-密文对时,可以暴力破解较小的公钥指数e。这些攻击方式强调了在实际应用中必须:

  1. 确保每个RSA密钥对使用完全独立的素数

  2. 使用足够大的公钥指数

  3. 避免使用可预测的明文

运行后flag为

BJD{p_is_common_divisor}

修改一下

NSSCTF{p_is_common_divisor}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值