xctf攻防世界 CRYPTO高手进阶区 best_rsa

1. 进入环境,下载附件

题目给的压缩包,包括4个文件,如图:
在这里插入图片描述
给出了2个公钥文件和和2个密文文件,用常规的RSA解密方式分别解密,解密失败(n为2048位难以分解)

2. 问题分析

  1. 继续复习RSA
  • 明文为m,密文为c,模数n = p * q
  • 使用欧拉函数,φ(n) = (p - 1) * (q- 1)
  • 选取一个大整数e,使得gcd(e, φ(n) ) = 1,e用来加密秘钥
  • 私钥d可以由欧拉函数值计算出来,满足ed mod φ(n) ≡ 1
  • 将明文m加密成密文c:m^e ≡ c (mod n)
  • 将密文c解密成明文m:c^d ≡ m (mod n)
  1. 共模攻击
    猜测应该是同一个明文,使用了2个不同的公钥加密得到了不同的密文,对同一明文的多次加密使用相同的模数和不同的公钥指数可能导致共模攻击。

翻看大佬的wp后:https://blog.csdn.net/weixin_44795952/article/details/108933406,明白了什么是共模攻击

所谓共模,就是明文m相同,模n相同,用两个公钥e1,e2加密得到两个私钥d1,d2和两个密文c1,c2
共模攻击,即当n不变的情况下,知道n,e1,e2,c1,c2 。可以在不知道d1,d2的情况下,解出m。
这里有个条件,即

gcd(e1,e2)=1
  1. 攻击原理
    此处引用博主的分析:https://blog.csdn.net/weixin_44795952/article/details/108933406

    有整数 s 1 s_{1} s1, s 1 s_{1} s1(一正一负),满足:

    e 1 ∗ s 1 + e 2 ∗ s 2 = 1 e_{1} * s_{1} + e_{2} * s_{2} = 1 e1s1+e2s2=1

根据扩展欧几里德算法,我们可以得到该式子的一组解(s1,s2),假设s1为正数,s2为负数。

同时需要了解欧几里得算法:
其实就是辗转相除法,得到最大公约数:

d = gcd(b,a mod b) //这里假设a>b
# 一次辗转相除如下
gcd(a,b) = gcd(b,a mod b)
# 一直辗转相除下去,可得:
gcd(a,b) = gcd(b,a mod b) = ... = gcd(m,0)
其中m为最大公约数

扩展欧几里得算法

对于不完全为 0 的非负整数 a,b,有gcd(a,b)
必然存在整数对 x,y ,使得 gcd(a,b)=a*x+b*y。

代码如下:

def egcd(a, b):
    if a == 0:
        return b, 0, 1
    else:
        g, y, x = egcd(b % a, a)
        return g, x - (b // a) * y, y

证明:

c 1 = m e 1 % n c_{1}=m^{e1}\%n c1=me1%n
c 2 = m e 2 % n c_{2}=m^{e2}\%n c2=me2%n

那么则有:
c 1 s 1 = ( m e 1 % n ) s 1 c_{1}^{s1} = (m^{e1} \% n )^{s1} c1s1=(me1%n)s1
c 2 s 2 = ( m e 2 % n ) s 2 c_{2}^{s2} = (m^{e2} \% n )^{s2} c2s2=(me2%n)s2

两式相乘,化简则有:
c 1 s 1 ∗ c 2 s 2 = m e 1 ∗ s 1 ∗ m e 2 ∗ s 2 % n c_{1}^{s1} *c_{2}^{s2}=m^{e1*s1}*m^{e2*s2}\%n c1s1c2s2=me1s1me2s2%n

又因为有:
e 1 ∗ s 1 + e 2 ∗ s 2 = 1 e_{1} * s_{1} + e_{2} * s_{2} = 1 e1s1+e2s2=1

最终则有:
c 1 s 1 ∗ c 2 s 2 = m % n c_{1}^{s1} *c_{2}^{s2}=m\%n c1s1c2s2=m%n

需要注意的是:
一个数的负次幂,在数论模运算中,要求一个数的负数次幂,与常规方法并不一样。比如此处要求c2的s2次幂,就要先计算c2的模反元素c2r,然后求c2r的-s2次幂

所以我们有以下脚本:

  1. 最终解题脚本
from Crypto.Util.number import long_to_bytes, bytes_to_long
from Crypto.PublicKey import RSA
from gmpy2 import gcd, invert


def egcd(a, b):
    if a == 0:
        return b, 0, 1
    else:
        g, y, x = egcd(b % a, a)
        return g, x - (b // a) * y, y


with open('pic/publickey1.pem', 'rb') as f:
    f1 = f.read()
pub1 = RSA.importKey(f1)
# 拿到共模数
n = int(pub1.n)
# 拿到公钥e1
e1 = int(pub1.e)

with open('pic/publickey2.pem', 'rb') as f:
    f2 = f.read()
pub2 = RSA.importKey(f2)

# 拿到公钥e2
e2 = int(pub2.e)

with open('pic/cipher1.txt', 'rb') as f:
    c1 = f.read()
# 得到密文c1
c1 = bytes_to_long(c1)
print(c1)

with open('pic/cipher2.txt', 'rb') as f:
    c2 = f.read()
# 得到密文c2
c2 = bytes_to_long(c2)
print(c2)

# 得到扩展欧几里得中的计算模系数
s = egcd(e1, e2)

s1 = s[1]
s2 = s[2]

# 避免负指数运算
if s1 < 0:
    s1 = -s1
    c1 = invert(c1, n)
elif s2 < 0:
    s2 = -s2
    c2 = invert(c2, n)

# 
m = pow(c1, s1, n) * pow(c2, s2, n) % n
print(m)
print(long_to_bytes(m).decode())

最终答案为:flag{interesting_rsa}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

l8947943

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值