Appearance
背包密码
背包问题
假设有序列
这个问题是 NP hard 的。
例如:
超增背包问题
假设有一个超增序列(SIK)
假设
- 251 > 186,不选 251, 余 186
- 120 ≤ 186,选 120, 余 66
- 57 ≤ 66,选 57, 余 9
- 30 > 9,不选 30, 余 9
- 14 > 9,不选 14, 余 9
- 7 ≤ 9,选 7, 余 2
背包密码
1. Keygen
- 选择一个超增序列
。 - 选择一个模数
,满足 。 - 选择
,满足 。 - 计算序列
,其中 。
得到:
- 公钥:
。 - 私钥:
。
e.g:
2. Encrypt
- 假设明文
- 密文
3. 解密
- 计算
。 - 然后使用超增序列,容易解得
,对应明文 。
使用格破解背包密码
从攻击者视角,只知道公钥超递增背包被“扰乱”后的序列:
- 已知:
,以及密文 - 不知:超增序列
、模数 、乘数
但对任意明文比特向量
以及
把解密问题改写成求解短向量的形式
解密的本质是:从所有
的向量
如果我们能把“所有可能的线性组合”组织进一个格里,那么“正确的那一个组合”就会对应于格中的某个特殊向量(通常是比较短的向量)。
这就把“解背包”转化成了一个格中的最短向量问题。
构造格
在这里,
任意整数向量
格
对于明文
因为
前
由于
利用 格基规约 算法恢复明文
可以通过 LLL 或者 BKZ 等格基规约算法,找到格
攻击步骤如下:
- 根据公钥
和密文 构造格基矩阵 ; - 对
应用 LLL 算法,得到一组约简基 ; - 检查每个基向量: 若某向量
的最后一个分量为 0, 且前 个分量均为 0 或 1, 则该向量极可能就是 ; - 提取前
位作为明文 ,并验证 。
Code
Sage
python
from sage.all import *
from Crypto.Util.number import *
Length = 16
# 生成私钥: 超增序列
def gen_superincreasing_sequence(length):
sequence = []
current_sum = 0
for _ in range(length):
next_element = current_sum + randint(1, 10)
sequence.append(next_element)
current_sum += next_element
return sequence, current_sum
sequence, total_sum = gen_superincreasing_sequence(Length)
print("私钥:",sequence)bash
私钥: [9, 17, 32, 65, 129, 259, 517, 1033, 2067, 4136, 8270, 16537, 33078, 66151, 132305, 264611]python
# 生成模数和乘数
bits = log(total_sum, 2)
p = getPrime(int(bits) + 1)
while True:
m = randint(2, p - 1)
if gcd(m, p) == 1:
break
print("p: ", p)
print("m: ", m)bash
p: 711751
m: 421763python
# 生成公钥
pub_key = []
for i in sequence:
pub_key.append((i * m) % p)
print("公钥: ",pub_key)bash
公钥: [237112, 52461, 684898, 368057, 314351, 338714, 255665, 89567, 600897, 621818, 400110, 246682, 45163, 116764, 75315, 572393]python
message = [1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0]
# 加密
ciphertext = 0
for i in range(Length):
ciphertext += message[i] * pub_key[i] % p
print("密文: ",ciphertext)bash
密文: 2613511python
# 解密
m_inv = inverse_mod(m, p)
adjusted_ciphertext = (ciphertext * m_inv) % p
def decrypt_superincreasing_sequence(sequence, adjusted_ciphertext):
decrypted_message = []
for element in reversed(sequence):
if adjusted_ciphertext >= element:
decrypted_message.append(1)
adjusted_ciphertext -= element
else:
decrypted_message.append(0)
decrypted_message.reverse()
return decrypted_message
dec = decrypt_superincreasing_sequence(sequence, adjusted_ciphertext)
print("解密:", dec)
assert dec == messagebash
解密: [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]- 构造格
在这里只有一条密文
python
# 生成单位阵 I
I = identity_matrix(Length)
weight = 1
# 零向量
zero_row = Matrix(ZZ, 1, Length, [0]*Length)
# 公钥向量
T_vev = Matrix(ZZ, Length, 1, pub_key) * weight
# 密文向量
C_vev = Matrix(ZZ, 1, 1, [-ciphertext]) * weight
# 拼接分块矩阵
L = block_matrix([[I, T_vev], [zero_row, C_vev]])
print(L)bash
[ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0| 237112]
[ 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0| 52461]
[ 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0| 684898]
[ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0| 368057]
[ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0| 314351]
[ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0| 338714]
[ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0| 255665]
[ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0| 89567]
[ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0| 600897]
[ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0| 621818]
[ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0| 400110]
[ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0| 246682]
[ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0| 45163]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0| 116764]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0| 75315]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1| 572393]
[-----------------------------------------------------------------------------------------------------------------------------------------------+--------]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|-2613511]python
# LLL
L_LLL = L.BKZ()
print(L_LLL)bash
[ 0 0 0 0 0 0 -2 -1 1 0 0 0 0 0 0 0 0]
[ 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 0]
[ 0 0 0 0 0 0 0 2 -1 0 0 0 0 0 -2 1 0]
[ 1 -1 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 1 -1 0]
[ 0 0 0 2 -1 0 -2 1 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 -2 1 -2 1 0 0 0 0 0 0 0 0]
[ 0 -2 -1 1 0 0 0 -2 1 0 0 0 0 0 0 0 0]
[ 0 -1 -1 0 0 -1 1 0 0 1 1 -1 1 0 0 0 1]
[ 1 -1 -1 0 -1 0 1 -1 -1 -2 0 0 -1 0 -1 0 0]
[ 0 0 0 0 0 0 0 -2 1 0 0 -2 -1 1 0 0 0]
[ 1 1 0 1 1 0 -2 1 0 -1 0 0 -1 1 0 0 1]
[ 1 0 -1 -1 0 0 1 0 0 0 1 1 -1 -1 1 0 2]
[ 0 0 2 -1 0 0 0 0 0 0 -2 -1 1 0 0 0 0]
[ 0 0 0 0 2 1 -1 0 0 0 -2 -1 -1 -1 -1 1 0]
[ 2 1 -1 0 0 0 0 0 0 0 0 0 0 2 -1 0 0]
[ 0 1 0 1 1 0 0 -2 -1 0 0 0 1 0 0 0 1]
[ 1 0 0 0 -1 0 -1 1 0 -1 -1 0 1 0 1 2 -1]python
# 找到最短向量
def fine(L_LLL):
all_positive = True
for i in range(Length):
for row in L_LLL[i][:-1]:
if row < 0:
all_positive = False
break
if all_positive:
return L_LLL[i][:-1]
all_positive = True
res = fine(L_LLL)
print("最短向量: ", res)
assert list(res) == messagebash
最短向量: (1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0)