背包加密算法
前言
在一次CTF比赛中遇到了,写了10个for嵌套硬爆出来了,复现的时候发现是背包加密。
Merkle–Hellman 公钥加密算法
整体加密流程 1
2
3
4
5
6
7
8import numpy
x = [1,0,0,1,0]#明文对应的2进制数
a = [3,7,16,50,120]# 产生一个超递增序列,称作私钥
#对私钥a进行加密,产生公钥b。
m = 251#选取一个模数
w = 300#选取一个乘数
b = [w * x % m for x in a]#产生公钥
S = numpy.dot(x,b)#加密结果
生成私钥
超递增序列,也就是a中每一位元素需要大于其之前所有元素的和。
1
2
3a =[randint(20, 50)]
for i in range(nbits - 1):
a.append(randint(2 * a[-1], 3 * a[-1]))
生成公钥
模数m要求:m > sum(a)
乘数w要求:gcd(w,m) == 1
1
2
3
4
5
6
7while True:
m = randint(2 * a[-1] + 1, 3 * a[-1])
w = randint(2 * a[-1] + 1, 3 * a[-1])
if gcd(w, m) == 1:
break
b = [w * x % m for x in a]S = numpy.dot(x,b)
解密
拿到公钥\(M=(m_1,m_2,\ldots,m_n)\),构造如下矩阵 \[ \begin{bmatrix} 2 & 0 & \ldots & 0 & m_1 \\ 0 & 2 & \ldots & 0 & m_2 \\ \vdots & \vdots & \ddots & \vdots & \vdots \\ 0 & 0 & \ldots & 2 & m_n \\ 1 & 1 & \ldots & 1 & S \\ \end{bmatrix} \] 这个矩阵的所有行向量的线性组合构成了一个格,接下来将通过明文的特点和格上的特殊解法来进行解密。
LLL
对于明文\(X=(x_1,x_2,\ldots,x_n)\)这一组数来说,构造一个向量 \[ a=\sum_{i=1}^nx_iv_i-v_{n+1}=(2x_1-1,2x_2-1,\ldots,2x_n-1,0) \] 显然,a向量在格L上。因为X中的所有x只能取值0或1,因此a向量的长度很小,约为\(\sqrt{n}\),对于很大的格基来说,a向量无疑是格L上的最小向量,因此我们利用LLL算法即可求出a向量。
例题
1 |
|
这里注意一下,第一行向量中是有+1与-1,需要进行取反,即-1代表1,1代表0。