Task.py
from Crypto.Util.number import * # 导入Crypto库中的数字处理工具
from secret import flag # 从secret模块中导入flag
import random # 导入random库以生成随机数
# 定义一个大质数p,用于后续的模运算
p = 2050446265000552948792079248541986570794560388346670845037360320379574792744856498763181701382659864976718683844252858211123523214530581897113968018397826268834076569364339813627884756499465068203125112750486486807221544715872861263738186430034771887175398652172387692870928081940083735448965507812844169983643977
assert len(flag) == 42 # 确保flag的长度为42字节
def encode(msg):
"""将字节消息转换为二进制字符串"""
return bin(bytes_to_long(msg))[2:].zfill(8 * len(msg)) # 转换为长整型后转为二进制,填充到固定长度
def genkey(length):
"""生成指定长度的随机密钥"""
sums = 0 # 初始化总和
keys = [] # 初始化密钥列表
for i in range(length):
k = random.randint(1, 7777) # 生成1到7777之间的随机数
x = sums + k # 计算当前密钥
keys.append(x) # 添加密钥到列表
sums += x # 更新总和
return keys # 返回生成的密钥列表
# 生成一个长度为42*8的密钥列表,表示42个字节的flag
key = genkey(42 * 8)
def enc(m, keys):
"""加密函数,将消息和密钥进行加密"""
msg = encode(m) # 将消息编码为二进制字符串
print(len(keys)) # 打印密钥的长度
print(len(msg)) # 打印消息的长度
assert len(msg) == len(keys) # 确保消息长度与密钥长度匹配
# 计算加密值s
s = sum((k if (int(p, 2) == 1) else 1) for p, k in zip(msg, keys))
print(msg) # 打印编码后的消息
for p0, k in zip(msg, keys):
print(int(p0, 2)) # 打印每个消息位对应的整数值
# 使用模运算计算最终密文
return pow(7, s, p)
# 进行加密,得到密文
cipher = enc(flag, key)
# 将密钥和密文写入output.txt文件
with open("output.txt", "w") as fs:
fs.write(str(key) + '\n') # 写入密钥
fs.write(str(cipher)) # 写入密文
先就题论题一下,这个是个背包问题,就是说在sum中,如果msg中的是1,那么它就是k的某位,反之,则是0.我们注意到k的生成过程,发现它每一项就是前几项的和。典型的背包问题,所以我们要想解flag,就是要解msg,要解msg,就是利用离散对数的方法求7的指数,然后根据背包贪心算法,找到哪些是msg的。
然后离散对数这边,我们才用的是Pohig-Hellman算法,它的条件分别是
- 求解以
base
为底 a
的对数ord
为base
的阶,可以忽略operation
可以是+
与*
,默认为*
bounds
是一个区间(ld,ud)
,需要保证所计算的对数在此区间内
它的式子是
discrete_log(a,base,ord,operation)
里面的一些数学问题,你们可以去搜索了解一下,这里不多说,因为我数学不是很好。
所以这时候分解一下p-1
sage: factor(p-1)
2^3 * 3 * 7 * 636277 * 677857 * 682777 * 735809 * 860059 * 903949 * 908441 * 954851 * 1017139 * 1032341 *
1163131 * 1190737 * 1227157 * 1341323 * 1395671 * 1463611 * 1556201 * 1569401 * 1713749 * 1930931 *
2219563 * 2476283 * 2477281 * 2590633 * 2756587 * 2833643 * 3095713 * 3281449 * 3688063 * 4008793 *
4285993 * 5443981 * 5720053 * 5822981 * 6201869 * 6892217 * 7093841 * 7319857 * 8227237 * 9381107 *
9477463 * 10078729 * 10084297 * 10764907 * 12416167 * 14095651 * 14294663 * 14788051
发现它比较光滑
所以exp很好写了(bushi)
from sage.all import *
from Crypto.Util.number import *
keys =
cipher =
p =
F = GF(p)
a = F(7)
X = F(cipher)
n = a.order()
primes = [2^3,3,7,636277,677857,682777,735809,860059,903949,908441,954851, 1017139, 1032341, 1163131,
1190737, 1227157, 1341323, 1395671, 1463611, 1556201, 1569401, 1713749, 1930931, 2219563, 2476283,
2477281, 2590633, 2756587, 2833643, 3095713, 3281449, 3688063, 4008793, 4285993, 5443981, 5720053,
5822981, 6201869, 6892217, 7093841, 7319857, 8227237, 9381107, 9477463, 10078729, 10084297, 10764907,
12416167, 14095651, 14294663,14788051]
dlogs = []
for fac in primes:
t = int(n//fac)
dlog = discrete_log(X**t, a**t)
dlogs += [dlog]
print("factor:"+str(fac)+",Discrete Log:"+str(dlog))
nc = crt(dlogs,primes)
print(nc)
assert pow(7,nc,p) == cipher
nc = nc % ((p-1)//8)
t = len(keys)
print(t)
x = []
for i in range(t):
x.append(0)
for i in range(1, t+1):
if nc >= keys[t-i]:
x[i-1] = 1
nc = nc - (keys[t-i])
else:
x[i-1] = 0
y = 0
for i in range(1, t+1):
y += x[i-1] * 2**(i-1)
print(y)
print(long_to_bytes(y))