【密码学全栈】8 信息论与完美保密完全指南:从Shannon熵、互信息到一次一密、语义安全及Python实现(万字长文)
目录
博主智算菩萨,专注于人工智能、Python编程、音视频处理及UI窗体程序设计等方向。致力于以通俗易懂的方式拆解前沿技术,从零基础入门到高阶实战,陪伴开发者共同成长。目前已开设五大技术专栏,累计发布多篇原创技术文章,深受读者好评。
📌 专栏导航
- 人工智能前沿知识:深度剖析Transformer架构、生成式AI、强化学习、具身智能、神经符号系统、大模型及智能体(Agent)技术,系统性解析AI核心技术体系与前沿趋势。
- Python基础小白编程:从零开始,以保姆式教程讲解变量、数据类型、流程控制、函数等核心语法,配有大量实战代码与避坑指南,真正做到学以致用。
- 机器学习与深度学习:系统化拆解线性模型、决策树、随机森林、梯度提升树、神经网络等算法原理与工程实践,覆盖从公式推导到代码实现的全链路内容。
- 音频、图像与视频处理理论与实战:涵盖FFmpeg多媒体处理、audio_shop开源工具、ComfyUI-WanVideoWrapper视频生成等实用技术,从基础操作到高级应用一应俱全。
- UI窗体程序设计实战:深入讲解UI设计、动态窗体生成、游戏UI框架设计等实战技巧,提供从配置到编码的完整解决方案。
智算菩萨,以代码为经,以算法为纬,在人工智能的星辰大海中,做你前行路上最可靠的导航者。
章节引言:1948年,Claude Shannon发表了划时代的论文《A Mathematical Theory of Communication》,奠定了信息论的数学基础。一年后,他又发表了《Communication Theory of Secrecy Systems》,将信息论的严谨工具引入密码学分析。这两篇论文从根本上改变了人类对"保密"的理解——密码学从此从一门依赖直觉和经验的艺术,转变为一门建立在严格数学证明之上的科学。本章将带领读者从信息论的基本概念出发,逐步理解完美保密的数学定义,见证一次一密(One-Time Pad)为何是唯一的完美保密系统,并理解从信息论安全到计算安全的范式转换——这一转换正是现代密码学得以存在的根本原因。
8.1 Shannon信息论基础
8.1.1 自信息:信息的原子单位
在信息论中,自信息(Self-Information)是最基本的概念。它回答了一个核心问题:当某个事件发生時,它带来了多少"信息"?直觉上,一个极其罕见的事件发生时,它携带的信息量应该很大;而一个几乎必然发生的事件发生时,信息量应该很小。
Shannon用对数来量化这一直觉。对于概率为 P ( x ) P(x) P(x) 的事件 x x x,其自信息定义为:
I ( x ) = − log 2 P ( x ) I(x) = -\log_2 P(x) I(x)=−log2P(x)
单位为比特(bit)。当 P ( x ) = 1 / 2 P(x) = 1/2 P(x)=1/2 时, I ( x ) = 1 I(x) = 1 I(x)=1 bit——这就是"1比特信息"的严格定义。自信息满足三个重要性质:非负性( I ( x ) ≥ 0 I(x) \geq 0 I(x)≥0)、单调性(概率越小,信息量越大),以及可加性(独立事件的联合信息等于各自信息之和)。
自信息的概念在密码学中至关重要:攻击者获取的关于密钥或明文的每一条信息,都可以用量化的比特数来衡量。
8.1.2 Shannon熵:不确定性的度量
自信息描述的是单个事件的信息量,但在密码学中我们更关心整个随机变量的平均不确定性。这就是Shannon熵(Entropy)的核心思想。
对于一个离散随机变量 X X X,其熵定义为自信息的期望值:
H ( X ) = E [ I ( X ) ] = − ∑ x ∈ X P ( x ) log 2 P ( x ) H(X) = \mathbb{E}[I(X)] = -\sum_{x \in \mathcal{X}} P(x) \log_2 P(x) H(X)=E[I(X)]=−x∈X∑P(x)log2P(x)
熵具有以下关键性质:
- 非负性: H ( X ) ≥ 0 H(X) \geq 0 H(X)≥0,当且仅当 X X X 是确定值时取等号
- 上界: H ( X ) ≤ log 2 ∣ X ∣ H(X) \leq \log_2 |\mathcal{X}| H(X)≤log2∣X∣,当且仅当 X X X 均匀分布时取等号
- 凹性: H ( X ) H(X) H(X) 是关于概率分布的凹函数
熵的密码学意义极为深刻:一个密码系统的安全性直接取决于密钥的熵—— H ( K ) H(K) H(K) 越大,攻击者猜测密钥所需的信息量就越多。如果 H ( K ) = 128 H(K) = 128 H(K)=128 bit,意味着攻击者平均需要尝试 2 128 2^{128} 2128 种可能才能确定密钥,这在实践中是不可逾越的屏障。
8.1.3 Python实现:熵的计算
下面通过Python代码来直观理解熵的计算,并对比不同分布的熵值:
"""
信息论基础:自信息、熵的计算与可视化
对比不同概率分布的熵值
"""
import numpy as np
import matplotlib.pyplot as plt
import math
# ========== 基础函数定义 ==========
def self_information(p):
"""计算自信息 I(x) = -log2(p)
参数: p - 事件概率
返回: 自信息(比特)
"""
if p <= 0 or p > 1:
return 0.0
return -np.log2(p)
def entropy(prob_dist):
"""计算Shannon熵 H(X) = -Σ p(x) * log2(p(x))
参数: prob_dist - 概率分布(numpy数组,和为1)
返回: 熵值(比特)
"""
prob_dist = np.array(prob_dist)
# 过滤掉概率为0的项
prob_dist = prob_dist[prob_dist > 0]
return -np.sum(prob_dist * np.log2(prob_dist))
# ========== 自信息计算示例 ==========
print("=" * 60)
print("自信息计算示例")
print("=" * 60)
events = {
"掷硬币得到正面": 0.5,
"掷骰子得到6点": 1/6,
"从一副牌中抽到黑桃A": 1/52,
"明天太阳从东方升起": 0.9999,
"猜对一个128位AES密钥": 2**(-128),
}
for event, prob in events.items():
info = self_information(prob)
print(f"{event:30s} (P={prob:.6f}) -> I = {info:.4f} bits")
# ========== 不同分布的熵对比 ==========
print("\n" + "=" * 60)
print("不同概率分布的熵对比")
print("=" * 60)
# 1. 公平硬币:均匀分布
dist_fair_coin = np.array([0.5, 0.5])
H_fair = entropy(dist_fair_coin)
print(f"\n1. 公平硬币 P=[0.5, 0.5]")
print(f" 熵 H(X) = {H_fair:.4f} bits (理论最大值 = log2(2) = 1)")
# 2. 偏置硬币:非均匀分布
dist_biased_coin = np.array([0.9, 0.1])
H_biased = entropy(dist_biased_coin)
print(f"\n2. 偏置硬币 P=[0.9, 0.1]")
print(f" 熵 H(X) = {H_biased:.4f} bits (比均匀分布减少了 {H_fair - H_biased:.4f} bits)")
# 3. 六面骰子:均匀分布
dist_fair_die = np.array([1/6]*6)
H_die = entropy(dist_fair_die)
print(f"\n3. 公平六面骰子 P=[1/6, ..., 1/6]")
print(f" 熵 H(X) = {H_die:.4f} bits (理论最大值 = log2(6) = {math.log2(6):.4f})")
# 4. 偏置骰子:某个面概率更高
dist_biased_die = np.array([0.5, 0.1, 0.1, 0.1, 0.1, 0.1])
H_biased_die = entropy(dist_biased_die)
print(f"\n4. 偏置骰子 P=[0.5, 0.1, ..., 0.1]")
print(f" 熵 H(X) = {H_biased_die:.4f} bits (比均匀分布减少了 {H_die - H_biased_die:.4f} bits)")
# 5. 确定性分布:无不确定性
dist_deterministic = np.array([1.0, 0.0, 0.0])
H_det = entropy(dist_deterministic)
print(f"\n5. 确定性分布 P=[1.0, 0.0, 0.0]")
print(f" 熵 H(X) = {H_det:.4f} bits (完全没有不确定性)")
# ========== 密码学中的熵:密钥空间分析 ==========
print("\n" + "=" * 60)
print("密码学中的密钥熵分析")
print("=" * 60)
key_scenarios = [
("4位数字PIN码", 10**4, "容易被暴力破解"),
("8位小写字母密码", 26**8, "中等安全性"),
("12位字母数字混合", 62**12, "较高安全性"),
("128位对称密钥 (AES-128)", 2**128, "当前标准安全级别"),
("256位对称密钥 (AES-256)", 2**256, "量子安全级别"),
]
for name, keyspace, comment in key_scenarios:
H = math.log2(keyspace)
print(f"\n{name}:")
print(f" 密钥空间大小: {keyspace:.2e}")
print(f" 熵 H(K) = {H:.2f} bits")
print(f" 安全评价: {comment}")
print("\n" + "=" * 60)
print("关键结论:熵是密钥强度的精确度量")
print("=" * 60)
print("""
熵(H)与攻击代价的关系:
- 对于均匀随机的n位密钥,H(K) = n bits
- 暴力破解平均需要 2^(n-1) 次尝试
- 安全性的黄金标准:H(K) ≥ 128 bits
""")
运行上述代码,可以看到不同分布的熵值对比结果。核心结论是:均匀分布最大化熵,这也是密码学中密钥必须均匀随机生成的理论依据——任何偏置都会降低熵,从而给攻击者带来信息优势。
8.2 联合熵、条件熵与互信息
当涉及多个随机变量时,信息论提供了一套丰富的工具来描述它们之间的关系。在密码学中,这些工具让我们能够精确量化密文泄露了多少关于明文的信息。
8.2.1 联合熵
联合熵(Joint Entropy)衡量两个随机变量共同的不确定性:
H ( X , Y ) = − ∑ x ∈ X ∑ y ∈ Y P ( x , y ) log 2 P ( x , y ) H(X, Y) = -\sum_{x \in \mathcal{X}} \sum_{y \in \mathcal{Y}} P(x, y) \log_2 P(x, y) H(X,Y)=−x∈X∑y∈Y∑P(x,y)log2P(x,y)
当 X X X 和 Y Y Y 独立时, H ( X , Y ) = H ( X ) + H ( Y ) H(X, Y) = H(X) + H(Y) H(X,Y)=H(X)+H(Y)。一般情况下, H ( X , Y ) ≤ H ( X ) + H ( Y ) H(X, Y) \leq H(X) + H(Y) H(X,Y)≤H(X)+H(Y),等号成立当且仅当独立——这是因为变量间的相关性减少了联合不确定性。
8.2.2 条件熵
条件熵(Conditional Entropy)衡量在已知一个变量的情况下,另一个变量的剩余不确定性:
H ( X ∣ Y ) = ∑ y ∈ Y P ( y ) H ( X ∣ Y = y ) = − ∑ x , y P ( x , y ) log 2 P ( x ∣ y ) H(X|Y) = \sum_{y \in \mathcal{Y}} P(y) H(X|Y=y) = -\sum_{x,y} P(x,y) \log_2 P(x|y) H(X∣Y)=y∈Y∑P(y)H(X∣Y=y)=−x,y∑P(x,y)log2P(x∣y)
条件熵满足关键的不等式 H ( X ∣ Y ) ≤ H ( X ) H(X|Y) \leq H(X) H(X∣Y)≤H(X)——知道额外信息不会增加不确定性(平均而言)。等号成立当且仅当 X X X 和 Y Y Y 独立。在密码学中, H ( M ∣ C ) H(M|C) H(M∣C) 表示攻击者看到密文后对明文的剩余不确定性。完美保密要求 H ( M ∣ C ) = H ( M ) H(M|C) = H(M) H(M∣C)=H(M),即密文完全不减少明文的不确定性。
8.2.3 互信息:信息泄露的精确度量
互信息(Mutual Information)是信息论中最重要的工具之一,它精确度量了两个变量之间共享的信息量:
I ( X ; Y ) = H ( X ) − H ( X ∣ Y ) = H ( Y ) − H ( Y ∣ X ) = H ( X ) + H ( Y ) − H ( X , Y ) I(X; Y) = H(X) - H(X|Y) = H(Y) - H(Y|X) = H(X) + H(Y) - H(X, Y) I(X;Y)=H(X)−H(X∣Y)=H(Y)−H(Y∣X)=H(X)+H(Y)−H(X,Y)
互信息满足: I ( X ; Y ) ≥ 0 I(X; Y) \geq 0 I(X;Y)≥0,等号成立当且仅当 X X X 和 Y Y Y 独立。在密码学中, I ( M ; C ) I(M; C) I(M;C) 度量了密文泄露了多少关于明文的信息——完美保密等价于 I ( M ; C ) = 0 I(M; C) = 0 I(M;C)=0。
这三个概念之间存在优美的关系,可以用以下信息论恒等式统一描述:
H ( X , Y ) ⏟ 联合不确定性 = H ( X ) ⏟ X 的不确定性 + H ( Y ∣ X ) ⏟ 已知 X 后 Y 的剩余不确定性 \underbrace{H(X, Y)}_{\text{联合不确定性}} = \underbrace{H(X)}_{X\text{的不确定性}} + \underbrace{H(Y|X)}_{\text{已知}X\text{后}Y\text{的剩余不确定性}} 联合不确定性 H(X,Y)=X的不确定性 H(X)+已知X后Y的剩余不确定性 H(Y∣X)
8.2.4 Python实现:联合熵、条件熵与互信息
"""
联合熵、条件熵与互信息的计算
演示信息论在密码学分析中的应用
"""
import numpy as np
# ========== 基础函数扩展 ==========
def entropy(prob_dist):
"""计算Shannon熵"""
prob_dist = np.array(prob_dist).flatten()
prob_dist = prob_dist[prob_dist > 0]
return -np.sum(prob_dist * np.log2(prob_dist))
def joint_entropy(joint_prob):
"""计算联合熵 H(X,Y)
参数: joint_prob - 联合概率矩阵 P[X][Y]
"""
joint_prob = np.array(joint_prob)
flat = joint_prob.flatten()
flat = flat[flat > 0]
return -np.sum(flat * np.log2(flat))
def conditional_entropy(joint_prob, axis=0):
"""计算条件熵 H(X|Y) 或 H(Y|X)
axis=0: 计算 H(X|Y),即已知Y时X的条件熵
axis=1: 计算 H(Y|X),即已知X时Y的条件熵
"""
joint_prob = np.array(joint_prob, dtype=float)
if axis == 0:
# H(X|Y): 对每个Y值计算H(X|Y=y),再按P(y)加权
marginal_y = np.sum(joint_prob, axis=0)
cond_ent = 0.0
for y in range(joint_prob.shape[1]):
if marginal_y[y] > 0:
cond_dist = joint_prob[:, y] / marginal_y[y]
cond_dist = cond_dist[cond_dist > 0]
h_cond = -np.sum(cond_dist * np.log2(cond_dist))
cond_ent += marginal_y[y] * h_cond
return cond_ent
else:
# H(Y|X)
marginal_x = np.sum(joint_prob, axis=1)
cond_ent = 0.0
for x in range(joint_prob.shape[0]):
if marginal_x[x] > 0:
cond_dist = joint_prob[x, :] / marginal_x[x]
cond_dist = cond_dist[cond_dist > 0]
h_cond = -np.sum(cond_dist * np.log2(cond_dist))
cond_ent += marginal_x[x] * h_cond
return cond_ent
def mutual_information(joint_prob):
"""计算互信息 I(X;Y) = H(X) - H(X|Y)"""
marginal_x = np.sum(joint_prob, axis=1)
marginal_y = np.sum(joint_prob, axis=0)
H_X = entropy(marginal_x)
H_Y = entropy(marginal_y)
H_XY = joint_entropy(joint_prob)
I_XY = H_X + H_Y - H_XY
return I_XY
# ========== 示例1:完全独立的变量(理想加密的目标) ==========
print("=" * 60)
print("示例1:完全独立的随机变量")
print("=" * 60)
# 独立联合分布: P(X,Y) = P(X) * P(Y)
P_X = np.array([0.5, 0.5]) # 公平硬币
P_Y = np.array([0.5, 0.5]) # 公平硬币
joint_independent = np.outer(P_X, P_Y)
print(f"联合概率矩阵 P(X,Y):")
print(joint_independent)
H_X = entropy(P_X)
H_Y = entropy(P_Y)
H_XY = joint_entropy(joint_independent)
H_X_given_Y = conditional_entropy(joint_independent, axis=0)
I_XY = mutual_information(joint_independent)
print(f"\nH(X) = {H_X:.4f} bits")
print(f"H(Y) = {H_Y:.4f} bits")
print(f"H(X,Y) = {H_XY:.4f} bits")
print(f"H(X|Y) = {H_X_given_Y:.4f} bits")
print(f"I(X;Y) = {I_XY:.4f} bits")
print(f"\n验证: H(X) + H(Y) = {H_X + H_Y:.4f} = H(X,Y) -> 独立变量")
print(f"验证: I(X;Y) = 0 -> 没有共享信息")
# ========== 示例2:完全相关的变量(完全不安全的加密) ==========
print("\n" + "=" * 60)
print("示例2:完全相关的随机变量")
print("=" * 60)
# 完全相关: X 永远等于 Y
joint_perfect_corr = np.array([
[0.5, 0.0],
[0.0, 0.5]
])
print(f"联合概率矩阵 P(X,Y):")
print(joint_perfect_corr)
H_X2 = entropy(np.sum(joint_perfect_corr, axis=1))
H_Y2 = entropy(np.sum(joint_perfect_corr, axis=0))
H_XY2 = joint_entropy(joint_perfect_corr)
H_X_given_Y2 = conditional_entropy(joint_perfect_corr, axis=0)
I_XY2 = mutual_information(joint_perfect_corr)
print(f"\nH(X) = {H_X2:.4f} bits")
print(f"H(Y) = {H_Y2:.4f} bits")
print(f"H(X,Y) = {H_XY2:.4f} bits")
print(f"H(X|Y) = {H_X_given_Y2:.4f} bits")
print(f"I(X;Y) = {I_XY2:.4f} bits")
print(f"\n验证: H(X|Y) = 0 -> 已知Y后X完全确定")
print(f"验证: I(X;Y) = H(X) = {H_X2:.4f} -> 完全信息共享")
# ========== 示例3:密码学场景 - 凯撒密码的泄露分析 ==========
print("\n" + "=" * 60)
print("示例3:凯撒密码的信息泄露分析")
print("=" * 60)
# 假设明文M是26个字母,密文C也是26个字母
# 凯撒密码: C = (M + K) mod 26,K固定(比如K=3)
# 这种情况下,M和C是一一对应的
# 假设明文均匀分布
P_M = np.ones(26) / 26
# 凯撒密码的密文也是均匀分布(因为明文均匀)
# 但M和C完全相关:知道C就能确定M
joint_caesar = np.zeros((26, 26))
shift = 3
for m in range(26):
c = (m + shift) % 26
joint_caesar[m, c] = 1/26
H_M = entropy(P_M)
H_C = entropy(np.sum(joint_caesar, axis=0))
H_M_given_C = conditional_entropy(joint_caesar, axis=0)
I_MC = mutual_information(joint_caesar)
print(f"凯撒密码(固定密钥,明文均匀分布):")
print(f"H(M) = {H_M:.4f} bits (明文的不确定性)")
print(f"H(C) = {H_C:.4f} bits (密文的不确定性)")
print(f"H(M|C) = {H_M_given_C:.4f} bits (看到密文后明文的剩余不确定性)")
print(f"I(M;C) = {I_MC:.4f} bits (密文泄露的信息量)")
print(f"\n结论: I(M;C) = H(M) = {H_M:.4f} bits")
print("密文泄露了关于明文的全部信息!凯撒密码完全不安全。")
# ========== 信息论量之间的关系总结 ==========
print("\n" + "=" * 60)
print("信息论恒等式验证")
print("=" * 60)
print(f"\n对于凯撒密码示例:")
print(f"I(M;C) = H(M) - H(M|C) = {H_M:.4f} - {H_M_given_C:.4f} = {H_M - H_M_given_C:.4f}")
print(f"I(M;C) = H(M) + H(C) - H(M,C) = {H_M:.4f} + {H_C:.4f} - {joint_entropy(joint_caesar):.4f} = {I_MC:.4f}")
print(f"\n所有恒等式验证通过!")
8.2.5 信息论核心概念关系图
以下图表展示了信息论中核心概念之间的数学关系,以及它们在密码学分析中的应用路径:
上图清晰地展示了从信息论基本概念到密码学安全性分析的逻辑链条。自信息和熵构成了信息度量的基础,联合熵、条件熵和互信息则将这一框架扩展到多个变量。在密码学中,互信息 I ( M ; C ) I(M; C) I(M;C) 成为衡量加密方案安全性的核心指标——它精确量化了密文泄露了多少关于明文的信息。当 I ( M ; C ) = 0 I(M; C) = 0 I(M;C)=0 时达到完美保密,但Shannon定理告诉我们这要求密钥不小于消息。计算安全通过限制攻击者能力,在保持实用性的同时实现了可证明的安全性。
8.3 信道容量与噪声信道编码定理
8.3.1 通信系统的数学模型
信息论不仅服务于密码学,它也是整个现代通信理论的基石。Shannon将通信系统抽象为一个数学模型:信源产生消息,编码器将消息转换为适合信道传输的信号,信道可能引入噪声,解码器从受噪声影响的信号中恢复原始消息。这个模型虽然简单,却蕴含着深刻的洞见。
8.3.2 信道容量
信道容量(Channel Capacity)是信息论中最重要的概念之一,它定义了信道能够可靠传输信息的最大速率。对于一个离散无记忆信道,容量定义为:
C = max P ( X ) I ( X ; Y ) C = \max_{P(X)} I(X; Y) C=P(X)maxI(X;Y)
即在所有可能的输入分布中,使输入和输出之间互信息最大化的那个值。信道容量的单位是比特每信道使用(bits/channel use)。
著名的二进制对称信道(BSC)的容量为 C = 1 − H b ( p ) C = 1 - H_b(p) C=1−Hb(p),其中 p p p 是比特翻转概率, H b H_b Hb 是二元熵函数。当 p = 0 p = 0 p=0(无噪声)时, C = 1 C = 1 C=1;当 p = 0.5 p = 0.5 p=0.5(完全噪声)时, C = 0 C = 0 C=0。
8.3.3 噪声信道编码定理
Shannon第二定理(噪声信道编码定理)是信息论的顶峰成果之一。它指出:对于任何速率 R < C R < C R<C,存在编码方案使得信息可以以速率 R R R 可靠传输,且错误概率可以任意小;反之,如果 R > C R > C R>C,则可靠传输是不可能的。
这一定理在密码学中有深刻的启示:攻击者面对密文时,相当于通过一个"信道"接收信息。完美保密要求这个信道的容量为零——即密文到明文的信息传输速率为零。
8.4 完美保密的Shannon定义
8.4.1 信息论安全性的诞生
在Shannon之前,"不可破解"是一个模糊的概念。密码学家们依靠经验和直觉来判断一个密码系统是否安全,但缺乏严格的数学定义。Shannon的划时代贡献在于,他用信息论的工具给出了"完美保密"的精确数学定义——这是人类历史上第一次用数学语言严格表述"不可破解"的含义。
8.4.2 完美保密的数学定义
一个加密方案 ( Gen , Enc , Dec ) (\text{Gen}, \text{Enc}, \text{Dec}) (Gen,Enc,Dec) 满足完美保密(Perfect Secrecy),当且仅当对所有明文 m ∈ M m \in \mathcal{M} m∈M 和所有密文 c ∈ C c \in \mathcal{C} c∈C(其中 P ( C = c ) > 0 P(C = c) > 0 P(C=c)>0):
P ( M = m ∣ C = c ) = P ( M = m ) P(M = m | C = c) = P(M = m) P(M=m∣C=c)=P(M=m)
这个等式的含义极其深刻:观察到密文 c c c 之后,攻击者对明文 m m m 的后验概率与先验概率完全相同。换言之,密文没有提供关于明文的任何信息——无论攻击者拥有多强的计算能力、使用多聪明的算法,密文对于破解都毫无用处。
完美保密有几个重要的等价表述:
- 信息论表述: H ( M ∣ C ) = H ( M ) H(M|C) = H(M) H(M∣C)=H(M),即 I ( M ; C ) = 0 I(M; C) = 0 I(M;C)=0
- 分布独立性表述:对所有 m 0 , m 1 ∈ M m_0, m_1 \in \mathcal{M} m0,m1∈M 和所有 c ∈ C c \in \mathcal{C} c∈C: P ( Enc ( K , m 0 ) = c ) = P ( Enc ( K , m 1 ) = c ) P(\text{Enc}(K, m_0) = c) = P(\text{Enc}(K, m_1) = c) P(Enc(K,m0)=c)=P(Enc(K,m1)=c)
- 不可区分性表述:对于任意两条等长消息 m 0 m_0 m0 和 m 1 m_1 m1,加密 m 0 m_0 m0 得到的密文分布与加密 m 1 m_1 m1 得到的密文分布完全相同
这些等价表述从不同角度揭示了同一本质:密文与明文统计独立。
8.4.3 为何完美保密是最强的安全定义
完美保密之所以是最强的保密定义,原因在于它对攻击者没有施加任何计算限制。无论攻击者是一台笔记本电脑、一个超级计算机集群,还是一台具有无限计算能力的机器,完美保密的方案对他们都同样安全。这种安全性完全来自信息论本身——密文中根本不包含关于明文的信息,无论你如何处理密文,都无法从中"榨取"出任何关于明文的知识。
这与计算安全形成了鲜明对比:计算安全的方案在数学上是可以被破解的,只是破解所需的计算量超出了任何实际攻击者的能力。
8.5 一次一密:唯一的完美保密系统
8.5.1 Vernam密码的诞生
一次一密(One-Time Pad, OTP)由Gilbert Vernam在1917年发明,是一种极其简单的加密方法。它使用与明文等长的随机密钥,通过逐比特异或(XOR)操作进行加密:
c i = m i ⊕ k i c_i = m_i \oplus k_i ci=mi⊕ki
解密过程与加密完全相同(异或的自逆性):
m i = c i ⊕ k i m_i = c_i \oplus k_i mi=ci⊕ki
一次一密有三个严格的要求:密钥必须真正随机、密钥长度必须与明文等长、密钥绝不能重复使用。前两个要求保证了安全性,第三个要求确保了即使攻击者截获多条密文,也无法通过比较来推断密钥信息。
8.5.2 Shannon的完美保密证明
定理:一次一密满足完美保密。
证明:设密钥 K K K 是在 { 0 , 1 } n \{0, 1\}^n {0,1}n 上均匀随机选取的 n n n 比特串。对于任意明文 m ∈ { 0 , 1 } n m \in \{0, 1\}^n m∈{0,1}n 和任意密文 c ∈ { 0 , 1 } n c \in \{0, 1\}^n c∈{0,1}n:
P ( C = c ∣ M = m ) = P ( K = m ⊕ c ) = 1 2 n P(C = c | M = m) = P(K = m \oplus c) = \frac{1}{2^n} P(C=c∣M=m)=P(K=m⊕c)=2n1
由于密钥均匀随机, K K K 取任何特定值的概率都是 2 − n 2^{-n} 2−n,与 m m m 的选择无关。根据贝叶斯定理:
P ( M = m ∣ C = c ) = P ( C = c ∣ M = m ) ⋅ P ( M = m ) P ( C = c ) P(M = m | C = c) = \frac{P(C = c | M = m) \cdot P(M = m)}{P(C = c)} P(M=m∣C=c)=P(C=c)P(C=c∣M=m)⋅P(M=m)
由于 P ( C = c ∣ M = m ) = 2 − n P(C = c | M = m) = 2^{-n} P(C=c∣M=m)=2−n 对所有 m m m 成立,且:
P ( C = c ) = ∑ m ′ ∈ M P ( C = c ∣ M = m ′ ) ⋅ P ( M = m ′ ) = 2 − n ∑ m ′ P ( M = m ′ ) = 2 − n P(C = c) = \sum_{m' \in \mathcal{M}} P(C = c | M = m') \cdot P(M = m') = 2^{-n} \sum_{m'} P(M = m') = 2^{-n} P(C=c)=m′∈M∑P(C=c∣M=m′)⋅P(M=m′)=2−nm′∑P(M=m′)=2−n
因此:
P ( M = m ∣ C = c ) = 2 − n ⋅ P ( M = m ) 2 − n = P ( M = m ) P(M = m | C = c) = \frac{2^{-n} \cdot P(M = m)}{2^{-n}} = P(M = m) P(M=m∣C=c)=2−n2−n⋅P(M=m)=P(M=m)
这正是完美保密的定义。证毕。
这个证明虽然简短,但揭示了一次一密安全性的根本原因:对于每一个密文 c c c,明文空间中的每一条消息 m m m 都恰好对应唯一的一个密钥 k = m ⊕ c k = m \oplus c k=m⊕c,而这些密钥的概率都相等。因此,密文 c c c 与所有明文都"同样兼容",攻击者无法排除任何可能性。
8.5.3 Python实现:一次一密与完美保密验证
"""
一次一密(One-Time Pad)的实现与完美保密验证
通过统计分析验证OTP满足完美保密
"""
import numpy as np
import random
from collections import Counter, defaultdict
class OneTimePad:
"""一次一密加密系统实现"""
@staticmethod
def generate_key(length):
"""生成真正随机的n位密钥"""
return ''.join(str(random.randint(0, 1)) for _ in range(length))
@staticmethod
def encrypt(plaintext, key):
"""加密:逐比特异或"""
if len(plaintext) != len(key):
raise ValueError("密钥长度必须与明文等长")
return ''.join('1' if p != k else '0' for p, k in zip(plaintext, key))
@staticmethod
def decrypt(ciphertext, key):
"""解密:与加密相同(异或的自逆性)"""
return OneTimePad.encrypt(ciphertext, key) # 异或是自逆运算
# ========== 基本加解密演示 ==========
print("=" * 60)
print("一次一密基本演示")
print("=" * 60)
otp = OneTimePad()
message = "10110011"
key = otp.generate_key(len(message))
ciphertext = otp.encrypt(message, key)
decrypted = otp.decrypt(ciphertext, key)
print(f"明文: {message}")
print(f"密钥: {key}")
print(f"密文: {ciphertext}")
print(f"解密结果: {decrypted}")
print(f"解密正确: {decrypted == message}")
# ========== 完美保密性统计验证 ==========
print("\n" + "=" * 60)
print("完美保密的统计验证")
print("=" * 60)
def verify_perfect_secrecy(num_trials=10000, msg_len=4):
"""
通过大量实验验证OTP满足完美保密。
核心思想:对于固定密文,统计它是由哪些明文产生的频率,
验证所有明文产生该密文的概率相等。
"""
otp = OneTimePad()
# 固定两条不同的明文
m0 = "0" * msg_len
m1 = "1" * msg_len
# 统计每个密文出现的次数
# ciphertext_counts[c] = {m0: count, m1: count}
ciphertext_counts = defaultdict(lambda: Counter())
all_ciphertexts = []
for trial in range(num_trials):
# 随机选择明文(50%概率选m0或m1)
m = random.choice([m0, m1])
# 生成随机密钥
k = otp.generate_key(msg_len)
# 加密
c = otp.encrypt(m, k)
ciphertext_counts[c][m] += 1
all_ciphertexts.append((m, k, c))
# 分析结果
print(f"\n实验参数: 消息长度={msg_len}, 实验次数={num_trials}")
print(f"选择明文: m0={m0}, m1={m1}")
# 检查几个代表性的密文
all_ciphertext_list = list(ciphertext_counts.keys())
# 统计密文分布
print(f"\n观察到 {len(all_ciphertext_list)} 种不同的密文")
print(f"理论密文空间大小: 2^{msg_len} = {2**msg_len}")
# 验证:对于任意密文c,P(c|m0) ≈ P(c|m1)
print(f"\n{'密文':<10} {'m0产生次数':<12} {'m1产生次数':<12} {'比率m0/m1':<12}")
print("-" * 50)
mismatches = 0
for c in sorted(all_ciphertext_list)[:10]: # 显示前10个
count_m0 = ciphertext_counts[c][m0]
count_m1 = ciphertext_counts[c][m1]
ratio = count_m0 / count_m1 if count_m1 > 0 else float('inf')
print(f"{c:<10} {count_m0:<12} {count_m1:<12} {ratio:<12.3f}")
# 如果比率显著偏离1,则记录不匹配
if abs(ratio - 1.0) > 0.3:
mismatches += 1
# 卡方检验:验证密文分布的独立性
print(f"\n统计检验: 显著偏离1.0的比率数量 = {mismatches}")
print(f"完美保密验证结果: {'通过' if mismatches == 0 else '需要更多样本'}")
verify_perfect_secrecy(num_trials=20000, msg_len=4)
# ========== 密钥重用攻击演示 ==========
print("\n" + "=" * 60)
print("密钥重用的致命后果")
print("=" * 60)
def demonstrate_key_reuse():
"""
演示为什么OTP要求密钥绝不能重用。
如果 c1 = m1 ⊕ k, c2 = m2 ⊕ k
则 c1 ⊕ c2 = m1 ⊕ m2(密钥被消去!)
"""
otp = OneTimePad()
msg_len = 16
# 两条明文
m1 = "1100110011001100"
m2 = "1010101010101010"
# 同一条密钥(错误用法!)
k = otp.generate_key(msg_len)
c1 = otp.encrypt(m1, k)
c2 = otp.encrypt(m2, k)
# 攻击:异或两个密文
c1_xor_c2 = otp.encrypt(c1, c2)
m1_xor_m2 = otp.encrypt(m1, m2)
print(f"明文1: {m1}")
print(f"明文2: {m2}")
print(f"密钥: {k}")
print(f"密文1: {c1}")
print(f"密文2: {c2}")
print(f"\n攻击: c1 ⊕ c2 = {c1_xor_c2}")
print(f"验证: m1 ⊕ m2 = {m1_xor_m2}")
print(f"密钥被消去: {c1_xor_c2 == m1_xor_m2}")
print("\n攻击者获得 m1 ⊕ m2 后,可以利用明文统计特性恢复原文!")
print("这是二战中'Venona计划'破解苏联密码的实际方法。")
demonstrate_key_reuse()
# ========== 熵函数定义 ==========
def entropy(p):
"""计算香农熵 H(P) = -Σ p(x) * log2(p(x))"""
p = p[p > 0] # 过滤掉0概率,避免log(0)
return -np.sum(p * np.log2(p))
def joint_entropy(joint):
"""计算联合熵 H(X,Y) = -Σ p(x,y) * log2(p(x,y))"""
joint = joint[joint > 0] # 过滤掉0概率
return -np.sum(joint * np.log2(joint))
# ========== OTP与确定性加密的熵对比 ==========
print("\n" + "=" * 60)
print("OTP与确定性加密的互信息对比")
print("=" * 60)
def compute_mi_otp_vs_deterministic():
"""对比OTP和确定性加密方案的互信息 I(M;C)"""
# 简化为2位消息空间
# M = {00, 01, 10, 11},均匀分布
num_messages = 4
num_keys = 4 # OTP需要4个密钥
# OTP的联合分布 P(M,C)
# 对于OTP,每个(m,c)对对应恰好一个密钥
joint_otp = np.zeros((num_messages, num_messages))
for m in range(num_messages):
for k in range(num_keys):
c = m ^ k # XOR加密
joint_otp[m, c] += (1/num_messages) * (1/num_keys)
# 确定性加密(固定密钥,比如k=0)的联合分布
joint_det = np.zeros((num_messages, num_messages))
k_fixed = 0
for m in range(num_messages):
c = m ^ k_fixed
joint_det[m, c] = 1/num_messages
# 计算互信息
def mi(joint):
marginal_m = np.sum(joint, axis=1)
marginal_c = np.sum(joint, axis=0)
H_M = entropy(marginal_m)
H_C = entropy(marginal_c)
H_MC = joint_entropy(joint)
return H_M + H_C - H_MC, H_M, H_C, H_MC
mi_otp, H_m_otp, H_c_otp, H_mc_otp = mi(joint_otp)
mi_det, H_m_det, H_c_det, H_mc_det = mi(joint_det)
print(f"\nOTP (随机密钥):")
print(f" H(M) = {H_m_otp:.4f}, H(C) = {H_c_otp:.4f}")
print(f" H(M,C) = {H_mc_otp:.4f}")
print(f" I(M;C) = {mi_otp:.4f} bits (完美保密要求 = 0)")
print(f"\n确定性加密 (固定密钥):")
print(f" H(M) = {H_m_det:.4f}, H(C) = {H_c_det:.4f}")
print(f" H(M,C) = {H_mc_det:.4f}")
print(f" I(M;C) = {mi_det:.4f} bits (泄露了全部信息)")
compute_mi_otp_vs_deterministic()
print("\n" + "=" * 60)
print("结论:OTP是唯一满足 I(M;C) = 0 的加密方案")
print("=" * 60)
8.6 Shannon定理:完美保密的代价
8.6.1 密钥必须不小于消息长度
一次一密虽然完美,但存在一个致命的实际缺陷:密钥必须与明文等长。这并非偶然,而是信息论的基本限制。Shannon证明了一个深刻的定理:
Shannon定理(关于完美保密):如果一个加密方案 ( Gen , Enc , Dec ) (\text{Gen}, \text{Enc}, \text{Dec}) (Gen,Enc,Dec) 满足完美保密,则密钥空间的大小必须满足 ∣ K ∣ ≥ ∣ M ∣ |\mathcal{K}| \geq |\mathcal{M}| ∣K∣≥∣M∣,即密钥空间至少与明文空间一样大。等价地,密钥的长度至少与明文的长度相同。
证明思路:假设 ∣ K ∣ < ∣ M ∣ |\mathcal{K}| < |\mathcal{M}| ∣K∣<∣M∣,推出矛盾。考虑一个密文 c c c 使得 P ( C = c ) > 0 P(C = c) > 0 P(C=c)>0。令 M ( c ) \mathcal{M}(c) M(c) 为所有可能通过某个密钥解密 c c c 得到的明文集合:
M ( c ) = { Dec ( k , c ) : k ∈ K } \mathcal{M}(c) = \{ \text{Dec}(k, c) : k \in \mathcal{K} \} M(c)={Dec(k,c):k∈K}
由于每个密钥最多产生一个解密结果, ∣ M ( c ) ∣ ≤ ∣ K ∣ < ∣ M ∣ |\mathcal{M}(c)| \leq |\mathcal{K}| < |\mathcal{M}| ∣M(c)∣≤∣K∣<∣M∣。因此存在某个明文 m ′ ∈ M m' \in \mathcal{M} m′∈M 使得 m ′ ∉ M ( c ) m' \notin \mathcal{M}(c) m′∈/M(c)——没有任何密钥能将 c c c 解密为 m ′ m' m′。这意味着 P ( M = m ′ ∣ C = c ) = 0 P(M = m' | C = c) = 0 P(M=m′∣C=c)=0,但如果 P ( M = m ′ ) > 0 P(M = m') > 0 P(M=m′)>0,我们有 P ( M = m ′ ∣ C = c ) = 0 ≠ P ( M = m ′ ) > 0 P(M = m' | C = c) = 0 \neq P(M = m') > 0 P(M=m′∣C=c)=0=P(M=m′)>0,这违反了完美保密的定义。
这个定理的结论是无可回避的:完美保密要求密钥至少与消息等长。这从根本上宣告了信息论安全在实践中的不可行性——如果 Alice 和 Bob 能够安全地传输与明文等长的密钥,他们何不直接安全地传输明文本身?
8.7 从完美保密到计算安全:现代密码学的桥梁
8.7.1 完美保密的实践困境
完美保密虽然是安全的终极标准,但在实际应用中面临不可克服的困难:
- 密钥分发问题:密钥必须与消息等长,且必须预先安全地共享
- 密钥管理问题:每个消息都需要唯一的密钥,导致密钥数量爆炸
- 实用性问题:加密1GB文件需要1GB的预共享密钥
这些限制意味着,对于大规模通信系统(如互联网),完美保密是不可行的。但这并不意味着我们要放弃安全性,而是需要重新定义安全性的含义。
8.7.2 语义安全:实际的安全定义
1970年代,Shafi Goldwasser和Silvio Micali提出了语义安全(Semantic Security)的概念,开创了现代密码学的新纪元。语义安全的核心思想是:
定义:一个加密方案是语义安全的,如果对于任何概率多项式时间(PPT)攻击者,从密文中计算出关于明文的任何"有意义"信息的概率,与不从密文中获取该信息的概率相比,差异可以忽略不计。
语义安全与完美保密的关键区别在于:
- 完美保密:没有任何攻击者(即使拥有无限计算能力)能从密文中获得信息
- 语义安全:没有高效的攻击者(限制为概率多项式时间)能从密文中获得信息
这个看似微小的放宽,却彻底改变了密码学的面貌。它允许我们使用短密钥加密长消息,因为安全性基于计算困难性假设(如因数分解、离散对数的困难性),而非信息论的严格限制。
8.7.3 IND-CPA安全性定义
IND-CPA(Indistinguishability under Chosen-Plaintext Attack)是语义安全的形式化等价定义,也是现代加密方案的黄金安全标准。
IND-CPA安全性通过一个挑战实验来定义:
- 挑战者生成密钥 k ← Gen ( 1 n ) k \leftarrow \text{Gen}(1^n) k←Gen(1n)
- 攻击者 A \mathcal{A} A 可以自适应地提交任意消息对 ( m 0 , m 1 ) (m_0, m_1) (m0,m1) 给加密预言机,获得 Enc ( k , m b ) \text{Enc}(k, m_b) Enc(k,mb)(其中 b b b 随机选择)
- 攻击者最终输出猜测 b ′ ∈ { 0 , 1 } b' \in \{0, 1\} b′∈{0,1}
- 方案是IND-CPA安全的,如果对于所有PPT攻击者:
∣ Pr [ b ′ = b ] − 1 2 ∣ ≤ negl ( n ) \left| \Pr[b' = b] - \frac{1}{2} \right| \leq \text{negl}(n) Pr[b′=b]−21 ≤negl(n)
其中 negl ( n ) \text{negl}(n) negl(n) 是可忽略函数——对于任何多项式 p ( n ) p(n) p(n),存在 N N N 使得对所有 n > N n > N n>N, negl ( n ) < 1 / p ( n ) \text{negl}(n) < 1/p(n) negl(n)<1/p(n)。
IND-CPA安全性的直观含义是:即使攻击者可以选择任意两条消息并看到其中一条的密文,也无法以显著优于随机猜测的概率判断是哪一条。这确保了密文不泄露任何可用于区分不同明文的信息。
8.8 安全性定义的层次关系
信息论安全和计算安全构成了密码学安全性定义的两座里程碑。在深入对比之前,我们先通过层次模型来理解各种安全定义之间的关系:
上图从三个维度展现了密码学安全性的全景:攻击者能力层次(从左到右逐渐增强)、安全性定义层次(从上到下逐渐弱化对密钥的要求),以及实际加密方案映射(从理论到实践)。虚线箭头表示"该攻击模型下可证明达到该安全级别"。值得注意的是,完美保密虽然位于安全性金字塔的顶端,但它对应的实际方案(OTP)因密钥管理问题几乎不可实用。现代密码学的智慧在于将安全性从信息论层面"下放"到计算层面,从而用可管理的密钥长度实现实际可部署的安全系统。
下表系统对比了各种安全定义的异同:
| 安全定义 | 攻击者能力 | 安全保证 | 密钥要求 | 典型方案 | 实践可行性 |
|---|---|---|---|---|---|
| 完美保密 | 无限计算能力 | I ( M ; C ) = 0 I(M;C) = 0 I(M;C)=0,信息论意义绝对安全 | ∣ K ∣ ≥ ∣ M ∣ |\mathcal{K}| \geq |\mathcal{M}| ∣K∣≥∣M∣ | 一次一密(OTP) | 极低,仅限特殊场景 |
| 语义安全 | 概率多项式时间(PPT) | 密文不泄露明文的"语义"信息 | 密钥长度独立于消息长度 | 公钥加密方案 | 高,理论安全 |
| IND-CPA | PPT + 选择明文攻击 | 无法区分两条消息的加密 | 同上 | AES-CBC, RSA-OAEP | 高,标准安全级别 |
| IND-CCA2 | PPT + 自适应选择密文攻击 | 即使可解密任意密文(除挑战外)也无法破解 | 同上 | AES-GCM, RSA-OAEP | 高,强安全级别 |
| 计算安全 | 所有已知算法 | 破解需要超多项式时间 | 依赖于困难问题假设 | AES, RSA, ECC | 极高,实际标准 |
上表清晰地展示了从信息论安全到计算安全的演进脉络。完美保密虽然提供了终极安全保证,但其对密钥的苛刻要求使其在实践中几乎不可行。计算安全通过限制攻击者的计算能力,实现了用短密钥保护长消息的目标,这是现代密码学得以支撑整个数字世界的根本原因。
8.9 唯密文攻击的熵分析
8.9.1 攻击者的信息视角
在唯密文攻击(Ciphertext-Only Attack, COA)模型中,攻击者只能观察到密文。从信息论的角度分析,攻击者的不确定性可以用熵来精确度量。
攻击前,攻击者对明文的先验不确定性为 H ( M ) H(M) H(M)。攻击后,攻击者观察到密文 c c c,其后验不确定性为 H ( M ∣ C = c ) H(M|C=c) H(M∣C=c)。攻击者获得的信息量为:
信息增益 = H ( M ) − H ( M ∣ C = c ) \text{信息增益} = H(M) - H(M|C=c) 信息增益=H(M)−H(M∣C=c)
对于完美保密的方案, H ( M ∣ C ) = H ( M ) H(M|C) = H(M) H(M∣C)=H(M),信息增益为零。对于不安全的方案(如凯撒密码), H ( M ∣ C ) ≈ 0 H(M|C) \approx 0 H(M∣C)≈0,信息增益接近 H ( M ) H(M) H(M),意味着密文泄露了几乎全部信息。
8.9.2 Python实现:唯密文攻击的熵分析
"""
唯密文攻击的信息论分析
对比不同加密方案在唯密文攻击下的信息泄露
"""
import numpy as np
from collections import Counter
def entropy(prob_dist):
"""计算Shannon熵"""
prob_dist = np.array(prob_dist).flatten()
prob_dist = prob_dist[prob_dist > 0]
return -np.sum(prob_dist * np.log2(prob_dist))
def joint_entropy(joint_prob):
"""计算联合熵"""
flat = np.array(joint_prob).flatten()
flat = flat[flat > 0]
return -np.sum(flat * np.log2(flat))
def conditional_entropy(joint_prob, axis=0):
"""计算条件熵 H(X|Y)"""
joint_prob = np.array(joint_prob, dtype=float)
if axis == 0:
marginal = np.sum(joint_prob, axis=axis)
cond_ent = 0.0
for i in range(joint_prob.shape[1]):
if marginal[i] > 0:
cond_dist = joint_prob[:, i] / marginal[i]
cond_dist = cond_dist[cond_dist > 0]
h = -np.sum(cond_dist * np.log2(cond_dist))
cond_ent += marginal[i] * h
return cond_ent
else:
marginal = np.sum(joint_prob, axis=axis)
cond_ent = 0.0
for i in range(joint_prob.shape[0]):
if marginal[i] > 0:
cond_dist = joint_prob[i, :] / marginal[i]
cond_dist = cond_dist[cond_dist > 0]
h = -np.sum(cond_dist * np.log2(cond_dist))
cond_ent += marginal[i] * h
return cond_ent
def mutual_information(joint_prob):
"""计算互信息"""
H_X = entropy(np.sum(joint_prob, axis=1))
H_Y = entropy(np.sum(joint_prob, axis=0))
H_XY = joint_entropy(joint_prob)
return H_X + H_Y - H_XY
def analyze_cipher(cipher_name, joint_prob, msg_size):
"""统一分析一个加密方案的信息论安全性"""
print(f"\n{'='*50}")
print(f"加密方案: {cipher_name}")
print(f"{'='*50}")
joint_prob = np.array(joint_prob, dtype=float)
joint_prob = joint_prob / np.sum(joint_prob) # 归一化
# 计算各种熵
H_M = entropy(np.sum(joint_prob, axis=1))
H_C = entropy(np.sum(joint_prob, axis=0))
H_M_given_C = conditional_entropy(joint_prob, axis=0)
H_C_given_M = conditional_entropy(joint_prob, axis=1)
H_MC = joint_entropy(joint_prob)
I_MC = mutual_information(joint_prob)
print(f"明文熵 H(M) = {H_M:.4f} bits (明文的不确定性)")
print(f"密文熵 H(C) = {H_C:.4f} bits (密文的不确定性)")
print(f"条件熵 H(M|C) = {H_M_given_C:.4f} bits (看到密文后明文的剩余不确定性)")
print(f"条件熵 H(C|M) = {H_C_given_M:.4f} bits (已知明文后密文的剩余不确定性)")
print(f"联合熵 H(M,C) = {H_MC:.4f} bits")
print(f"互信息 I(M;C) = {I_MC:.4f} bits (密文泄露的明文信息量)")
# 安全性评估
info_leaked_pct = (I_MC / H_M * 100) if H_M > 0 else 0
print(f"\n安全性分析:")
print(f" 信息泄露比例: {info_leaked_pct:.1f}%")
if abs(I_MC) < 1e-10:
print(f" 安全等级: ★★★★★ 完美保密 (I(M;C) = 0)")
elif info_leaked_pct < 10:
print(f" 安全等级: ★★★★☆ 高安全性 (泄露极少)")
elif info_leaked_pct < 50:
print(f" 安全等级: ★★★☆☆ 中等安全性")
elif info_leaked_pct < 90:
print(f" 安全等级: ★★☆☆☆ 低安全性 (泄露严重)")
else:
print(f" 安全等级: ★☆☆☆☆ 极不安全 (几乎完全泄露)")
return {
'H_M': H_M, 'H_C': H_C, 'H_M_given_C': H_M_given_C,
'H_MC': H_MC, 'I_MC': I_MC, 'leak_pct': info_leaked_pct
}
# ========== 场景1:一次一密 (完美保密) ==========
print("=" * 60)
print("唯密文攻击下的信息论安全性对比分析")
print("=" * 60)
# 2位消息空间,OTP
# 消息: 00, 01, 10, 11 (均匀分布)
# 密钥: 00, 01, 10, 11 (均匀分布)
# C = M XOR K
joint_otp = np.zeros((4, 4))
for m in range(4):
for k in range(4):
c = m ^ k
joint_otp[m, c] += 1/16 # P(M=m)*P(K=k) = (1/4)*(1/4)
stats_otp = analyze_cipher("一次一密 (OTP)", joint_otp, 2)
# ========== 场景2:确定性加密 (固定密钥 k=0) ==========
joint_det = np.zeros((4, 4))
for m in range(4):
c = m ^ 0 # 固定密钥
joint_det[m, c] = 1/4
stats_det = analyze_cipher("确定性加密 (固定密钥)", joint_det, 2)
# ========== 场景3:部分随机密钥 (密钥从{00, 11}中均匀选择) ==========
joint_partial = np.zeros((4, 4))
key_space = [0, 3] # 00和11
for m in range(4):
for k in key_space:
c = m ^ k
joint_partial[m, c] += 1/8 # P(M=m)*P(K=k) = (1/4)*(1/2)
stats_partial = analyze_cipher("部分随机加密 (密钥空间减半)", joint_partial, 2)
# ========== 场景4:凯撒密码 (模4加密的简化版) ==========
joint_caesar = np.zeros((4, 4))
shift = 1 # 固定偏移
for m in range(4):
c = (m + shift) % 4
joint_caesar[m, c] = 1/4
stats_caesar = analyze_cipher("凯撒密码 (模4, 偏移=1)", joint_caesar, 2)
# ========== 总结对比 ==========
print("\n" + "=" * 60)
print("安全性总结对比")
print("=" * 60)
print(f"\n{'加密方案':<25} {'H(M)':>8} {'H(M|C)':>10} {'I(M;C)':>10} {'泄露%':>8} {'评级':>6}")
print("-" * 65)
ciphers = [
("一次一密 (OTP)", stats_otp),
("部分随机加密", stats_partial),
("凯撒密码", stats_caesar),
("确定性加密", stats_det),
]
for name, s in ciphers:
rating = "★" * (5 - int(s['leak_pct'] / 20)) + "☆" * int(s['leak_pct'] / 20)
print(f"{name:<25} {s['H_M']:>8.4f} {s['H_M_given_C']:>10.4f} {s['I_MC']:>10.4f} {s['leak_pct']:>7.1f}% {rating:>6}")
print(f"\n关键发现:")
print(f"- OTP: I(M;C) = 0,完美保密")
print(f"- 确定性加密: I(M;C) = H(M),完全泄露")
print(f"- 部分随机: I(M;C) = H(M) - H(M|C),取决于密钥熵")
print(f"- 密钥熵越大,泄露越小:H(K)↑ → I(M;C)↓")
8.10 信息论工具集与现代密码学
8.10.1 Min-Entropy与猜测熵
除了经典的Shannon熵,现代密码学还使用其他熵的变体来衡量安全性。其中最重要的是Min-Entropy:
H ∞ ( X ) = − log 2 max x ∈ X P ( X = x ) H_{\infty}(X) = -\log_2 \max_{x \in \mathcal{X}} P(X = x) H∞(X)=−log2x∈XmaxP(X=x)
Min-Entropy度量了猜测一个随机变量最可能值所需的比特数,是衡量密钥对抗暴力破解能力的更保守估计。对于均匀分布, H ∞ ( X ) = H ( X ) H_{\infty}(X) = H(X) H∞(X)=H(X);对于非均匀分布, H ∞ ( X ) < H ( X ) H_{\infty}(X) < H(X) H∞(X)<H(X)。在密码学中,Min-Entropy比Shannon熵更适合衡量随机数生成器的质量——因为它关注的是最容易被猜到的那个值的难度。
8.10.2 从信息论到计算安全性:桥梁回顾
信息论安全与计算安全之间的桥梁可以通过以下关键步骤来理解:
- 完美保密要求 H ( K ) ≥ H ( M ) H(K) \geq H(M) H(K)≥H(M):这是信息论的基本限制
- 计算安全放宽到PPT攻击者:安全性不再要求信息论上的不可能性
- 计算不可区分性替代统计独立:密文分布只需要"看起来随机",而非真正随机
- 困难问题假设提供安全性基础:如因数分解、离散对数、格问题等
- 短密钥通过PRG扩展为长伪随机序列:流密码模拟OTP的行为
这一范式的成功在于:虽然理论上所有基于计算假设的加密都可以被破解(通过穷举或解决底层数学问题),但破解所需的时间远超宇宙的年龄,使得这种"理论可破解"在实践中毫无意义。
8.11 本章总结
本章从Shannon信息论的基础概念出发,走过了从自信息、熵到联合熵、条件熵和互信息的完整工具链。我们见证了信息论如何赋予密码学以严格的数学基础——完美保密的精确定义、一次一密的优雅证明、以及Shannon定理揭示的信息论下界。
核心结论可以概括为:
- I ( M ; C ) = 0 I(M; C) = 0 I(M;C)=0 是完美保密的等价信息论表述
- 一次一密是唯一的完美保密系统,但它要求密钥与消息等长
- Shannon定理证明了完美保密必然伴随巨大的密钥开销
- 语义安全和IND-CPA通过限制攻击者为PPT,实现了短密钥加密长消息
- 从信息论安全到计算安全的范式转换,是现代密码学得以存在的根本原因
理解这些概念之间的关系,是掌握现代密码学理论基础的必经之路。正如Shannon所展示的那样,数学的严谨性为密码学这门古老的艺术注入了科学的灵魂。
本章关键公式速查:
| 概念 | 公式 | 密码学含义 |
|---|---|---|
| 自信息 | I ( x ) = − log 2 P ( x ) I(x) = -\log_2 P(x) I(x)=−log2P(x) | 单个事件的信息量 |
| Shannon熵 | H ( X ) = − ∑ P ( x ) log 2 P ( x ) H(X) = -\sum P(x)\log_2 P(x) H(X)=−∑P(x)log2P(x) | 随机变量的平均不确定性 |
| 联合熵 | H ( X , Y ) = − ∑ ∑ P ( x , y ) log 2 P ( x , y ) H(X,Y) = -\sum\sum P(x,y)\log_2 P(x,y) H(X,Y)=−∑∑P(x,y)log2P(x,y) | 两个变量的总不确定性 |
| 条件熵 | H ( X ∣ Y ) = H ( X , Y ) − H ( Y ) H(X|Y) = H(X,Y) - H(Y) H(X∣Y)=H(X,Y)−H(Y) | 已知Y后X的剩余不确定性 |
| 互信息 | I ( X ; Y ) = H ( X ) − H ( X ∣ Y ) I(X;Y) = H(X) - H(X|Y) I(X;Y)=H(X)−H(X∣Y) | X和Y共享的信息量 |
| 完美保密 | I ( M ; C ) = 0 I(M;C) = 0 I(M;C)=0 或 H ( M ∣ C ) = H ( M ) H(M|C) = H(M) H(M∣C)=H(M) | 密文不泄露明文信息 |
| Shannon定理 | ∣ K ∣ ≥ ∣ M ∣ |\mathcal{K}| \geq |\mathcal{M}| ∣K∣≥∣M∣ | 完美保密需要长密钥 |
| IND-CPA | ∣ Pr [ b ′ = b ] − 1 / 2 ∣ ≤ negl ( n ) |\Pr[b'=b] - 1/2| \leq \text{negl}(n) ∣Pr[b′=b]−1/2∣≤negl(n) | 计算安全性定义 |
更多推荐



所有评论(0)