BugKu-MaybeEasyRSA
BugKu-MaybeEasyRSA
from Crypto.Util.number import *
from secret import flag
from sympy import nextprime
flag=b''
r = getRandomNBitInteger(64)
p1 = r**5 + r**4 - r**3 + r**2 - r + 2024
q1 = r**5 - r**4 + r**3 - r**2 + r + 2024
p =nextprime(p1)
q =nextprime(q1)
n = p*q
def enc(flag, n):
m = bytes_to_long(flag)
return pow(m, 65537, n)#这里的65537是公钥,
# m是明文然后是m的65537次方求余n得到c也就是密文
#这里公开了三个东西一个是公钥,一个是N,一个是密文
#公开N就代表了公开了两个质数的乘积
# 而这里最难的就是找到这两个质数,我们取最大的可能就是r^10次方等于N求r
c = enc(flag, n)
print(n)
print(c)
#1058756604181685917958185571746711428601045466594619627088399455470892502310139608978164573773765910533535849969889860275644658086339362201840191861497991951344100284004205747279828567835277683
#643011921358774538378881505518732362708757638007688649119354348647468190640688857686213431516881297805187671774564672497176686191162897918672339254715366498963369868410476737543157157149810569
拿到题看到:r = getRandomNBitInteger(64)r的位数为64位也是非常大
p1 = r**5 + r**4 - r**3 + r**2 - r + 2024
q1 = r**5 - r**4 + r**3 - r**2 + r + 2024
因为r为64位的数所以r^5+r^4-r^3+r^2+2024<r^5
p1和p2最大约等于r^5次方
p =nextprime(p1)这句话的意思是:nextprime()是一个函数作用是找比p1还大的最小质数
n = p*q 因为p和q 的最大值都约等于r^5次方所以n最大为r^10次方
def enc(flag, n):
m = bytes_to_long(flag)
return pow(m, 65537, n)
这里定义了一个函数enc代表加密,解释一下:pow(m,65537,n)用m^65537次方求余n
c = enc(flag, n)然后将值给到c,最后输出了n和c
这里的65537对应的是E,然后密文是c所以我们就需要知道N就行了,难就难在这里!
我们先看上面两张图N是两个质数的乘积而N我们已经知道了但是这两个质数很大所以很难。我们要反推求质数从而得到欧拉函数的值然后在用欧拉函数的值和公钥来算私钥:(D*E)%T=1就行使用invert(E,T)就行
所以,这道题就是考验反推两个质数就行
使用脚本:
from gmpy2 import *
from sympy import nextprime
n = 1058756604181685917958185571746711428601045466594619627088399455470892502310139608978164573773765910533535849969889860275644658086339362201840191861497991951344100284004205747279828567835277683
c = 643011921358774538378881505518732362708757638007688649119354348647468190640688857686213431516881297805187671774564672497176686191162897918672339254715366498963369868410476737543157157149810569
e = 65537
#先已知的值赋值进去
# p1 ≈ r^5
# q1 ≈ r^5
# n ≈ (r^5) * (r^5) = r^10
# iroot(n, 10)[0] 是计算 n 的第10次方根
r_prox = iroot(n, 10)[0]
print(f"n的十次方为:{r_prox}")
# 循环遍历
for r in range(r_prox - 2000, r_prox + 2000):#这句话是从a-2000到a+2000总共4000次循环,为什么这样写因为我也不知道
p1 = r ** 5 + r ** 4 - r ** 3 + r ** 2 - r + 2024
q1 = r ** 5 - r ** 4 + r ** 3 - r ** 2 + r + 2024
p = nextprime(p1)
q = nextprime(q1)
if p * q == n:
# 计算私钥
print(f"p:{p}")
print(f"q:{q}")
L = (p - 1) * (q - 1)#这个是欧拉函数,就是个质数减一然后相乘等于T
d = invert(e, L)#这就是(D*E)%L=1,已知两个求第二个只能求D和E中的一个且必须知道一个和T才行
# 求明文
m = pow(c, d, n)#我们知道了私钥和密文以及公文N就可以求明文,密文^d%n=明文就等于c^d%n=明文
# m.bit_length(): 返回整数 m 的二进制表示中最高位的索引(即,m 的二进制表示的位数)。
# + 7: 这是为了向上取整。如果我们直接除以 8,我们可能会丢失不足一个字节的那些位。例如,9 位实际上需要 2 个字节(9/8 = 1.125 向上取整到 2)。所以我们加上 7 来保证任何非零位数都能向上取整。
# // 8: 整除 8,计算出 m 转换为字节串所需的字节数。每个字节包含 8 位,所以我们需要除以 8。
byte_length = (m.bit_length() + 7) // 8
# m.to_bytes(byte_length, byteorder='big'): 将整数 m 转换为字节串。
# byteorder='big': 表示使用大端序(big-endian)字节顺序存储整数。大端序意味着最高有效字节(最左边的字节)存储在最小的内存地址上。
decrypted_flag = m.to_bytes(byte_length, byteorder='big')
#这句话的意思是将得到的明文字节数byte_length以byteorder='big'这种正常方式由左到右放,然后m.to_bytes表示将这一段数字转换为二进制然后没八位转换为ascii编码对应的字符
print(decrypted_flag)
break
byte_length = (m.bit_length() + 7) // 8我解释一下这个就行了,一个字节站8位也就是8bite(比特),就是8个二进制数,然后m.bit_length()这个就是计算m一共有多少位bite,然后为什么要加7,因为当m.bit_length为9-15时他们理应站两个字节但是//8就只有一个字节了因为//是直接砍掉小数,所以加7是为了留下少的那个字节比如
byte_length=(9+7)//8:结果就为16//8=2,byte_length=(6+7)//8:等于13//8=1。
得到的结果就是m所占的字节数。
b是占位符单引号里面才是我们要的内容



浙公网安备 33010602011771号