密码学的目标
1. 机密性(Confidentiality)
目标:保护信息不被未授权访问。
- 通过 加密(Encryption)技术确保数据只能被授权方解密和读取。
- 主要方法:
- 对称加密(AES、3DES):用于保护数据存储或高速传输。
- 非对称加密(RSA、ECC):用于安全通信和身份验证(如SSL/TLS)。
- 数据脱敏(Masking)、零知识证明(Zero-Knowledge Proofs)等技术。
2. 完整性(Integrity)
目标:确保数据未被篡改或损坏。
- 使用 哈希算法(Hashing) 生成唯一的摘要值,以检测数据篡改。
- 主要方法:
- 哈希函数(MD5、SHA-256):确保数据完整性。
- 消息认证码(MAC):如 HMAC-SHA256,验证数据完整性和真实性。
- 数字签名:结合哈希算法和公钥加密,确保数据和发送者的身份可信。
3. 可用性(Availability)
目标:确保加密数据在授权情况下仍然可以正常使用。
- 加密算法不能影响系统性能,数据在需要时必须可用。
- 主要方法:
- 密钥管理(Key Management):确保密钥安全存储和分发,避免因密钥丢失导致数据无法解密。
- 冗余和容错(Redundancy & Fault Tolerance):确保加密系统不会因单点故障而失效(如RAID、数据备份)。
- 抗拒绝服务攻击(防止 DoS/DDoS 对加密系统的影响)。
4. 真实性(Authentication)
目标:确保通信双方身份真实,防止伪造身份的攻击。
- 主要方法:
- 数字签名(Digital Signatures):使用公钥加密验证数据来源。
- PKI(公钥基础设施):通过数字证书(如 X.509 证书)验证用户身份。
- 多因素身份验证(MFA):结合密码学技术(如 OTP、FIDO2、证书认证)。
5. 抗抵赖性(Non-repudiation)
目标:防止发送者或接收者否认他们的行为。
- 主要方法:
- 数字签名:提供可靠的身份认证,防止发送者事后否认已发送的数据。
- 时间戳(Timestamping):记录交易时间,确保数据的法律效力。
- 区块链技术:去中心化的交易记录,提高数据可信度。
柯克霍夫原则(Kerckhoffs’s Principle)
柯克霍夫原则(Kerckhoffs’s Principle) 是密码学中的一个核心原则,由荷兰密码学家奥古斯特·柯克霍夫(Auguste Kerckhoffs) 在 1883 年提出。该原则的核心思想是:
“密码系统的安全性不应依赖于算法的保密性,而应仅依赖于密钥的保密性。”
柯克霍夫原则的关键要点包括:
- 加密算法可以公开:攻击者可以知道算法的具体实现,但仍无法破解消息。
- 密钥必须保密:系统的安全性应该完全依赖于密钥的机密性,而不是算法的隐秘性。
- 即使敌人掌握了整个系统(除了密钥),也无法轻易破解:换句话说,即使攻击者知道加密方法,只要密钥足够安全,攻击者仍无法解密数据。
- 系统应当是可用的:即使密钥丢失,系统仍应支持快速更换密钥,而不是整个系统报废。
Nonce(Number Once,随机数/一次性数值)
Nonce 是密码学和计算机安全领域中的一个一次性使用的随机数或计数器值,通常用于防止重放攻击、确保数据唯一性或增强加密安全性。
1. Nonce 的主要作用
Nonce 在加密系统中主要用于以下几个方面:
防止重放攻击(Replay Attack)
- 在身份验证或数据传输过程中,如果没有 Nonce,攻击者可以截取数据包并重复发送,导致安全漏洞。
- 解决方案:使用 随机 Nonce 或 递增计数器 Nonce,确保每条消息都是唯一的,防止重复攻击。
用于密码学协议
- TLS/SSL 握手:客户端和服务器在建立安全连接时,交换 Nonce 以防止旧密钥被重复使用。
- 区块链(如比特币):矿工需要找到一个合适的 Nonce,使得区块哈希满足特定条件(如比特币的 PoW 机制)。
- 加密算法(如 AES-GCM, ChaCha20-Poly1305):加密时,Nonce 确保每次加密生成不同的密文,即使明文相同。
确保随机性和唯一性
- 在加密过程中,Nonce 可以作为初始化向量(IV),确保相同的明文不会生成相同的密文,提高安全性。
- 在身份验证协议(如 Kerberos)中,Nonce 确保身份验证请求是唯一的,防止攻击者重复使用旧请求。
2. Nonce 的类型
Nonce 主要有两种类型:
类型 | 特点 | 应用场景 |
---|---|---|
随机 Nonce | 由加密安全的随机数生成器(CSPRNG)生成 | TLS、区块链、身份验证 |
计数器 Nonce | 递增的数值,确保唯一性 | AES-GCM、数据库事务 |
不同应用场景需要不同的 Nonce 生成方式。例如,在 TLS 协议中,使用的是 随机 Nonce,而 AES-GCM 加密模式通常使用 计数器 Nonce。
3. Nonce 示例
TLS/SSL 中的 Nonce
在 TLS 1.2 和 TLS 1.3 握手过程中,服务器和客户端会交换随机数(Nonce)以避免重放攻击:
Client Hello:
Nonce: 0xA1B2C3D4E5F6...
Server Hello:
Nonce: 0xF6E5D4C3B2A1...
这样,即使攻击者截获了 TLS 握手信息,无法重用相同的 Nonce 进行攻击。
零知识证明(Zero-Knowledge Proof, ZKP
零知识证明(ZKP, Zero-Knowledge Proof) 是一种密码学协议,允许证明者(Prover) 在不泄露任何秘密信息的情况下,向 验证者(Verifier) 证明自己知道某个秘密。
1. 零知识证明的特点
一个好的零知识证明协议需要满足 3 个关键特性:
-
完备性(Completeness)
- 如果证明者真的知道秘密,验证者就一定会验证通过。
-
可靠性(Soundness)
- 如果证明者不知道秘密,几乎不可能骗过验证者。
-
零知识性(Zero-Knowledge)
- 证明过程中,验证者无法获得任何关于秘密的信息,只知道证明者确实拥有这个秘密。
2. 经典的零知识证明示例
山洞问题(The Ali Baba Cave)
故事背景:
- 山洞有两个入口(A 和 B),里面有一个魔法门,只有知道魔法咒语的人才能打开。
- 佩姬(Peggy) 想向 维克多(Victor) 证明自己知道咒语,但又不想告诉维克多。
证明过程:
- 维克多站在洞外,要求佩姬随机从 A 或 B 进入山洞。
- 佩姬随便选一个入口(比如 A 进入)。
- 维克多在外面随机要求她从 A 或 B 出来。
- 如果佩姬真的知道魔法咒语,她就可以随意从任何出口出来。
- 这个过程重复多次,如果佩姬每次都成功,维克多就相信她知道咒语。
关键点:
- 维克多不会学到咒语(零知识性)。
- 如果佩姬不会咒语,她有 50% 的概率猜对出口,但多次测试后,骗过维克多的概率会接近 0(可靠性)。
3. 真实应用中的零知识证明
区块链 & 加密货币
-
ZK-SNARKs & ZK-STARKs(零知识简洁非交互式知识论证):
- Zcash 使用 ZK-SNARKs 进行匿名交易,证明交易有效但不泄露金额和发送方信息。
- Ethereum 也在使用 ZK-Rollups 扩展网络,减少计算量,提高隐私性。
身份验证(无需密码)
-
零知识身份验证:证明用户拥有密码或身份信息,而不泄露具体内容。例如:
- 证明你是某个银行的客户,而不透露你的账户号码。
- 证明你超过 18 岁,而不透露你的出生日期。
电子投票
- 确保投票者的身份被验证,但不暴露他们投给了谁。
4. ZKP 的两种主要类型
类型 | 特点 | 代表应用 |
---|---|---|
交互式零知识证明(Interactive ZKP) | 证明者和验证者多次交互 | 经典的山洞问题 |
非交互式零知识证明(Non-Interactive ZKP, NIZK) | 只需提供一个证明文件,无需多次交互 | ZK-SNARKs、ZK-STARKs |
- ZK-SNARKs(简洁非交互式零知识证明):计算快,但需要可信初始化。
- ZK-STARKs(透明可扩展零知识证明):计算更复杂,但无需可信初始化,安全性更高。
5. 零知识证明的未来
- Web3 & 隐私保护:用于去中心化身份认证(DID)、DAO 投票、NFT 交易保护。
- 隐私支付:未来的银行可能会使用零知识证明处理交易,既能满足合规性,又能保护用户隐私。
- 人工智能 & 机器学习:零知识证明可以用于 AI 模型推理,确保数据安全。
Vernam密码(Vernam Cipher)
Vernam 密码是一种 一次性密码本(One-Time Pad, OTP) 加密方法,由 Gilbert Vernam 在 1917 年发明,被认为是唯一绝对安全的加密算法,但同时难以实际应用。
密码
1. 运动密钥密码(Dynamic Key Cipher)
运动密钥密码指的是加密过程中,密钥会不断变化,而不是使用固定密钥。例如:
- 一次性密码本(One-Time Pad, OTP):每个明文字符使用不同的密钥进行加密。
- 会话密钥(Session Key):TLS 等协议中,每次通信都会生成新的加密密钥。
- 动态密钥扩展(Dynamic Key Expansion):密钥根据某种算法动态变化,如 RSA+AES 组合加密。
优势:
增强安全性,避免长期密钥被攻击。
适用于安全通信协议,如 TLS、IPsec、SSH 等。
2. 块密码(Block Cipher)
块密码是一种对 固定大小的明文块 进行加密的算法,如 AES、DES。它通常将明文分成 多个固定长度的块(如 128 位),然后使用相同的密钥分别加密这些块。
常见的块密码算法:
- AES(高级加密标准):常见于 TLS、VPN、Wi-Fi WPA2 等。
- DES(数据加密标准)(已淘汰)。
- 3DES(三重 DES)(较老,已逐渐被 AES 取代)。
块密码的模式(Block Cipher Modes):
模式 | 特点 |
---|---|
ECB(电子密码本模式) | 不安全,相同明文加密结果相同,容易被分析。 |
CBC(密码块链接模式) | 每个块与上一个密文块 XOR,安全性更高。 |
CFB(密码反馈模式) | 适合流式数据加密。 |
OFB(输出反馈模式) | 适合流式数据加密,避免误差扩散。 |
GCM(Galois/Counter 模式) | 现代模式,支持认证加密(AEAD)。 |
示例(AES-CBC 模式):
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
key = get_random_bytes(16) # 生成 16 字节密钥
iv = get_random_bytes(16) # 生成 16 字节 IV
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = b"Hello, World! " # 明文需要填充到 16 字节
ciphertext = cipher.encrypt(plaintext)
print("密文:", ciphertext.hex())
3. 流密码(Stream Cipher)
流密码是一种按 字节或比特 进行加密的算法,适用于 实时数据流(VoIP、视频通话)。它的加密密钥会不断变化,生成一个密钥流(Keystream),然后用 XOR 操作加密明文。
常见流密码算法:
- RC4(已被淘汰):曾用于 Wi-Fi WEP,现在不安全。
- ChaCha20:目前最安全的流密码之一,广泛用于 TLS 1.3、WireGuard VPN。
- Salsa20:ChaCha20 的前身,安全性较高。
流密码 vs 块密码:
对比项 | 块密码 | 流密码 |
---|---|---|
加密单位 | 固定大小的块(如 128 位) | 按位或按字节流式加密 |
速度 | 相对较慢 | 快,适用于实时通信 |
适用场景 | 硬盘加密、数据库加密 | VoIP、视频流加密 |
示例(ChaCha20 加密):
from Crypto.Cipher import ChaCha20
from Crypto.Random import get_random_bytes
key = get_random_bytes(32) # ChaCha20 需要 256-bit 密钥
nonce = get_random_bytes(8) # ChaCha20 需要 8 字节 nonce
cipher = ChaCha20.new(key=key, nonce=nonce)
plaintext = b"Hello, Stream Cipher!"
ciphertext = cipher.encrypt(plaintext)
print("密文:", ciphertext.hex())
4. 混淆(Confusion)与扩散(Diffusion)
这两个概念由 Claude Shannon(香农) 提出,是现代密码学的两个核心设计原则。
混淆(Confusion)
- 让密文和密钥之间的关系尽可能复杂,使攻击者难以推测密钥。
- 方法:使用 S 盒(Substitution box) 进行替换,使密钥和密文之间的关系复杂化。
- 示例:AES 使用 S 盒(S-Box),改变字节值,使其不可预测。
扩散(Diffusion)
- 让明文的每一位都影响密文的多个位,防止攻击者找到明文和密文的直接关系。
- 方法:使用 置换(Permutation),如 AES 的 ShiftRows 和 MixColumns 变换。
- 示例:如果改变明文的 1 位,整个密文都会大幅变化(雪崩效应)。
AES 的混淆与扩散
AES 操作 | 作用 |
---|---|
SubBytes(S 盒) | 通过替换增加混淆 |
ShiftRows | 通过行移位增加扩散 |
MixColumns | 通过列混合增加扩散 |
非对称密钥算法(Asymmetric Encryption)
非对称加密(Asymmetric Encryption)是一种 公钥密码学(Public-Key Cryptography),使用两个不同的密钥:
- 公钥(Public Key):用于加密,可公开。
- 私钥(Private Key):用于解密,必须保密。
特点:
提高安全性:即使公钥泄露,也无法解密数据。
适用于身份验证、数字签名、密钥交换等。
计算速度较慢:相比对称加密(AES),非对称加密计算量大,通常用于加密小数据(如密钥交换)。
1. 经典非对称加密算法
算法 | 密钥长度 | 安全性 | 应用场景 |
---|---|---|---|
RSA | 2048+ 位 | 依赖大整数分解 | SSL/TLS、数字签名 |
ECC(椭圆曲线加密) | 256+ 位 | 比 RSA 更高效 | 区块链、数字签名 |
DSA(数字签名算法) | 1024+ 位 | 主要用于签名 | 数字签名 |
Diffie-Hellman(DH) | 2048+ 位 | 用于密钥交换 | TLS、VPN |
2. RSA 加密
RSA(Rivest-Shamir-Adleman) 是最经典的非对称加密算法,基于大整数分解难题。
RSA 工作原理
-
密钥生成:
- 选取两个大素数
p
和q
。 - 计算
n = p × q
作为 模数(modulus)。 - 计算欧拉函数:
φ(n) = (p-1) × (q-1)
。 - 选择公钥指数
e
(通常为 65537)。 - 计算私钥
d
,使d × e ≡ 1 (mod φ(n))
。
- 选取两个大素数
-
加密:
C = M e m o d n C = M^e \mod n C=Memodn-
M
是明文,C
是密文。
-
-
解密:
M = C d m o d n M = C^d \mod n M=Cdmodn-
d
只能由私钥计算。
-
Python 示例(RSA 加密 & 解密):
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
# 生成 RSA 密钥对
key = RSA.generate(2048)
public_key = key.publickey()
# 加密
cipher_rsa = PKCS1_OAEP.new(public_key)
plaintext = b"Hello, RSA!"
ciphertext = cipher_rsa.encrypt(plaintext)
print("密文:", ciphertext.hex())
# 解密
cipher_rsa = PKCS1_OAEP.new(key)
decrypted = cipher_rsa.decrypt(ciphertext)
print("解密后明文:", decrypted.decode())
3. ECC(椭圆曲线加密)
ECC(Elliptic Curve Cryptography)是一种基于椭圆曲线离散对数问题的非对称加密算法,比 RSA 更安全、密钥更短、计算更快。
ECC vs RSA
算法 | 安全等效(RSA vs ECC) | 密钥长度 |
---|---|---|
RSA | 2048 位 | 2048 位 |
ECC | 2048 位 RSA ≈ 256 位 ECC | 256 位 |
ECC 应用:
- 区块链(Bitcoin, Ethereum)
- SSL/TLS
- 移动设备(低功耗场景)
Python 示例(ECC 密钥生成):
from ecdsa import SigningKey, SECP256k1
# 生成 ECC 密钥对
private_key = SigningKey.generate(curve=SECP256k1)
public_key = private_key.verifying_key
print("私钥:", private_key.to_string().hex())
print("公钥:", public_key.to_string().hex())
4. Diffie-Hellman(DH)密钥交换
Diffie-Hellman 不是用于加密,而是用于安全地交换对称密钥。
工作原理
-
Alice 和 Bob 选择一个公开的素数
p
和基数g
。 -
Alice 选择私钥
a
,Bob 选择私钥b
。 -
Alice 计算
A = g^a mod p
并发送给 Bob。 -
Bob 计算
B = g^b mod p
并发送给 Alice。 -
Alice 计算共享密钥
K = B^a mod p
。 -
Bob 计算共享密钥
K = A^b mod p
。 -
最终双方计算出的
K
是相同的,可用于对称加密(如 AES)。
Python 示例(DH 密钥交换):
from cryptography.hazmat.primitives.asymmetric import dh
# 生成 DH 参数
parameters = dh.generate_parameters(generator=2, key_size=2048)
# 生成 Alice 和 Bob 的私钥
alice_private_key = parameters.generate_private_key()
bob_private_key = parameters.generate_private_key()
# 计算公钥
alice_public_key = alice_private_key.public_key()
bob_public_key = bob_private_key.public_key()
# 交换公钥并计算共享密钥
alice_shared_key = alice_private_key.exchange(bob_public_key)
bob_shared_key = bob_private_key.exchange(alice_public_key)
# 确保双方计算出的密钥相同
assert alice_shared_key == bob_shared_key
print("共享密钥:", alice_shared_key.hex())
5. 数字签名
非对称加密不仅用于加密,还可用于数字签名,用于身份验证和完整性验证。
数字签名过程(以 RSA 为例)
-
签名:
- 计算消息
M
的哈希值H(M)
。 - 用私钥
d
对H(M)
进行签名:S = H(M)^d mod n
。 - 发送
(M, S)
给接收方。
- 计算消息
-
验证:
- 用公钥
e
计算H(M) = S^e mod n
。 - 如果计算结果与接收到的
M
经过哈希计算的值相同,则签名有效。
- 用公钥
Python 示例(RSA 签名 & 验证):
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
# 生成 RSA 密钥
key = RSA.generate(2048)
public_key = key.publickey()
# 签名
message = b"Hello, Digital Signature!"
hash_msg = SHA256.new(message)
signature = pkcs1_15.new(key).sign(hash_msg)
# 验证
try:
pkcs1_15.new(public_key).verify(hash_msg, signature)
print("签名验证成功!")
except:
print("签名验证失败!")
对称密码的运行模式(Block Cipher Modes of Operation)
在 对称加密(Symmetric Encryption) 中,块密码(Block Cipher)如 AES(高级加密标准) 需要特定的**运行模式(Modes of Operation)**来加密数据块。这些模式决定了如何处理多个块的数据。
1. 电子密码本模式(ECB - Electronic Codebook)
特点
- 每个数据块(128 位)单独加密,相同的明文块加密后总是相同的密文块。
- 容易受到模式分析攻击(相同的输入总是产生相同的输出)。
- 不推荐使用!
适用场景
不建议用于任何安全应用!
2. 密码块链接模式(CBC - Cipher Block Chaining)
特点
- 每个密文块都会影响下一个块,避免模式泄露。
- 需要一个随机初始化向量(IV),保证相同明文每次加密结果不同。
- 如果某个块损坏,后续解密可能会受到影响。
加密过程
C i = E k ( P i ⊕ C i − 1 ) C_i = E_k(P_i \oplus C_{i-1}) Ci=Ek(Pi⊕Ci−1)
-
C_i
:第i
块密文 -
P_i
:第i
块明文 -
C_{i-1}
:前一块的密文 -
IV
:第一块需要的初始化向量
示例(AES-CBC 加密 & 解密)
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
key = get_random_bytes(16) # 16字节AES密钥
iv = get_random_bytes(16) # 16字节随机IV
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = b"Hello, CBC Mode!" # 明文
padded_text = pad(plaintext, AES.block_size) # 填充明文
ciphertext = cipher.encrypt(padded_text) # 加密
print("密文:", ciphertext.hex())
# 解密
decipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = unpad(decipher.decrypt(ciphertext), AES.block_size)
print("解密后:", decrypted.decode())
适用场景
文件加密、数据库加密、磁盘加密(BitLocker、SSL/TLS)。
3. 计算反馈模式(CFB - Cipher Feedback)
特点
- 像流密码一样工作(不需要填充)。
- 加密时一个字节(或更小单位)输出一个字节。
- 适用于实时数据流(如 VoIP、视频流)。
加密过程
C i = P i ⊕ E k ( C i − 1 ) C_i = P_i \oplus E_k(C_{i-1}) Ci=Pi⊕Ek(Ci−1)
-
P_i
是明文,C_i
是密文。
适用场景
流式数据加密(如网络通信、VoIP)。
4. 输出反馈模式(OFB - Output Feedback)
特点
- 与 CFB 类似,但不使用前一个密文,而是不断加密 IV 生成密钥流。
- 错误不会扩散(如果某个密文块损坏,不影响其他块)。
- 适用于流式加密,避免误差传播。
加密过程
O
i
=
E
k
(
O
i
−
1
)
O_i = E_k(O_{i-1})
Oi=Ek(Oi−1)
C
i
=
P
i
⊕
O
i
C_i = P_i \oplus O_i
Ci=Pi⊕Oi
-
O_i
是加密 IV 的输出。
适用场景
无线通信、卫星通信。
5. 计数器模式(CTR - Counter)
特点
- 每个块的加密密钥由一个递增的计数器(Nonce + Counter)生成。
- 加密和解密可以并行执行(相比 CBC 更快)。
- 像流密码一样,无需填充。
加密过程
C i = P i ⊕ E k ( Nonce ∣ ∣ i ) C_i = P_i \oplus E_k(\text{Nonce} || i) Ci=Pi⊕E