[MoeCTF_EzPack]背包问题+Pohig-Hellman算法

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的对数
  • ordbase的阶,可以忽略
  • 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))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值