【提示】 本文所有技术内容仅用于授权测试、安全研究和学习目的。未经授权对他人系统进行密码破解或攻击属于违法行为。请务必在合法授权范围内进行操作,遵守《网络安全法》《数据安全法》《个人信息保护法》等相关法律法规。文中涉及的攻击技术仅供防御研究使用。
前言:为什么密码学是信息安全的基石
在现代网络安全体系中,密码学是一切安全机制的数学根基。从HTTPS加密通信到数据库密码存储,从数字签名验签到区块链共识机制,密码学无处不在。然而,密码学的误用和配置错误仍然是导致数据泄露的最常见原因之一。
实际安全工作中,密码学问题往往比注入漏洞更隐蔽------一个使用了MD5存储密码的系统表面上看"加了密",但实际上攻击者可以在秒级完成破解;一个使用了ECB模式加密的通信协议,即使算法本身是AES-256,也会导致严重的信息泄露。
本文将从密码学基础原理出发,系统性地覆盖对称加密、非对称加密、哈希算法、数字签名、PKI证书体系、TLS协议、密码攻击技术、密码存储安全、加密通信实现、国密算法以及后量子密码等完整知识图谱,每种技术均配有实际可用的代码示例和攻击演示。
一、密码学基础概念
1.1 密码学四大核心目标
密码学旨在实现四个基本安全目标,它们构成了信息安全的CIA三要素扩展:
| 安全目标 | 英文 | 核心机制 | 应用场景 |
|---|---|---|---|
| 机密性 | Confidentiality | 加密算法 | 防止数据被未授权读取 |
| 完整性 | Integrity | 哈希/MAC | 防止数据被篡改 |
| 认证性 | Authentication | 签名/MAC | 验证数据来源身份 |
| 不可否认性 | Non-repudiation | 数字签名 | 防止发送方否认操作 |
【提示】 机密性和完整性是独立的两个目标。只加密不验证完整性是不安全的------攻击者虽然不能读取密文,但可以通过比特翻转等方式篡改密文,导致解密后得到错误的明文。
1.2 对称加密 vs 非对称加密
| 对比维度 | 对称加密 | 非对称加密 |
|---|---|---|
| 密钥数量 | 1个(共享密钥) | 2个(公钥+私钥) |
| 加解密速度 | 极快(AES约1GB/s) | 较慢(RSA约100次/秒) |
| 密钥分发 | 需安全通道传递密钥 | 公钥可公开,无需安全通道 |
| 典型算法 | AES、ChaCha20、SM4 | RSA、ECC、SM2 |
| 适用场景 | 大量数据加密 | 密钥交换、数字签名 |
| 密钥管理 | N个人需N(N-1)/2个密钥 | N个人需N对密钥 |
| 安全基础 | 替换与混淆的强度 | 数学难题难度 |
实际应用中通常采用混合加密体系:用非对称加密协商对称密钥,再用对称加密处理实际数据。HTTPS/TLS就是典型例子。
1.3 加密模式对比
分组密码只能加密固定长度的数据块(如AES为128位),加密模式定义了如何处理任意长度的数据。
| 加密模式 | 全称 | 并行计算 | 是否需要IV | 安全性评价 |
|---|---|---|---|---|
| ECB | Electronic Codebook | 加密可并行 | 否 | 不安全,相同明文产生相同密文 |
| CBC | Cipher Block Chaining | 解密可并行 | 是 | 安全(需随机IV),易受Padding Oracle攻击 |
| CFB | Cipher Feedback | 解密可并行 | 是 | 安全,可将分组密码转为流密码 |
| OFB | Output Feedback | 不可并行 | 是 | 安全,IV不可重用 |
| CTR | Counter | 加解密均可并行 | 是(Nonce) | 安全,性能优,IV不可重用 |
| GCM | Galois/Counter Mode | 加解密均可并行 | 是(Nonce) | 安全,提供AEAD认证加密 |
【提示】 永远不要使用ECB模式。GCM是当前推荐的默认模式,它同时提供加密和完整性验证(AEAD),一个操作解决机密性和完整性两个目标。
1.4 填充方案
当明文长度不是块大小的整数倍时,需要填充处理。
| 填充方案 | 原理 | 特点 |
|---|---|---|
| PKCS7 | 填充N个值为N的字节 | 最常用,每块必须填充(满块时追加整块) |
| PKCS5 | PKCS7的子集,块大小固定8字节 | 仅适用于DES等8字节块算法 |
| Zero Padding | 填充0x00字节 | 无法区分填充与原始0x00数据 |
| ISO10126 | 填充随机字节,最后一字节为长度 | 已弃用,随机性增加破解难度 |
| ANSI X.923 | 填充0x00,最后一字节为长度 | 可确定原始长度 |
| ISO/IEC 7816-4 | 首字节填0x80,后填0x00 | 用于智能卡 |
1.5 密码学常见术语表
| 术语 | 英文 | 说明 |
|---|---|---|
| 明文 | Plaintext | 未加密的原始数据 |
| 密文 | Ciphertext | 加密后的数据 |
| 密钥 | Key | 控制加解密过程的秘密参数 |
| IV | Initialization Vector | 初始化向量,使相同明文产生不同密文 |
| Nonce | Number used once | 一次性使用的随机数,防止重放攻击 |
| Salt | Salt | 随机附加值,防止彩虹表攻击 |
| MAC | Message Authentication Code | 消息认证码,验证完整性和真实性 |
| AEAD | Authenticated Encryption with Associated Data | 认证加密,同时提供机密性和完整性 |
| KDF | Key Derivation Function | 密钥派生函数,从密码生成密钥 |
| PRNG | Pseudo-Random Number Generator | 伪随机数生成器 |
二、对称加密算法详解
2.1 AES算法原理
AES(Advanced Encryption Standard)是当前最广泛使用的对称加密算法,由NIST于2001年标准化,替代DES。AES的分组大小固定为128位(16字节),密钥长度可为128/192/256位。
AES加密过程由多轮变换组成,每轮包含四个基本操作:
text
AES单轮变换流程:
┌─────────────────────────────────────┐
│ 1. SubBytes - 字节替换(S盒) │
│ 每个字节通过S盒非线性替换 │
│ 提供非线性特性,抵抗线性分析 │
├─────────────────────────────────────┤
│ 2. ShiftRows - 行移位 │
│ 第i行循环左移i个字节 │
│ 提供扩散特性,打乱字节位置 │
├─────────────────────────────────────┤
│ 3. MixColumns - 列混淆 │
│ 每列在GF(2^8)上做矩阵乘法 │
│ 进一步扩散,使一个字节影响整列 │
├─────────────────────────────────────┤
│ 4. AddRoundKey - 轮密钥加 │
│ 与轮密钥做异或运算 │
│ 引入密钥,提供安全性 │
└─────────────────────────────────────┘
| AES参数 | AES-128 | AES-192 | AES-256 |
|---|---|---|---|
| 密钥长度(位) | 128 | 192 | 256 |
| 轮数 | 10 | 12 | 14 |
| 分组大小(位) | 128 | 128 | 128 |
| 密钥扩展后长度 | 176字节 | 208字节 | 240字节 |
| 安全强度(位) | 128 | 192 | 256 |
| 抗量子安全 | 是(Grover减半) | 是 | 是 |
Python实现AES加密:
python
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
import base64
def aes_gcm_encrypt(plaintext: str, key: bytes = None) -> dict:
"""AES-GCM认证加密"""
if key is None:
key = get_random_bytes(32) # AES-256
elif len(key) not in (16, 24, 32):
raise ValueError("密钥长度必须为16/24/32字节")
nonce = get_random_bytes(12) # GCM推荐12字节nonce
cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
ciphertext, tag = cipher.encrypt_and_digest(plaintext.encode('utf-8'))
return {
'ciphertext': base64.b64encode(ciphertext).decode(),
'nonce': base64.b64encode(nonce).decode(),
'tag': base64.b64encode(tag).decode(),
'key': base64.b64encode(key).decode()
}
def aes_gcm_decrypt(enc_data: dict) -> str:
"""AES-GCM解密验证"""
key = base64.b64decode(enc_data['key'])
nonce = base64.b64decode(enc_data['nonce'])
ciphertext = base64.b64decode(enc_data['ciphertext'])
tag = base64.b64decode(enc_data['tag'])
cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
plaintext = cipher.decrypt_and_verify(ciphertext, tag)
return plaintext.decode('utf-8')
# 使用示例
if __name__ == '__main__':
message = "这是一段需要加密的秘密消息 Secret Message"
encrypted = aes_gcm_encrypt(message)
print(f"加密结果: {encrypted}")
decrypted = aes_gcm_decrypt(encrypted)
print(f"解密结果: {decrypted}")
assert decrypted == message, "解密验证失败"
print("AEAD验证通过,数据完整且未被篡改")
2.2 DES与3DES的退役
DES(Data Encryption Standard)使用56位密钥,已于2005年被NIST正式退役。56位密钥空间仅为2^56,现代硬件可在数小时内穷举破解。
3DES(Triple DES)通过三次DES运算将有效密钥长度提升到112位,但速度极慢,已于2023年在TLS 1.3中被完全移除。
python
from Crypto.Cipher import DES3
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
# 3DES加密(仅作演示,生产环境不应使用)
def des3_cbc_encrypt(plaintext: bytes, key: bytes = None) -> tuple:
if key is None:
key = DES3.adjust_key_parity(get_random_bytes(24))
iv = get_random_bytes(8)
cipher = DES3.new(key, DES3.MODE_CBC, iv=iv)
ct = cipher.encrypt(pad(plaintext, DES3.block_size))
return iv, ct
def des3_cbc_decrypt(iv: bytes, ciphertext: bytes, key: bytes) -> bytes:
cipher = DES3.new(key, DES3.MODE_CBC, iv=iv)
return unpad(cipher.decrypt(ciphertext), DES3.block_size)
# 暴力破解DES的Hashcat命令(仅用于安全研究)
# hashcat -m 14000 des_hash.txt -a 3 ?a?a?a?a?a?a?a?a --force
2.3 国密SM4算法
SM4是我国发布的分组密码标准(GB/T 32907-2016),分组大小和密钥长度均为128位,共32轮变换。SM4已在TLS、IPSec等协议中获得广泛支持。
python
# 使用gmssl库实现SM4加密
# pip install gmssl
from gmssl.sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT
import os
def sm4_cbc_encrypt(plaintext: str, key: bytes = None) -> dict:
"""SM4-CBC加密"""
if key is None:
key = os.urandom(16) # SM4密钥为16字节
iv = os.urandom(16)
sm4_crypt = CryptSM4()
sm4_crypt.set_key(key, SM4_ENCRYPT)
ciphertext = sm4_crypt.crypt_cbc(iv, plaintext.encode('utf-8'))
return {
'ciphertext': ciphertext.hex(),
'iv': iv.hex(),
'key': key.hex()
}
def sm4_cbc_decrypt(enc_data: dict) -> str:
"""SM4-CBC解密"""
key = bytes.fromhex(enc_data['key'])
iv = bytes.fromhex(enc_data['iv'])
ciphertext = bytes.fromhex(enc_data['ciphertext'])
sm4_crypt = CryptSM4()
sm4_crypt.set_key(key, SM4_DECRYPT)
plaintext = sm4_crypt.crypt_cbc(iv, ciphertext)
return plaintext.decode('utf-8')
2.4 ChaCha20流密码
ChaCha20是Daniel Bernstein设计的流密码,配合Poly1305构成AEAD方案。与AES相比,ChaCha20在纯软件实现(无AES-NI指令支持)时性能更优,已被Google用于Android和Chrome的TLS通信。
python
from Crypto.Cipher import ChaCha20_Poly1305
from Crypto.Random import get_random_bytes
import base64
def chacha20_encrypt(plaintext: str, key: bytes = None) -> dict:
"""ChaCha20-Poly1305认证加密"""
if key is None:
key = get_random_bytes(32) # 256位密钥
nonce = get_random_bytes(12)
cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
ciphertext, tag = cipher.encrypt_and_digest(plaintext.encode('utf-8'))
return {
'ciphertext': base64.b64encode(ciphertext).decode(),
'nonce': base64.b64encode(nonce).decode(),
'tag': base64.b64encode(tag).decode(),
'key': base64.b64encode(key).decode()
}
def chacha20_decrypt(enc_data: dict) -> str:
"""ChaCha20-Poly1305解密验证"""
key = base64.b64decode(enc_data['key'])
nonce = base64.b64decode(enc_data['nonce'])
ciphertext = base64.b64decode(enc_data['ciphertext'])
tag = base64.b64decode(enc_data['tag'])
cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
plaintext = cipher.decrypt_and_verify(ciphertext, tag)
return plaintext.decode('utf-8')
2.5 RC4弱点分析
RC4是Ron Rivest设计的流密码,曾被广泛用于WEP/TLS/SSL。由于存在严重的密钥调度偏差(Fluhrer-Mantin-Shamir攻击)和初始字节偏差,RC4已于2015年被RFC 7465禁止在TLS中使用。
python
# RC4弱点演示(仅用于安全分析)
# RC4的Keystream存在偏差:第2字节倾向于0
from Crypto.Cipher import ARC4
from collections import Counter
def demonstrate_rc4_bias():
"""演示RC4密钥流的统计偏差"""
key = b'SecretKey123'
cipher = ARC4.new(key)
# 生成大量密钥流
keystream = cipher.encrypt(b'\x00' * 1000000)
# 统计第2字节的分布
second_bytes = keystream[1::256]
counter = Counter(second_bytes)
# 理论上每字节概率应为1/256,但0的概率明显偏高
print(f"字节0出现次数: {counter[0]} (期望约{1000000/256/256:.0f})")
print(f"RC4密钥流存在统计偏差,不应用于新系统")
# WEP破解原理:FMS攻击利用RC4弱密钥恢复WEP密钥
# aircrack-ng工具就是基于此原理
2.6 对称算法性能对比
| 算法 | 密钥长度 | 分组大小 | 加密速度(软件) | 硬件加速 | 推荐状态 |
|---|---|---|---|---|---|
| AES-128-GCM | 128位 | 128位 | 约1.5 GB/s | AES-NI | 推荐 |
| AES-256-GCM | 256位 | 128位 | 约1.2 GB/s | AES-NI | 推荐 |
| ChaCha20-Poly1305 | 256位 | 流密码 | 约1.0 GB/s | 不需要 | 推荐 |
| SM4-CBC | 128位 | 128位 | 约300 MB/s | 逐步支持 | 国密环境推荐 |
| 3DES-CBC | 168位 | 64位 | 约50 MB/s | 不适用 | 已退役 |
| DES-CBC | 56位 | 64位 | 约100 MB/s | 不适用 | 已废弃 |
| RC4 | 40-2048位 | 流密码 | 约200 MB/s | 不适用 | 禁用 |
三、非对称加密算法
3.1 RSA数学原理
RSA的安全性基于大整数分解难题:给定大数n=p*q,分解出p和q在计算上不可行。
RSA密钥生成与加解密的数学过程:
text
RSA密钥生成过程:
1. 选择两个大素数 p, q(通常1024位以上)
2. 计算 n = p * q(模数,公钥的一部分)
3. 计算欧拉函数 φ(n) = (p-1) * (q-1)
4. 选择公钥指数 e,满足 1 < e < φ(n) 且 gcd(e, φ(n)) = 1
常用 e = 65537 (0x10001)
5. 计算私钥指数 d = e^(-1) mod φ(n)
即 d * e ≡ 1 (mod φ(n))
使用扩展欧几里得算法求模逆元
公钥 = (n, e)
私钥 = (n, d)
加密:c = m^e mod n
解密:m = c^d mod n
签名:s = m^d mod n
验签:m = s^e mod n
RSA密钥生成与加解密代码:
python
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
import base64
def generate_rsa_keypair(key_size: int = 2048) -> tuple:
"""生成RSA密钥对"""
key = RSA.generate(key_size)
private_key = key.export_key()
public_key = key.publickey().export_key()
return private_key, public_key
def rsa_encrypt(plaintext: str, public_key_pem: bytes) -> str:
"""RSA-OAEP加密"""
recipient_key = RSA.import_key(public_key_pem)
cipher = PKCS1_OAEP.new(recipient_key)
ciphertext = cipher.encrypt(plaintext.encode('utf-8'))
return base64.b64encode(ciphertext).decode()
def rsa_decrypt(ciphertext_b64: str, private_key_pem: bytes) -> str:
"""RSA-OAEP解密"""
private_key = RSA.import_key(private_key_pem)
cipher = PKCS1_OAEP.new(private_key)
ciphertext = base64.b64decode(ciphertext_b64)
plaintext = cipher.decrypt(ciphertext)
return plaintext.decode('utf-8')
def rsa_sign(message: str, private_key_pem: bytes) -> str:
"""RSA-PKCS1v15签名"""
private_key = RSA.import_key(private_key_pem)
h = SHA256.new(message.encode('utf-8'))
signature = pkcs1_15.new(private_key).sign(h)
return base64.b64encode(signature).decode()
def rsa_verify(message: str, signature_b64: str, public_key_pem: bytes) -> bool:
"""RSA签名验证"""
public_key = RSA.import_key(public_key_pem)
h = SHA256.new(message.encode('utf-8'))
try:
pkcs1_15.new(public_key).verify(h, base64.b64decode(signature_b64))
return True
except (ValueError, TypeError):
return False
# 使用示例
if __name__ == '__main__':
priv, pub = generate_rsa_keypair(2048)
encrypted = rsa_encrypt("Hello RSA World", pub)
decrypted = rsa_decrypt(encrypted, priv)
print(f"解密: {decrypted}")
sig = rsa_sign("重要消息", priv)
valid = rsa_verify("重要消息", sig, pub)
print(f"签名验证: {'通过' if valid else '失败'}")
【提示】 RSA加密必须使用OAEP或PKCS1v1.5填充方案。裸RSA(直接做m^e mod n)存在多种数学攻击(如选择密文攻击、低指数攻击等)。OAEP是目前推荐的填充方案。
3.2 ECC椭圆曲线密码
ECC(Elliptic Curve Cryptography)基于椭圆曲线离散对数问题(ECDLP),在相同安全强度下密钥远小于RSA。
text
椭圆曲线方程:y² = x³ + ax + b (mod p)
核心运算:
1. 点加法:P + Q = R
几何意义:过P和Q作直线,与曲线的第三交点关于x轴对称即为R
2. 点乘(标量乘法):k * P = P + P + ... + P(k次)
这是ECC的单向函数基础
已知P和k,计算k*P很容易
已知P和Q=k*P,求k极其困难(离散对数问题)
3. 基点G:曲线上选定的公共起点
私钥 d:随机大整数
公钥 Q = d * G
python
from Crypto.PublicKey import ECC
from Crypto.Signature import eddsa
from Crypto.Hash import SHA512
import base64
def generate_ecc_keypair(curve: str = 'P-256') -> tuple:
"""生成ECC密钥对"""
key = ECC.generate(curve=curve)
private_key = key.export_key(format='PEM')
public_key = key.public_key().export_key(format='PEM')
return private_key, public_key
def ecc_sign(message: bytes, private_key_pem: str) -> bytes:
"""ECDSA签名"""
key = ECC.import_key(private_key_pem)
signer = eddsa.new(key, 'rfc8032')
return signer.sign(message)
def ecc_verify(message: bytes, signature: bytes, public_key_pem: str) -> bool:
"""ECDSA验签"""
key = ECC.import_key(public_key_pem)
verifier = eddsa.new(key, 'rfc8032')
try:
verifier.verify(message, signature)
return True
except ValueError:
return False
3.3 国密SM2算法
SM2是基于椭圆曲线的我国公钥密码标准(GB/T 32918),使用256位素数域上的椭圆曲线,等效安全强度约3072位RSA。
python
# pip install gmssl
from gmssl import sm2, func
def sm2_keypair():
"""生成SM2密钥对"""
private_key = func.random_hex(64) # 256位私钥
# SM2推荐曲线参数
sm2_obj = sm2.CryptSM2(private_key=private_key, public_key='')
public_key = sm2_obj._kg(int(private_key, 16), func.sm2_para())
return private_key, '%064x' % public_key
def sm2_encrypt(plaintext: bytes, pub_key_hex: str) -> bytes:
"""SM2加密"""
sm2_obj = sm2.CryptSM2(public_key=pub_key_hex, private_key='')
return sm2_obj.encrypt(plaintext)
def sm2_decrypt(ciphertext: bytes, priv_key_hex: str, pub_key_hex: str) -> bytes:
"""SM2解密"""
sm2_obj = sm2.CryptSM2(private_key=priv_key_hex, public_key=pub_key_hex)
return sm2_obj.decrypt(ciphertext)
3.4 Diffie-Hellman密钥交换
DH密钥交换允许双方在不安全信道上协商共享密钥,安全性基于离散对数问题。
python
from Crypto.Random import get_random_bytes
from Crypto.Protocol.SecretSharing import Shamir
# 经典DH密钥交换演示
def dh_key_exchange_demo():
"""
Diffie-Hellman密钥交换原理:
1. 双方约定公共参数:大素数p和生成元g
2. Alice选随机数a,计算A = g^a mod p,发送A给Bob
3. Bob选随机数b,计算B = g^b mod p,发送B给Alice
4. Alice计算共享密钥 s = B^a mod p = (g^b)^a mod p = g^(ab) mod p
5. Bob计算共享密钥 s = A^b mod p = (g^a)^b mod p = g^(ab) mod p
6. 攻击者只能看到A和B,要计算g^(ab)需要知道a或b(离散对数难题)
"""
# 实际使用ECDH(椭圆曲线DH)
from Crypto.PublicKey import ECC
# Alice生成密钥对
alice_key = ECC.generate(curve='P-256')
alice_pub = alice_key.public_key()
# Bob生成密钥对
bob_key = ECC.generate(curve='P-256')
bob_pub = bob_key.public_key()
# Alice用Bob的公钥和自己的私钥计算共享密钥
alice_shared = alice_key.d * bob_pub.pointQ
# Bob用Alice的公钥和自己的私钥计算共享密钥
bob_shared = bob_key.d * alice_pub.pointQ
# 两者相等
print(f"Alice共享密钥: {alice_shared.x}")
print(f"Bob共享密钥: {bob_shared.x}")
print(f"密钥一致: {alice_shared.x == bob_shared.x}")
# ECDH的OpenSSL命令行操作
# 生成密钥对:openssl ecparam -name prime256v1 -genkey -out ec_key.pem
# 导出公钥: openssl ec -in ec_key.pem -pubout -out ec_pub.pem
# 派生共享密钥需要编程实现
3.5 非对称算法安全强度对比
| 算法 | 密钥长度 | 等效对称强度 | 推荐用途 |
|---|---|---|---|
| RSA-1024 | 1024位 | 约80位 | 已不推荐 |
| RSA-2048 | 2048位 | 约112位 | 最低可用标准 |
| RSA-3072 | 3072位 | 约128位 | 推荐 |
| RSA-4096 | 4096位 | 约150位 | 高安全需求 |
| ECC-224 | 224位 | 约112位 | 等效RSA-2048 |
| ECC-256 (P-256) | 256位 | 约128位 | 推荐,等效RSA-3072 |
| ECC-384 (P-384) | 384位 | 约192位 | 高安全需求 |
| ECC-521 (P-521) | 521位 | 约256位 | 最高安全需求 |
| SM2 | 256位 | 约128位 | 国密合规 |
【提示】 RSA-2048与ECC-256提供近似的安全强度,但ECC的密钥长度仅为RSA的1/8。这使得ECC在移动端和IoT设备上具有显著优势。NIST建议2030年后使用至少3072位RSA或256位ECC。
四、哈希算法与破解
4.1 MD5原理与碰撞攻击
MD5由Ronald Rivest设计,输出128位哈希值。其核心是Merkle-Damgard结构,通过64轮压缩函数处理512位消息块。
2004年,中国密码学家王小云团队发表了MD5碰撞攻击,可以在约220次运算内找到碰撞(理论安全需264次),使MD5彻底退出安全哈希领域。
python
import hashlib
def md5_collision_demo():
"""
MD5碰撞演示 - 同一MD5值的不同消息
这是王小云攻击产生的经典碰撞对
"""
# 两个不同的消息产生相同的MD5
msg1 = bytes.fromhex(
'd131dd02c5e6eec4693d9a0698aff95c'
'2fcab58712467eab4004583eb8fb7f89'
'55ad340609f4b30283e488832571415a'
'085125e8f7cdc99fd91dbdf280373c5b'
'8831998d6e559a2af2c2a0c4eaa1e2c3'
'7d4d5d6c6e559a2af2c2a0c4eaa1e2c3'
)
msg2 = bytes.fromhex(
'd131dd02c5e6eec4693d9a0698aff95c'
'2fcab50712467eab4004583eb8fb7f89'
'55ad340609f4b30283e4888325f1415a'
'085125e8f7cdc99fd91dbd7280373c5b'
'8831998d6e559a2af2c2a0c4eaa1e2c3'
'7d4d5d6c6e559a2af2c2a0c4eaa1e2c3'
)
hash1 = hashlib.md5(msg1).hexdigest()
hash2 = hashlib.md5(msg2).hexdigest()
print(f"消息1 MD5: {hash1}")
print(f"消息2 MD5: {hash2}")
print(f"碰撞结果: {hash1 == hash2}")
print(f"消息相同: {msg1 == msg2}")
4.2 SHA-1退役与SHA-2/SHA-3
SHA-1输出160位哈希值。2017年Google与CWI Amsterdam发表了SHAttered攻击,以263次运算(远低于理论280)找到SHA-1碰撞。各大浏览器自2017年起停止信任SHA-1证书。
SHA-2家族包括SHA-224/256/384/512,使用64/80轮压缩函数,目前无已知实际碰撞攻击。SHA-3(Keccak)采用海绵结构,与SHA-2完全不同的设计,作为SHA-2的补充标准。
python
import hashlib
# SHA-2/SHA-3使用示例
def hash_comparison():
message = b"Hello Cryptography World"
algorithms = {
'MD5': hashlib.md5,
'SHA-1': hashlib.sha1,
'SHA-256': hashlib.sha256,
'SHA-512': hashlib.sha512,
'SHA3-256': hashlib.sha3_256,
'SHA3-512': hashlib.sha3_512,
'BLAKE2b': hashlib.blake2b,
'BLAKE2s': hashlib.blake2s,
}
for name, algo in algorithms.items():
h = algo(message).hexdigest()
print(f"{name:12s}: {h}")
# OpenSSL命令行哈希操作
# echo -n "Hello" | openssl dgst -md5
# echo -n "Hello" | openssl dgst -sha256
# echo -n "Hello" | openssl dgst -sha3-256
# openssl dgst -sha256 file.txt
4.3 国密SM3
SM3是我国密码杂凑算法标准(GB/T 32905-2016),输出256位,采用Merkle-Damgard结构,压缩函数共64轮。
python
from gmssl import sm3, func
def sm3_hash(message: str) -> str:
"""计算SM3哈希"""
data = func.bytes_to_list(message.encode('utf-8'))
return sm3.sm3_hash(data)
# SM3在国密体系中的应用
# - SM2签名使用SM3作为摘要算法
# - 国密TLS使用SM3替代SHA-256
# - 数字证书中使用SM3做指纹哈希
4.4 BLAKE2/BLAKE3
BLAKE2是BLAKE算法的改进版,比MD5更快且安全性等同SHA-3。BLAKE3进一步改进,支持并行计算和可扩展输出长度。
python
import hashlib
def blake3_example():
"""BLAKE2使用(Python 3.6+内置)"""
# BLAKE2b - 64位平台优化,输出最长512位
h = hashlib.blake2b(b"Hello", digest_size=32)
print(f"BLAKE2b-256: {h.hexdigest()}")
# BLAKE2b带密钥(MAC模式)
key = b'secret_key_for_mac'
h = hashlib.blake2b(b"Hello", key=key, digest_size=32)
print(f"BLAKE2b-MAC: {h.hexdigest()}")
# BLAKE3需要安装:pip install blake3
def blake3_example():
"""BLAKE3使用"""
import blake3
h = blake3.blake3(b"Hello BLAKE3")
print(f"BLAKE3: {h.hexdigest()}")
# 可扩展输出
print(f"BLAKE3-64: {h.hexdigest(64)}")
4.5 密码哈希函数 bcrypt/scrypt/Argon2
普通哈希函数(SHA-256等)计算太快,不适合密码存储。密码哈希函数通过加盐和可调计算成本来抵抗暴力破解。
python
# pip install bcrypt scrypt argon2-cffi
import bcrypt
import argon2
import hashlib
import os
import base64
def bcrypt_example(password: str):
"""bcrypt密码哈希"""
# 自动生成盐值并哈希
salt = bcrypt.gensalt(rounds=12) # cost=2^12,约250ms
hashed = bcrypt.hashpw(password.encode('utf-8'), salt)
print(f"bcrypt哈希: {hashed.decode()}")
return hashed
def bcrypt_verify(password: str, hashed: bytes) -> bool:
"""bcrypt验证"""
return bcrypt.checkpw(password.encode('utf-8'), hashed)
def argon2_example(password: str):
"""Argon2id密码哈希(推荐)"""
ph = argon2.PasswordHasher(
time_cost=3, # 迭代次数
memory_cost=65536, # 64MB内存
parallelism=4, # 4线程并行
hash_len=32, # 输出32字节
salt_len=16 # 盐值16字节
)
hashed = ph.hash(password)
print(f"Argon2id哈希: {hashed}")
return ph, hashed
def argon2_verify(ph, password: str, hashed: str) -> bool:
"""Argon2验证"""
try:
return ph.verify(hashed, password)
except argon2.exceptions.VerifyMismatchError:
return False
# scrypt示例
def scrypt_example(password: str):
"""scrypt密码哈希"""
salt = os.urandom(16)
dk = hashlib.scrypt(
password.encode('utf-8'),
salt=salt,
n=2**14, # CPU/内存成本参数
r=8, # 块大小参数
p=1, # 并行参数
dklen=32 # 输出长度
)
stored = f"scrypt${n}${r}${p}${base64.b64encode(salt).decode()}${base64.b64encode(dk).decode()}"
print(f"scrypt哈希: {stored}")
return stored
【提示】 密码存储应优先使用Argon2id(2025年OWASP推荐首选),其次是scrypt和bcrypt。永远不要使用MD5/SHA-1/SHA-256直接存储密码。Argon2id通过同时消耗CPU和大量内存,有效抵抗GPU和ASIC破解。
4.6 哈希算法安全性对比
| 哈希算法 | 输出长度 | 块大小 | 轮数 | 碰撞攻击 | 推荐状态 |
|---|---|---|---|---|---|
| MD5 | 128位 | 512位 | 64 | 存在(2^20) | 禁止用于安全用途 |
| SHA-1 | 160位 | 512位 | 80 | 存在(2^63) | 禁止用于证书 |
| SHA-256 | 256位 | 512位 | 64 | 无已知 | 推荐 |
| SHA-512 | 512位 | 1024位 | 80 | 无已知 | 推荐 |
| SHA3-256 | 256位 | 可变 | 24 | 无已知 | 推荐 |
| SHA3-512 | 512位 | 可变 | 24 | 无已知 | 推荐 |
| SM3 | 256位 | 512位 | 64 | 无已知 | 国密推荐 |
| BLAKE2b | 最多512位 | 1024位 | 12 | 无已知 | 推荐 |
| BLAKE3 | 可变 | 1024位 | 7 | 无已知 | 推荐(高性能) |
4.7 哈希长度扩展攻击
长度扩展攻击针对Merkle-Damgard结构的哈希函数(MD5、SHA-1、SHA-256等),攻击者已知hash(secret || message),无需知道secret即可计算hash(secret || message || padding || extension)。
python
"""
哈希长度扩展攻击演示
利用Merkle-Damgard结构的弱点,在不知道密钥的情况下伪造HMAC
攻击条件:
1. 哈希函数使用Merkle-Damgard结构(如MD5/SHA-1/SHA-256)
2. 已知 hash(secret || original_message) 的值
3. 知道 original_message 的长度(可推算secret长度)
防御方案:使用HMAC结构而非简单的 hash(secret || message)
"""
import struct
import hashlib
def md5_extension_attack():
"""MD5长度扩展攻击原理演示"""
def md5_compress(state, message_block):
"""模拟MD5压缩函数的内部状态设置"""
# 通过设置MD5初始状态来模拟从中间继续哈希
# 实际需要操作MD5内部寄存器
pass
# 攻击场景:
# 服务器使用 cookie = md5(secret + "data=guest") 验证权限
# 攻击者知道cookie值,但不知道secret
# 目标:伪造 cookie = md5(secret + "data=guest" + padding + "data=admin")
secret_length = 16 # 假设密钥16字节(攻击者需尝试不同长度)
original_msg = b"data=guest"
# 模拟服务器计算
secret = b'supersecretkey!' # 攻击者不知道
original_hash = hashlib.md5(secret + original_msg).hexdigest()
print(f"已知哈希: {original_hash}")
print(f"密钥长度(攻击者未知,需爆破): {secret_length}")
# 计算MD5填充
msg_length = secret_length + len(original_msg)
padding = b'\x80'
padding += b'\x00' * ((56 - (msg_length + 1) % 64) % 64)
padding += struct.pack('<Q', msg_length * 8)
# 附加的恶意数据
extension = b"data=admin"
# 使用hashpumpy工具进行实际攻击:
# pip install hashpumpy
# import hashpumpy
# new_hash, new_msg = hashpumpy.hashpump(
# original_hash,
# original_msg,
# extension,
# secret_length
# )
# print(f"伪造哈希: {new_hash}")
# print(f"伪造消息: {new_msg}")
print(f"\n防御方案:使用HMAC替代直接哈希")
print(f"HMAC = H(key XOR opad || H(key XOR ipad || message))")
print(f"HMAC不受长度扩展攻击影响")
md5_extension_attack()
五、消息认证码与数字签名
5.1 HMAC原理与实现
HMAC(Hash-based Message Authentication Code)使用密钥和哈希函数生成消息认证码,同时提供完整性和认证性。
python
import hmac
import hashlib
def hmac_sign(key: bytes, message: bytes, algorithm=hashlib.sha256) -> str:
"""HMAC签名"""
mac = hmac.new(key, message, algorithm).hexdigest()
return mac
def hmac_verify(key: bytes, message: bytes, received_mac: str, algorithm=hashlib.sha256) -> bool:
"""HMAC验证(使用恒定时间比较防止时序攻击)"""
expected_mac = hmac.new(key, message, algorithm).hexdigest()
return hmac.compare_digest(expected_mac, received_mac)
# HMAC使用示例
secret_key = b'my_secret_hmac_key_2024'
message = b'转账:Alice -> Bob,金额:10000元'
mac = hmac_sign(secret_key, message)
print(f"HMAC-SHA256: {mac}")
# 验证
is_valid = hmac_verify(secret_key, message, mac)
print(f"验证结果: {is_valid}")
# 篡改检测
tampered_msg = b'转账:Alice -> Bob,金额:1000000元'
is_tampered = hmac_verify(secret_key, tampered_msg, mac)
print(f"篡改检测: {'未检测到篡改(危险!)' if is_tampered else '检测到篡改(安全)'}")
5.2 CBC-MAC与CMAC
python
from Crypto.Hash import CMAC
from Crypto.Cipher import AES
def cmac_example():
"""AES-CMAC计算"""
key = b'Sixteen byte key' # 16字节AES密钥
message = b'This is the message to authenticate'
cobj = CMAC.new(key, ciphermod=AES)
cobj.update(message)
mac = cobj.hexdigest()
print(f"AES-CMAC: {mac}")
# 验证
cobj2 = CMAC.new(key, ciphermod=AES)
cobj2.update(message)
try:
cobj2.verify(bytes.fromhex(mac))
print("CMAC验证通过")
except ValueError:
print("CMAC验证失败")
5.3 HMAC vs 数字签名对比
| 对比维度 | HMAC | 数字签名 |
|---|---|---|
| 使用的密钥 | 对称密钥 | 非对称密钥(私钥签名/公钥验签) |
| 不可否认性 | 不支持 | 支持 |
| 计算速度 | 快 | 较慢 |
| 验证方 | 任何持有密钥的人 | 任何持有公钥的人 |
| 适用场景 | 会话认证、API签名 | 证书签发、合同签署 |
| 标准方案 | HMAC-SHA256 | RSA-PSS、ECDSA、EdDSA |
5.4 RSA数字签名
python
from Crypto.PublicKey import RSA
from Crypto.Signature import pss
from Crypto.Hash import SHA256
def rsa_pss_sign(message: bytes, private_key_pem: bytes) -> bytes:
"""RSA-PSS签名(推荐)"""
key = RSA.import_key(private_key_pem)
h = SHA256.new(message)
signature = pss.new(key).sign(h)
return signature
def rsa_pss_verify(message: bytes, signature: bytes, public_key_pem: bytes) -> bool:
"""RSA-PSS验签"""
key = RSA.import_key(public_key_pem)
h = SHA256.new(message)
verifier = pss.new(key)
try:
verifier.verify(h, signature)
return True
except (ValueError, TypeError):
return False
5.5 ECDSA签名与验证
python
from Crypto.PublicKey import ECC
from Crypto.Signature import DSS
from Crypto.Hash import SHA256
def ecdsa_sign(message: bytes, private_key_pem: str) -> bytes:
"""ECDSA签名(使用ECDSA + SHA-256)"""
key = ECC.import_key(private_key_pem)
h = SHA256.new(message)
signer = DSS.new(key, 'fips-186-3')
return signer.sign(h)
def ecdsa_verify(message: bytes, signature: bytes, public_key_pem: str) -> bool:
"""ECDSA验签"""
key = ECC.import_key(public_key_pem)
h = SHA256.new(message)
verifier = DSS.new(key, 'fips-186-3')
try:
verifier.verify(h, signature)
return True
except ValueError:
return False
5.6 签名方案对比
| 签名方案 | 密钥长度 | 签名长度 | 签名速度 | 验签速度 | 推荐状态 |
|---|---|---|---|---|---|
| RSA-PKCS1v15 | 2048位 | 256字节 | 慢 | 快 | 可用(旧系统兼容) |
| RSA-PSS | 2048位 | 256字节 | 慢 | 快 | 推荐 |
| ECDSA | 256位 | 64字节 | 中 | 快 | 推荐 |
| Ed25519 | 256位 | 64字节 | 极快 | 极快 | 强烈推荐 |
| SM2 | 256位 | 64字节 | 中 | 中 | 国密推荐 |
| DSA | 1024位 | 48字节 | 中 | 中 | 已弃用 |
【提示】 Ed25519是Daniel Bernstein设计的EdDSA签名方案,签名和验签速度均远超ECDSA,且实现简单、安全性高,已被SSH、Signal、age等现代系统广泛采用。
六、PKI与数字证书体系
6.1 X.509证书结构
X.509是公钥基础设施中最广泛使用的证书格式标准。一个X.509证书包含以下字段:
| 字段 | 说明 | 示例 |
|---|---|---|
| Version | 证书版本(v1/v2/v3) | v3 |
| Serial Number | 序列号(CA签发的唯一编号) | 04:8F:FF:... |
| Signature Algorithm | 签名算法标识 | SHA256withRSA |
| Issuer | 颁发者(CA的DN) | CN=Let's Encrypt R3 |
| Validity | 有效期(notBefore/notAfter) | 2024-01-01 至 2024-04-01 |
| Subject | 主体(持有者DN) | CN=example.com |
| Subject Public Key | 主体公钥信息 | RSA 2048位公钥 |
| Extensions | 扩展字段 | SAN, KeyUsage, BasicConstraints |
| Signature | CA的数字签名 | CA私钥对TBS证书的签名 |
6.2 CA证书链验证流程
text
证书链验证流程:
根CA (Root CA) ← 自签名,预装在操作系统/浏览器中
│
├── 中间CA (Intermediate CA)
│ │
│ ├── 终端证书 (example.com)
│ ├── 终端证书 (api.example.com)
│ └── 终端证书 (mail.example.com)
│
└── 中间CA (Another Intermediate)
└── ...
验证步骤:
1. 收到服务器证书链 [终端证书, 中间CA证书]
2. 检查终端证书的签名是否由中间CA签发(用中间CA公钥验签)
3. 检查中间CA的签名是否由根CA签发(用根CA公钥验签)
4. 根CA是自签名的,且预装在信任库中 → 信任链建立
5. 检查每个证书的有效期
6. 检查证书吊销状态(CRL或OCSP)
7. 检查主机名匹配(SAN/CN字段)
6.3 OpenSSL证书操作命令集
bash
# === 生成私钥和CSR ===
# 生成RSA私钥(2048位)
openssl genrsa -out private.key 2048
# 生成带密码保护的私钥
openssl genrsa -aes256 -out private_encrypted.key 2048
# 从私钥生成CSR(证书签名请求)
openssl req -new -key private.key -out request.csr -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=example.com"
# 一步生成私钥和CSR
openssl req -newkey rsa:2048 -nodes -keyout private.key -out request.csr -subj "/C=CN/ST=Beijing/O=MyCompany/CN=example.com"
# 生成ECC私钥和CSR
openssl ecparam -name prime256v1 -genkey -noout -out ec_private.key
openssl req -new -key ec_private.key -out ec_request.csr -subj "/C=CN/CN=example.com"
# === 自签名证书(仅用于测试) ===
openssl req -x509 -newkey rsa:2048 -nodes -keyout private.key -out cert.pem -days 365 -subj "/C=CN/CN=localhost"
# === CA签发证书 ===
# 使用CA私钥和CA证书签发CSR
openssl x509 -req -in request.csr -CA ca_cert.pem -CAkey ca_private.key -CAcreateserial -out server_cert.pem -days 365 -sha256
# 带扩展签发(SAN等)
openssl x509 -req -in request.csr -CA ca_cert.pem -CAkey ca_private.key -CAcreateserial -out server_cert.pem -days 365 -sha256 -extfile <(printf "subjectAltName=DNS:example.com,DNS:www.example.com\nextendedKeyUsage=serverAuth")
# === 查看证书 ===
# 查看证书详情
openssl x509 -in cert.pem -text -noout
# 只查看主体
openssl x509 -in cert.pem -subject -noout
# 只查看颁发者
openssl x509 -in cert.pem -issuer -noout
# 只查看有效期
openssl x509 -in cert.pem -dates -noout
# 只查看公钥
openssl x509 -in cert.pem -pubkey -noout
# 查看CSR内容
openssl req -in request.csr -text -noout
# === 验证证书 ===
# 验证证书链
openssl verify -CAfile ca_cert.pem server_cert.pem
# 验证带中间证书的链
openssl verify -CAfile ca_cert.pem -untrusted intermediate.pem server_cert.pem
# 检查证书与私钥是否匹配
openssl x509 -in cert.pem -pubkey -noout | openssl md5
openssl rsa -in private.key -pubout -outform PEM | openssl md5
# 两个MD5值一致说明匹配
# === 格式转换 ===
# PEM转DER
openssl x509 -in cert.pem -outform DER -out cert.der
# DER转PEM
openssl x509 -in cert.der -inform DER -outform PEM -out cert.pem
# PEM转PKCS12(.p12/.pfx)
openssl pkcs12 -export -out cert.p12 -inkey private.key -in cert.pem -chain -CAfile ca_cert.pem
# PKCS12转PEM
openssl pkcs12 -in cert.p12 -out cert_and_key.pem -nodes
# 查看PKCS12内容
openssl pkcs12 -in cert.p12 -info -noout
# === 在线检查证书(连接远程服务器) ===
# 查看HTTPS服务器证书
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -text -noout
# 获取证书链
echo | openssl s_client -connect example.com:443 -showcerts 2>/dev/null
# === CRL和OCSP ===
# 下载CRL
openssl crl -in crl.pem -text -noout
# OCSP查询
openssl ocsp -issuer ca_cert.pem -cert server_cert.pem -url http://ocsp.example.com -resp_text
6.4 证书透明度与Pinning
text
证书透明度(Certificate Transparency, CT):
- 要求CA将签发的证书提交到公开的CT日志中
- 任何人可以查询和审计证书签发情况
- 浏览器要求EV证书和2018年后的证书必须包含SCT
- 查询工具:https://crt.sh、https://censys.io
证书Pinning:
- 客户端预先固定信任的证书公钥哈希
- 即使CA被攻破也无法进行中间人攻击
- 缺点:证书轮换时需更新Pinning,可能导致服务中断
- 已被移动端广泛采用(如Android Network Security Config)
HTTP Public Key Pinning (HPKP) 已被废弃,推荐使用:
- Android: Network Security Config
- iOS: App Transport Security + Pinned Public Keys
- 浏览器: 不再推荐HPKP,改为使用CT监控
七、TLS/SSL协议详解
7.1 TLS 1.2握手流程
text
TLS 1.2完整握手流程:
Client Server
| |
|--- ClientHello ------------------------------>|
| (TLS版本, 客户端随机数, 密码套件列表, |
| 扩展: SNI, ALPN, Signature Algorithms) |
| |
|<-- ServerHello -------------------------------|
| (选定TLS版本, 服务器随机数, 选定密码套件) |
|<-- Certificate -------------------------------|
| (服务器证书链) |
|<-- ServerKeyExchange -------------------------|
| (DH/ECDH参数, 服务器签名) |
|<-- ServerHelloDone ---------------------------|
| |
|--- ClientKeyExchange ------------------------->|
| (加密的Pre-Master Secret或ECDH公钥) |
|--- ChangeCipherSpec ------------------------->|
|--- Finished --------------------------------->|
| (用协商密钥加密的握手消息哈希) |
| |
|<-- ChangeCipherSpec --------------------------|
|<-- Finished ---------------------------------|
| |
|<========= 应用数据加密通信 ===================>|
密钥派生过程:
1. PreMasterSecret(RSA交换或ECDH计算得到)
2. MasterSecret = PRF(PreMasterSecret, "master secret", ClientRandom + ServerRandom)
3. Key Block = PRF(MasterSecret, "key expansion", ServerRandom + ClientRandom)
4. 从Key Block中切分出:
- 客户端写密钥、服务器写密钥
- 客户端写MAC密钥、服务器写MAC密钥
- 客户端写IV、服务器写IV
7.2 TLS 1.3改进分析
TLS 1.3对TLS 1.2进行了大幅简化,移除了所有不安全的算法和冗余的握手消息。
| 改进项 | TLS 1.2 | TLS 1.3 |
|---|---|---|
| 握手往返次数 | 2-RTT | 1-RTT(可0-RTT) |
| 密钥交换 | RSA/DH/ECDH | 仅ECDHE/DHE |
| 对称加密 | CBC/GCM/CCM等 | 仅AEAD(GCM/CCM/ChaCha20) |
| 哈希算法 | MD5/SHA-1/SHA-2 | 仅SHA-2/SHA-3 |
| 签名算法 | RSA-PKCS1v15等 | RSA-PSS/ECDSA/EdDSA |
| 压缩 | 支持 | 移除(CRIME/BREACH攻击) |
| 重协商 | 支持 | 移除 |
| 0-RTT | 不支持 | 支持(基于PSK) |
| 向前保密 | 可选 | 强制 |
text
TLS 1.3握手流程(1-RTT):
Client Server
| |
|--- ClientHello ------------------------------>|
| (TLS 1.3, 客户端随机数, 密码套件, |
| key_share扩展含ECDH公钥, |
| early_data扩展(0-RTT时)) |
| |
|<-- ServerHello -------------------------------|
| (服务器随机数, 选定密码套件, |
| key_share扩展含ECDH公钥) |
|<-- EncryptedExtensions -----------------------|
|<-- Certificate -------------------------------|
|<-- CertificateVerify ------------------------|
|<-- Finished ---------------------------------|
| |
|--- Finished --------------------------------->|
| |
|<========= 应用数据加密通信 ===================>|
0-RTT模式(基于PSK的会话恢复):
- 客户端在ClientHello中携带early_data
- 服务器收到后可立即处理(无需等待握手完成)
- 风险:0-RTT数据不具备前向保密性,且可能遭受重放攻击
- 仅适用于幂等请求(如GET)
7.3 TLS攻击历史
| 攻击名称 | 年份 | 攻击原理 | 受影响版本 | 缓解措施 |
|---|---|---|---|---|
| BEAST | 2011 | 利用CBC模式选择明文攻击 | TLS 1.0 | 使用TLS 1.1+,或RC4(已废弃) |
| CRIME | 2012 | 利用TLS压缩泄露Cookie | 所有版本 | 禁用TLS压缩 |
| BREACH | 2013 | 利用HTTP压缩泄露敏感数据 | 所有版本 | 禁用HTTP压缩或随机化响应 |
| POODLE | 2014 | 利用SSL 3.0 CBC填充缺陷 | SSL 3.0 | 禁用SSL 3.0 |
| Heartbleed | 2014 | OpenSSL心跳扩展内存泄露 | OpenSSL 1.0.1 | 升级OpenSSL |
| FREAK | 2015 | 强制降级到512位RSA出口密钥 | 所有版本 | 禁用出口级密码套件 |
| Logjam | 2015 | 降级到512位DH参数 | 所有版本 | 使用2048位以上DH参数 |
| DROWN | 2016 | 通过SSLv2服务器攻击RSA | 启用SSLv2的服务器 | 禁用SSLv2 |
| ROBOT | 2017 | 利用RSA PKCS1v1.5签名缺陷 | RSA加密服务器 | 使用RSA-PSS或ECDHE |
| Raccoon | 2020 | 利用DH共享密钥的时序差 | TLS 1.2及以下 | 使用TLS 1.3 |
7.4 密码套件命名规则与安全配置
text
TLS密码套件命名规则(TLS 1.2):
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
│ │ │ │ │ │
│ │ │ │ │ └── PRF/哈希算法
│ │ │ │ └── 加密模式
│ │ │ └── 加密算法和密钥长度
│ │ └── 认证算法
│ └── 密钥交换算法
└── 协议标识
安全密码套件推荐优先级(TLS 1.2):
1. TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
2. TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
3. TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
4. TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
5. TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
6. TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
TLS 1.3密码套件(仅AEAD):
1. TLS_AES_256_GCM_SHA384
2. TLS_AES_128_GCM_SHA256
3. TLS_CHACHA20_POLY1305_SHA256
4. TLS_AES_128_CCM_SHA256
7.5 TLS安全配置示例
Nginx安全TLS配置:
nginx
# Nginx TLS安全配置
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
# 证书配置
ssl_certificate /etc/ssl/certs/fullchain.pem;
ssl_certificate_key /etc/ssl/private/privkey.pem;
# 仅允许TLS 1.2和1.3
ssl_protocols TLSv1.2 TLSv1.3;
# TLS 1.2安全密码套件(优先使用前向保密)
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
# 会话恢复
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# HSTS(严格传输安全)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# 安全响应头
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# 证书透明度
ssl_ct on;
}
Apache安全TLS配置:
apache
# Apache TLS安全配置
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/fullchain.pem
SSLCertificateKeyFile /etc/ssl/private/privkey.pem
# 仅允许TLS 1.2和1.3
SSLProtocol -all +TLSv1.2 +TLSv1.3
# 安全密码套件
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
SSLHonorCipherOrder on
# 会话恢复
SSLSessionCache shmcb:/var/cache/httpd/sslcache(512000)
SSLSessionCacheTimeout 300
# OCSP Stapling
SSLUseStapling on
SSLStaplingCache shmcb:/var/cache/httpd/sslstapling(512000)
# HSTS
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
# HTTP/2
Protocols h2 http/1.1
</VirtualHost>
【提示】 配置TLS后务必使用SSL Labs(https://www.ssllabs.com/ssltest/)进行评分,目标为A+评级。常见扣分项包括:支持旧版TLS、密码套件不安全、缺少HSTS头、未启用OCSP Stapling。
八、密码攻击技术
8.1 哈希破解方法分类
| 破解方法 | 原理 | 适用场景 | 速度 | 效果 |
|---|---|---|---|---|
| 字典攻击 | 使用预编密码字典逐个尝试 | 通用密码 | 快 | 中高 |
| 暴力破解 | 穷举所有可能字符组合 | 短密码/已知字符集 | 慢 | 高(受限于时间) |
| 彩虹表 | 预计算哈希链,空间换时间 | 无盐哈希 | 极快 | 高(仅限无盐) |
| 掩码攻击 | 指定密码模式(如?u?l?l?d?d?d?d) | 已知密码结构 | 中 | 高 |
| 规则攻击 | 对字典应用变换规则(大小写/追加等) | 变形密码 | 中 | 高 |
| 组合攻击 | 两个字典的组合 | 复合密码 | 慢 | 中 |
| 混合攻击 | 字典+掩码/暴力后缀 | 字典词+数字 | 中 | 中高 |
8.2 hashcat使用详解
hashcat是当前最强大的GPU加速密码破解工具,支持超过300种哈希类型。
bash
# === hashcat基本语法 ===
# hashcat [选项] 哈希文件 字典/掩码
# 常用选项
# -m <type> 指定哈希类型编号
# -a <mode> 指定攻击模式
# -o <file> 输出破解结果
# --force 忽略警告
# -r <file> 规则文件
# -w <1-4> 工作负载(1=低, 4=高)
# -O 优化内核(限制密码长度)
# --status 显示状态
# -I 显示GPU设备信息
# 查看GPU设备
hashcat -I
# 查看支持的哈希类型
hashcat --help | grep -i md5
hashcat --help | grep -i sha
hashcat --help | grep -i bcrypt
# === 攻击模式 ===
# -a 0 字典攻击(Straight)
hashcat -m 0 hashes.txt rockyou.txt
# -a 1 组合攻击(Combinatorial)
hashcat -m 0 hashes.txt dict1.txt dict2.txt
# -a 3 掩码攻击(Brute-force)
hashcat -m 0 hashes.txt ?a?a?a?a?a?a?a?a
# -a 6 混合攻击(字典+掩码后缀)
hashcat -m 0 hashes.txt rockyou.txt ?d?d?d?d
# -a 7 混合攻击(掩码前缀+字典)
hashcat -m 0 hashes.txt ?d?d?d rockyou.txt
# === 常见哈希类型编号 ===
# -m 0 MD5
# -m 100 SHA-1
# -m 1400 SHA-256
# -m 1700 SHA-512
# -m 1000 NTLM
# -m 1800 sha512crypt ($6$)
# -m 500 md5crypt ($1$)
# -m 3200 bcrypt ($2a$)
# -m 10900 PBKDF2-HMAC-SHA256
# -m 13400 Keepass
# -m 22000 WPA3
# -m 18200 ASN.1 ECDSA
| 攻击模式 | 编号 | 说明 | 命令示例 |
|---|---|---|---|
| 字典攻击 | -a 0 | 使用字典文件 | hashcat -m 0 -a 0 hash.txt dict.txt |
| 组合攻击 | -a 1 | 两个字典组合 | hashcat -m 0 -a 1 hash.txt d1.txt d2.txt |
| 掩码攻击 | -a 3 | 指定字符模式 | hashcat -m 0 -a 3 hash.txt ?u?l?l?d?d |
| 混合(字典+掩码) | -a 6 | 字典+掩码后缀 | hashcat -m 0 -a 6 hash.txt dict.txt ?d?d?d |
| 混合(掩码+字典) | -a 7 | 掩码前缀+字典 | hashcat -m 0 -a 7 hash.txt ?d?d dict.txt |
| 规则攻击 | -r | 字典+变换规则 | hashcat -m 0 hash.txt dict.txt -r rules.rule |
bash
# === 掩码字符集 ===
# ?l = abcdefghijklmnopqrstuvwxyz
# ?u = ABCDEFGHIJKLMNOPQRSTUVWXYZ
# ?d = 0123456789
# ?s = !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
# ?a = ?l?u?d?s
# ?b = 0x00 - 0xff(任意字节)
# 自定义字符集
hashcat -m 0 -a 3 hash.txt -1 ?d?l -2 ?d?l ?1?1?1?2?2?2
# -1 定义第一个自定义字符集
# -2 定义第二个自定义字符集
# 常见密码模式掩码
# 8位小写字母: ?l?l?l?l?l?l?l?l
# 6位数字密码: ?d?d?d?d?d?d
# 首字母大写+小写+4位数字: ?u?l?l?l?l?d?d?d?d
# 中国手机号: 1[3-9]????????? -> 1 -3 ?d?d?d?d?d?d?d?d?d
# === 规则文件示例 ===
# 创建 rules.rule 文件:
# : 原样输出
# l 转小写
# u 转大写
# c 首字母大写
# t 反转大小写
# r 反转字符串
# d 复制(wordword)
# $1 末尾追加1
# $2 末尾追加2
# ^a 开头插入a
# so 替换o为s
# so0 替换o为0(leet speak)
# 使用规则攻击
hashcat -m 0 hashes.txt rockyou.txt -r /usr/share/hashcat/rules/best64.rule
hashcat -m 0 hashes.txt rockyou.txt -r /usr/share/hashcat/rules/rockyou-30000.rule
# === 会话管理 ===
# 保存/恢复破解进度
hashcat -m 0 hashes.txt rockyou.txt --session mysession
hashcat --session mysession --restore
# === 性能优化 ===
# 增加工作负载
hashcat -m 0 hashes.txt rockyou.txt -w 4
# 优化内核(密码<=15位时)
hashcat -m 0 hashes.txt rockyou.txt -O
# 多GPU并行
hashcat -m 0 hashes.txt rockyou.txt -d 1,2,3,4
# === benchmark测试 ===
# 测试GPU破解速度
hashcat -m 0 --benchmark
hashcat -m 3200 --benchmark # bcrypt
hashcat -m 1000 --benchmark # NTLM
8.3 John the Ripper使用
bash
# John the Ripper - 另一款经典密码破解工具
# 基本使用
john --wordlist=rockyou.txt hashes.txt
# 自动识别哈希格式
john --format=raw-md5 --wordlist=rockyou.txt hashes.txt
# 常见格式
# --format=raw-md5 MD5
# --format=raw-sha1 SHA-1
# --format=raw-sha256 SHA-256
# --format=raw-sha512 SHA-512
# --format=bcrypt bcrypt
# --format=NT NTLM
# --format=sha512crypt $6$ (Linux shadow)
# --format=md5crypt $1$ (Linux shadow)
# 规则攻击
john --wordlist=rockyou.txt --rules hashes.txt
# 增量模式(暴力破解)
john --incremental hashes.txt
# 查看已破解结果
john --show hashes.txt
# 恢复会话
john --restore
# 影子文件破解
unshadow /etc/passwd /etc/shadow > hashes.txt
john --wordlist=rockyou.txt hashes.txt
# 使用OpenMP并行
john --fork=4 --wordlist=rockyou.txt hashes.txt
8.4 彩虹表生成与使用
bash
# === 彩虹表工具 ===
# rtgen - 生成彩虹表
# 语法: rtgen hash_algorithm charset table_index chain_len chain_num part_index
rtgen md5 loweralpha-numeric 0 3800 33554432 0
rtgen md5 loweralpha-numeric 1 3800 33554432 0
rtgen md5 loweralpha-numeric 2 3800 33554432 0
# rtsort - 排序彩虹表
rtsort .
# rcrack - 使用彩虹表破解
rcrack . -h 098f6bcd4621d373cade4e832627b4f6
rcrack . -l hash_list.txt
# 注意:彩虹表仅对无盐哈希有效
# bcrypt/scrypt/Argon2因有盐值,彩虹表攻击无效
8.5 哈希类型破解速度对比
| 哈希类型 | hashcat编号 | RTX 4090速度(H/s) | 特点 |
|---|---|---|---|
| MD5 | 0 | 约160,000,000,000 | 极快,秒级破解 |
| SHA-1 | 100 | 约70,000,000,000 | 极快 |
| SHA-256 | 1400 | 约25,000,000,000 | 快 |
| SHA-512 | 1700 | 约12,000,000,000 | 快 |
| NTLM | 1000 | 约80,000,000,000 | 极快 |
| MD5crypt (111) | 500 | 约5,000,000 | 中等 |
| SHA512crypt (666) | 1800 | 约150,000 | 慢 |
| bcrypt (2a2a2a, cost=12) | 3200 | 约20,000 | 很慢 |
| scrypt | 8900 | 约5,000 | 很慢 |
| Argon2id | 0 | 约3,000 | 最慢 |
| WPA2 | 22000 | 约2,500,000 | 中等 |
【提示】 从速度对比可以看出,MD5比bcrypt快约800万倍。一个8位字母数字密码,MD5在GPU上约0.6秒破解,而bcrypt需要约5天。这就是为什么密码存储必须使用慢哈希函数。
8.6 GPU破解配置与性能优化
bash
# === GPU驱动和CUDA配置 ===
# 安装NVIDIA驱动
sudo apt-get install nvidia-driver-535
# 安装CUDA Toolkit
sudo apt-get install nvidia-cuda-toolkit
# 验证GPU
nvidia-smi
# hashcat GPU调优
# 查看GPU温度和利用率
nvidia-smi -l 1
# 增加功耗限制(提升性能)
sudo nvidia-smi -pl 350 # RTX 4090可设到450W
# 超频(需谨慎)
nvidia-settings -a GPUGraphicsClockOffset[0]=100
nvidia-settings -a GPUMemoryTransferRateOffset[0]=1000
# hashcat性能优化技巧
# 1. 使用-O优化内核(密码<=15位)
# 2. 增加工作负载 -w 4
# 3. 调整GPU风扇转速
# 4. 使用多GPU并行 -d 1,2
# 5. 将哈希文件和字典放在SSD上
# 6. 使用 --session 管理长时间任务
# 7. 预处理字典:去重、排序
九、密码存储安全
9.1 密码存储方案演进
| 方案 | 示例 | 安全性 | 问题 |
|---|---|---|---|
| 明文存储 | password123 | 极低 | 数据库泄露即全部暴露 |
| Base64编码 | cGFzc3dvcmQxMjM= | 极低 | 仅编码不加密,可逆 |
| MD5哈希 | 482c811da5d5b4bc6d497ffa98491e38 | 低 | 彩虹表/字典秒破 |
| MD5+Salt | salt:abc hash:... | 中低 | GPU暴力破解仍可行 |
| SHA-256+Salt | ... | 中低 | GPU暴力破解仍可行 |
| bcrypt | $2a121212N9qo8u... | 高 | 可调成本,抗GPU |
| scrypt | scryptNNNrpppsalt$hash | 高 | 内存困难,抗ASIC |
| Argon2id | argon2idargon2idargon2idv=19$m=65536... | 最高 | 同时抗CPU和内存攻击 |
9.2 盐值与胡椒
python
import os
import hashlib
import hmac
import base64
import argon2
# === 盐值(Salt) ===
# 每个用户独立的随机值,存储在数据库中
# 防止彩虹表攻击,使相同密码产生不同哈希
def generate_salt(length: int = 16) -> bytes:
"""生成安全随机盐值"""
return os.urandom(length)
def hash_with_salt(password: str, salt: bytes) -> str:
"""SHA-256 + Salt(演示用,不推荐生产环境)"""
dk = hashlib.pbkdf2_hmac(
'sha256',
password.encode('utf-8'),
salt,
iterations=100000, # 10万次迭代
dklen=32
)
return base64.b64encode(dk).decode()
# === 胡椒(Pepper) ===
# 全局密钥,不在数据库中存储(存储在配置文件/HSM中)
# 数据库泄露后攻击者无法离线破解
PEPPER = os.environ.get('PASSWORD_PEPPER', b'default_pepper_change_me')
def hash_with_pepper(password: str, salt: bytes) -> str:
"""bcrypt + Pepper"""
import bcrypt
# 将pepper附加到密码后
peppered = password.encode('utf-8') + PEPPER
salt_bcrypt = bcrypt.gensalt(rounds=12)
return bcrypt.hashpw(peppered, salt_bcrypt).decode()
def verify_with_pepper(password: str, hashed: str) -> bool:
"""验证带pepper的密码"""
import bcrypt
peppered = password.encode('utf-8') + PEPPER
return bcrypt.checkpw(peppered, hashed.encode('utf-8'))
9.3 自适应哈希函数配置
| 函数 | 参数 | 推荐值 | 说明 |
|---|---|---|---|
| bcrypt | cost | 12-14 | 每增加1翻倍计算量,目标约250ms |
| scrypt | N | 2^14 (16384) | CPU/内存成本 |
| scrypt | r | 8 | 块大小 |
| scrypt | p | 1 | 并行参数 |
| Argon2id | t (time) | 3 | 迭代次数 |
| Argon2id | m (memory) | 65536 (64MB) | 内存使用量 |
| Argon2id | p (parallel) | 4 | 并行线程数 |
9.4 完整安全密码存储代码
python
# === Python实现 ===
import argon2
import os
import secrets
import base64
class PasswordManager:
"""安全的密码存储管理器"""
def __init__(self):
self.ph = argon2.PasswordHasher(
time_cost=3,
memory_cost=65536,
parallelism=4,
hash_len=32,
salt_len=16,
type=argon2.Type.ID # Argon2id
)
# Pepper应从安全配置或HSM读取
self._pepper = os.environ.get('APP_PEPPER', '').encode('utf-8')
def hash_password(self, password: str) -> str:
"""安全哈希密码"""
# 应用pepper
peppered = password + self._pepper.decode('utf-8')
return self.ph.hash(peppered)
def verify_password(self, password: str, stored_hash: str) -> bool:
"""验证密码"""
peppered = password + self._pepper.decode('utf-8')
try:
self.ph.verify(stored_hash, peppered)
return True
except argon2.exceptions.VerifyMismatchError:
return False
except argon2.exceptions.InvalidHash:
return False
def needs_rehash(self, stored_hash: str) -> bool:
"""检查是否需要重新哈希(参数变更后)"""
return self.ph.check_needs_rehash(stored_hash)
# 使用示例
pm = PasswordManager()
hashed = pm.hash_password("MySecurePassword123!")
print(f"存储哈希: {hashed}")
print(f"验证正确密码: {pm.verify_password('MySecurePassword123!', hashed)}")
print(f"验证错误密码: {pm.verify_password('WrongPassword', hashed)}")
java
// === Java实现 ===
import de.mkammerer.argon2.Argon2;
import de.mkammerer.argon2.Argon2Factory;
import java.security.SecureRandom;
import java.util.Base64;
public class PasswordManager {
private static final Argon2 argon2 = Argon2Factory.create(Argon2Types.ARGON2id);
private static final int ITERATIONS = 3;
private static final int MEMORY = 65536; // 64MB
private static final int PARALLELISM = 4;
private static final int SALT_LENGTH = 16;
private static final int HASH_LENGTH = 32;
private final String pepper;
public PasswordManager(String pepper) {
this.pepper = pepper;
}
public String hashPassword(String password) {
String peppered = password + pepper;
// argon2库自动处理盐值生成和格式化
return argon2.hash(ITERATIONS, MEMORY, PARALLELISM, peppered);
}
public boolean verifyPassword(String password, String storedHash) {
String peppered = password + pepper;
try {
return argon2.verify(storedHash, peppered);
} catch (Exception e) {
return false;
}
}
}
javascript
// === Node.js实现 ===
const argon2 = require('argon2');
class PasswordManager {
constructor() {
this.options = {
type: argon2.argon2id,
timeCost: 3,
memoryCost: 65536,
parallelism: 4,
hashLength: 32,
saltLength: 16
};
this.pepper = process.env.APP_PEPPER || '';
}
async hashPassword(password) {
const peppered = password + this.pepper;
return await argon2.hash(peppered, this.options);
}
async verifyPassword(password, storedHash) {
const peppered = password + this.pepper;
try {
return await argon2.verify(storedHash, peppered);
} catch (err) {
return false;
}
}
}
// 使用示例
(async () => {
const pm = new PasswordManager();
const hash = await pm.hashPassword('MySecurePassword123!');
console.log('存储哈希:', hash);
const valid = await pm.verifyPassword('MySecurePassword123!', hash);
console.log('验证结果:', valid);
})();
9.5 密码策略设计
text
密码策略最佳实践(NIST SP 800-63B):
1. 最小长度:至少8位(建议12位以上)
2. 最大长度:至少支持64位(不截断)
3. 字符集:允许所有ASCII和Unicode字符
4. 复杂度:不再强制要求大小写/数字/特殊字符混合
5. 黑名单:检查常见密码(如rockyou前10000)
6. 过期策略:不再要求定期更换(除非泄露)
7. 粘性密码:禁止使用上次密码
8. 错误锁定:5次错误后锁定15分钟(防暴力)
9. 二次认证:推荐TOTP/WebAuthn
10. 密码强度计:使用zxcvbn评估实际熵
十、加密通信实现
10.1 端到端加密(E2EE)原理
text
端到端加密核心原则:
1. 加密和解密只在通信双方(终端)进行
2. 服务器只转发密文,无法解密内容
3. 即使服务器被入侵,通信内容仍然安全
4. 前向保密:即使长期密钥泄露,过去的通信也无法解密
典型E2EE系统:
- Signal Protocol(WhatsApp/Signal/Facebook Messenger E2EE)
- PGP/GPG(邮件加密)
- OMEMO(XMPP)
- Matrix(端到端加密聊天)
- WebRTC(DTLS-SRTP)
10.2 Signal协议详解
text
Signal协议三大核心组件:
1. X3DH(Extended Triple Diffie-Hellman)- 初始密钥协商
- 利用预发布密钥实现异步密钥交换
- Alice无需Bob在线即可建立会话
- 组合DH计算:DH1 = DH(IK_A, SPK_B), DH2 = DH(EK_A, IK_B),
DH3 = DH(EK_A, SPK_B), DH4 = DH(EK_A, OPK_B)
- SK = KDF(DH1 || DH2 || DH3 || DH4)
2. Double Ratchet - 持续密钥更新
- 对称密钥棘轮:每条消息使用新密钥(前向保密)
- DH棘轮:每次方向切换时更新DH密钥对(后向安全)
- 即使一条消息密钥泄露,其他消息仍然安全
3. XEdDSA和VEdDSA - 签名方案
- 基于Ed25519,支持同一密钥对既做DH又做签名
10.3 PGP/GPG加密实战
bash
# === GnuPG (GPG) 操作 ===
# 生成密钥对
gpg --full-generate-key
# 选择密钥类型(RSA和RSA)
# 密钥长度(3072或4096)
# 有效期(0=永不过期)
# 姓名、邮箱、注释
# 查看密钥
gpg --list-keys
gpg --list-secret-keys
# 导出公钥
gpg --export --armor alice@example.com > alice_public.asc
# 导入他人公钥
gpg --import bob_public.asc
# 从密钥服务器获取
gpg --keyserver keys.openpgp.org --recv-keys KEY_ID
# 加密文件
gpg --encrypt --recipient bob@example.com message.txt
# 加密并签名
gpg --encrypt --sign --recipient bob@example.com message.txt
# 解密文件
gpg --decrypt message.txt.gpg > decrypted.txt
# 签名文件
gpg --sign document.txt # 生成 document.txt.gpg
gpg --detach-sign document.txt # 生成 document.txt.sig
gpg --clearsign document.txt # 生成带签名的文本
# 验证签名
gpg --verify document.txt.sig document.txt
gpg --verify document.txt.asc
# 加密目录(先压缩)
tar czf - secret_dir/ | gpg --encrypt --recipient alice@example.com -o secret.tar.gz.gpg
gpg --decrypt secret.tar.gz.gpg | tar xzf -
# 对称加密(密码加密,无需密钥对)
gpg --symmetric --cipher-algo AES256 secret.txt
gpg --decrypt secret.txt.gpg
10.4 SSH密钥管理与安全配置
bash
# === SSH密钥管理 ===
# 生成Ed25519密钥(推荐)
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519 -C "alice@example.com"
# 生成RSA密钥(兼容旧系统)
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa -C "alice@example.com"
# 生成ECDSA密钥
ssh-keygen -t ecdsa -b 521 -f ~/.ssh/id_ecdsa -C "alice@example.com"
# 复制公钥到远程服务器
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
# 手动添加公钥
cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
# 使用硬件密钥(YubiKey)
ssh-keygen -t ed25519-sk -f ~/.ssh/id_ed25519_sk
# === SSH安全配置 (/etc/ssh/sshd_config) ===
# 仅允许密钥认证
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin prohibit-password
# 仅允许Ed25519和RSA密钥
PubkeyAcceptedKeyTypes ssh-ed25519,rsa-sha2-512,rsa-sha2-256
# 禁用不安全的密钥交换和MAC
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
# 限制登录用户
AllowUsers alice bob
AllowGroups ssh-users
# 登录限制
MaxAuthTries 3
LoginGraceTime 30
MaxStartups 10:30:60
# 审计日志
LogLevel VERBOSE
SyslogFacility AUTHPRIV
# 空闲超时
ClientAliveInterval 300
ClientAliveCountMax 0
10.5 age加密工具
bash
# age - 现代文件加密工具(比GPG更简单安全)
# 安装:go install filippo.io/age/cmd/age@latest
# 生成密钥对
age-keygen -o age.key
# 加密文件(使用公钥)
age -r age1ql3z7hjy54pw3hy... recipient.txt -o encrypted.age
# 加密文件(使用密码)
age -p secret.txt -o encrypted.age
# 解密
age -d -i age.key encrypted.age > decrypted.txt
# 加密给多个收件人
age -r age1ql3z... -r age1xy9pw... secret.txt -o encrypted.age
# SSH密钥加密(age可使用SSH公钥)
age -R ~/.ssh/id_ed25519.pub secret.txt -o encrypted.age
age -d -i ~/.ssh/id_ed25519 encrypted.age
十一、密码学漏洞实战
11.1 弱随机数漏洞
python
import random
import os
import time
# === 危险:使用random模块生成密钥 ===
def insecure_random_key():
"""不安全的随机数生成"""
# random模块基于Mersenne Twister,可预测
key = random.randint(0, 2**256)
return key
def predict_random_seed():
"""演示random模块的可预测性"""
# 如果攻击者知道大约的生成时间
approximate_time = int(time.time())
# 可以爆破种子
for seed in range(approximate_time - 60, approximate_time + 60):
r = random.Random(seed)
candidate = r.randint(0, 2**256)
if candidate == target_key:
print(f"找到种子: {seed}")
break
# === 安全:使用密码学安全随机数 ===
def secure_random_key():
"""安全的随机数生成"""
# 使用操作系统的CSPRNG
key = os.urandom(32) # 256位密钥
return key
# Python secrets模块(3.6+)
import secrets
def secure_token():
"""生成安全令牌"""
token = secrets.token_hex(32) # 64字符十六进制
url_token = secrets.token_urlsafe(32) # URL安全的Base64
return token, url_token
bash
# Linux随机数源对比:
# /dev/random - 阻塞式,熵不足时等待(不推荐)
# /dev/urandom - 非阻塞,使用CSPRNG(推荐,永远不返回低质量随机数)
# getrandom(2) - 系统调用,现代推荐方式
# 验证随机数质量
cat /dev/urandom | rngtest -c 1000
# 查看熵池大小
cat /proc/sys/kernel/random/entropy_avail
11.2 ECB模式信息泄露
python
"""
ECB模式信息泄露演示
相同的明文块加密后产生相同的密文块
导致密文中泄露了明文的结构信息
"""
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from PIL import Image
import numpy as np
def ecb_image_leak():
"""演示ECB模式加密图像后的信息泄露"""
# 加载图像(灰度图)
img = Image.open('plain_image.bmp').convert('L')
pixels = np.array(img)
# 将像素转换为字节
data = pixels.tobytes()
key = b'SixteenByteKey!!'
# ECB加密
cipher_ecb = AES.new(key, AES.MODE_ECB)
encrypted_ecb = cipher_ecb.encrypt(pad(data, 16))
# CBC加密
from Crypto.Random import get_random_bytes
iv = get_random_bytes(16)
cipher_cbc = AES.new(key, AES.MODE_CBC, iv=iv)
encrypted_cbc = cipher_cbc.encrypt(pad(data, 16))
# ECB加密后的图像仍然可见轮廓
# CBC加密后的图像是随机噪声
print("ECB加密结果中图像轮廓清晰可见!")
print("CBC加密结果为随机噪声,安全。")
# 著名的ECB Tux(企鹅)图像就是此漏洞的经典演示
11.3 CBC Padding Oracle攻击
python
"""
CBC Padding Oracle攻击完整实现
利用解密时的填充错误提示来逐字节恢复明文
攻击条件:
1. 目标使用CBC模式加密
2. 攻击者可发送任意密文给服务器
3. 服务器返回不同的错误信息(填充错误 vs 解密错误)
攻击原理:
修改前一个密文块的某字节,观察填充是否正确
当填充正确时,被修改字节对应的解密值为特定值
通过推算可恢复明文字节
"""
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
class PaddingOracleServer:
"""模拟存在Padding Oracle漏洞的服务器"""
def __init__(self):
self.key = get_random_bytes(16)
self.iv = get_random_bytes(16)
self.cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
def encrypt(self, plaintext: bytes) -> bytes:
"""加密"""
ct = self.cipher.encrypt(pad(plaintext, 16))
return self.iv + ct
def decrypt_and_check(self, ciphertext: bytes) -> bool:
"""返回True=填充正确, False=填充错误"""
iv = ciphertext[:16]
ct = ciphertext[16:]
cipher = AES.new(self.key, AES.MODE_CBC, iv=iv)
try:
pt = cipher.decrypt(ct)
unpad(pt, 16) # 如果填充不正确会抛出异常
return True
except (ValueError, KeyError):
return False
def padding_oracle_attack(server: PaddingOracleServer, ciphertext: bytes) -> bytes:
"""Padding Oracle攻击 - 逐字节恢复明文"""
iv = ciphertext[:16]
ct_blocks = [ciphertext[i:i+16] for i in range(16, len(ciphertext), 16)]
recovered = b''
for block_idx, ct_block in enumerate(ct_blocks):
prev_block = iv if block_idx == 0 else ct_blocks[block_idx - 1]
intermediate = bytearray(16) # 中间值
for byte_pos in range(15, -1, -1):
padding_value = 16 - byte_pos # 期望的填充值
for guess in range(256):
# 构造修改后的前一个块
modified = bytearray(16)
# 已知的中间值部分
for k in range(byte_pos + 1, 16):
modified[k] = intermediate[k] ^ padding_value
modified[byte_pos] = guess
# 发送给服务器
test_ct = bytes(modified) + ct_block
if server.decrypt_and_check(test_ct):
# 填充正确,计算中间值
intermediate[byte_pos] = guess ^ padding_value
break
# 恢复明文
plaintext_block = bytes(a ^ b for a, b in zip(intermediate, prev_block))
recovered += plaintext_block
print(f"块 {block_idx} 恢复: {plaintext_block}")
return recovered
# 攻击示例
if __name__ == '__main__':
server = PaddingOracleServer()
secret = b"Padding Oracle Attack is very powerful!"
ciphertext = server.encrypt(secret)
print(f"密文长度: {len(ciphertext)}")
print("开始Padding Oracle攻击...")
recovered = padding_oracle_attack(server, ciphertext)
print(f"\n恢复的明文: {recovered}")
11.4 RSA低指数攻击
python
"""
RSA低指数攻击(Håstad广播攻击)
当e=3且同一消息发送给3个接收者时
使用中国剩余定理(CRT)可恢复明文
"""
from sympy.ntheory.modular import crt
def rsa_low_exponent_attack():
"""e=3的Håstad广播攻击"""
# 三个不同的RSA公钥(相同e=3,不同n)
e = 3
n1 = 1000000007 * 1000000009 # 简化示例
n2 = 1000000007 * 1000000033
n3 = 1000000007 * 1000000087
# 实际应使用大数,此处仅为演示
# 假设消息m < min(n1, n2, n3)
m = 42
# 加密三次
c1 = pow(m, e, n1)
c2 = pow(m, e, n2)
c3 = pow(m, e, n3)
# 使用CRT求解 m^3 ≡ c1 (mod n1), m^3 ≡ c2 (mod n2), m^3 ≡ c3 (mod n3)
moduli = [n1, n2, n3]
remainders = [c1, c2, c3]
result, _ = crt(moduli, remainders)
# m^3 = result,所以 m = result^(1/3)
m_recovered = round(result ** (1.0 / e))
print(f"原始消息: {m}")
print(f"恢复消息: {m_recovered}")
assert m == m_recovered
print("\n防御方案:")
print("1. 使用e=65537而非e=3")
print("2. 使用OAEP填充(使每次加密结果不同)")
rsa_low_exponent_attack()
11.5 RSA共模攻击
python
"""
RSA共模攻击
同一明文用相同模数n但不同指数e1, e2加密
当gcd(e1, e2)=1时,可用扩展欧几里得算法恢复明文
"""
from math import gcd
def extended_gcd(a, b):
"""扩展欧几里得算法"""
if a == 0:
return b, 0, 1
g, x, y = extended_gcd(b % a, a)
return g, y - (b // a) * x, x
def rsa_common_modulus_attack():
"""RSA共模攻击"""
# 相同模数n,不同指数e1, e2
p, q = 61, 53
n = p * q # n = 3233
e1 = 17
e2 = 23 # gcd(17, 23) = 1
# 明文
m = 65
# 加密
c1 = pow(m, e1, n)
c2 = pow(m, e2, n)
# 攻击:找到 a, b 使 a*e1 + b*e2 = 1
g, a, b = extended_gcd(e1, e2)
# 确保 a > 0
if a < 0:
c1 = pow(c1, -1, n) # 模逆
a = -a
if b < 0:
c2 = pow(c2, -1, n)
b = -b
# m = c1^a * c2^b mod n
m_recovered = (pow(c1, a, n) * pow(c2, b, n)) % n
print(f"原始消息: {m}")
print(f"恢复消息: {m_recovered}")
assert m == m_recovered
print("\n防御方案:")
print("1. 不同用户使用不同的模数n")
print("2. 永远不要在多个系统间共享RSA模数")
rsa_common_modulus_attack()
11.6 AES密钥固定与IV重用攻击
python
"""
AES-GCM中Nonce重用攻击
GCM模式下Nonce重用会导致灾难性后果:
1. 相同Nonce下,相同明文产生相同密文(信息泄露)
2. 攻击者可恢复认证密钥H,伪造任意消息(完全破坏认证)
3. 多组密文异或可恢复明文异或(两时间密码本攻击)
"""
def gcm_nonce_reuse_demo():
"""演示GCM Nonce重用的危险"""
from Crypto.Cipher import AES
key = b'SixteenByteKey!!'
nonce = b'Fixed12byteN' # 固定Nonce(危险!)
# 加密两条消息(使用相同key和nonce)
cipher1 = AES.new(key, AES.MODE_GCM, nonce=nonce)
ct1, tag1 = cipher1.encrypt_and_digest(b'Message one: secret')
cipher2 = AES.new(key, AES.MODE_GCM, nonce=nonce)
ct2, tag2 = cipher2.encrypt_and_digest(b'Message two: public')
# 攻击者可计算 ct1 XOR ct2 = pt1 XOR pt2
# 已知一个明文即可恢复另一个
known_pt = b'Message two: public'
recovered_pt = bytes(a ^ b ^ c for a, b, c in zip(ct1, ct2, known_pt))
print(f"恢复的明文1: {recovered_pt}")
# 输出: b'Message one: secret'
print("\n防御方案:")
print("1. 每次加密使用不同的随机Nonce")
print("2. 使用计数器作为Nonce(确保不重复)")
print("3. GCM的Nonce在同一密钥下绝对不能重用")
gcm_nonce_reuse_demo()
11.7 时序攻击
python
"""
时序攻击 - 利用密码比较的时间差泄露信息
不安全的比较函数在第一个不匹配字节处返回
攻击者可逐字节爆破
"""
import time
import hmac
def insecure_compare(a: bytes, b: bytes) -> bool:
"""不安全的比较(存在时序泄露)"""
if len(a) != len(b):
return False
for i in range(len(a)):
if a[i] != b[i]:
return False # 第一个不匹配就返回
time.sleep(0.001) # 模拟处理延迟
return True
def timing_attack(target: bytes, length: int) -> bytes:
"""时序攻击恢复目标值"""
recovered = bytearray(length)
for pos in range(length):
best_byte = 0
best_time = 0
for guess in range(256):
test = bytearray(recovered)
test[pos] = guess
start = time.time()
insecure_compare(bytes(test), target)
elapsed = time.time() - start
if elapsed > best_time:
best_time = elapsed
best_byte = guess
recovered[pos] = best_byte
print(f"位置 {pos}: 0x{best_byte:02x} (耗时 {best_time:.4f}s)")
return bytes(recovered)
# 防御方案:使用恒定时间比较
def secure_compare(a: bytes, b: bytes) -> bool:
"""安全的恒定时间比较"""
return hmac.compare_digest(a, b)
# Python的hmac.compare_digest使用C实现的恒定时间比较
# Java: java.security.MessageDigest.isEqual()
# JavaScript: 使用crypto.timingSafeEqual()
# Go: crypto/subtle.ConstantTimeCompare()
十二、国密算法实践
12.1 国密算法概览
| 算法 | 类型 | 标准号 | 对标国际算法 | 密钥长度 | 说明 |
|---|---|---|---|---|---|
| SM2 | 非对称 | GB/T 32918 | RSA/ECC | 256位 | 椭圆曲线公钥密码 |
| SM3 | 哈希 | GB/T 32905 | SHA-256 | - | 输出256位 |
| SM4 | 对称 | GB/T 32907 | AES | 128位 | 分组密码 |
| SM9 | 标识 | GB/T 32918 | IBC | 256位 | 标识密码算法 |
| ZUC | 流密码 | GB/T 32933 | SNOW 3G | 128位 | 祖冲之序列密码 |
12.2 GmSSL使用
bash
# GmSSL是支持国密算法的OpenSSL分支
# 安装GmSSL
git clone https://github.com/guanzhi/GmSSL.git
cd GmSSL
mkdir build && cd build
cmake ..
make && sudo make install
# 生成SM2密钥对
gmssl ecparam -genkey -name sm2p256v1 -out sm2_key.pem
# 生成SM2证书请求
gmssl req -new -key sm2_key.pem -out sm2_req.csr -subj "/C=CN/CN=example.com"
# 使用SM3计算哈希
gmssl dgst -sm3 file.txt
# 使用SM4加密
gmssl enc -sm4 -in plaintext.txt -out encrypted.bin -K 0123456789abcdef0123456789abcdef -iv 0123456789abcdef0123456789abcdef
# 生成SM2自签名证书
gmssl req -x509 -sm3 -key sm2_key.pem -out sm2_cert.pem -days 365 -subj "/C=CN/CN=example.com"
# 查看SM2证书
gmssl x509 -in sm2_cert.pem -text -noout
12.3 国密算法Python实现
python
# pip install gmssl
from gmssl import sm2, sm3, sm4, func
import os
class GMSuite:
"""国密算法套件"""
@staticmethod
def sm2_keygen():
"""SM2密钥生成"""
priv = func.random_hex(64)
sm2_obj = sm2.CryptSM2(private_key=priv, public_key='')
pub = sm2_obj._kg(int(priv, 16), func.sm2_para())
return priv, '%064x' % pub
@staticmethod
def sm2_encrypt_decrypt_demo():
"""SM2加解密演示"""
priv, pub = GMSuite.sm2_keygen()
message = b"SM2国密加密测试"
# 加密(使用公钥)
sm2_enc = sm2.CryptSM2(public_key=pub, private_key='')
ciphertext = sm2_enc.encrypt(message)
# 解密(使用私钥)
sm2_dec = sm2.CryptSM2(private_key=priv, public_key=pub)
plaintext = sm2_dec.decrypt(ciphertext)
print(f"原始: {message}")
print(f"解密: {plaintext}")
assert message == plaintext
@staticmethod
def sm3_hash_demo():
"""SM3哈希"""
message = "SM3哈希算法测试"
data = func.bytes_to_list(message.encode('utf-8'))
hash_val = sm3.sm3_hash(data)
print(f"SM3({message}) = {hash_val}")
@staticmethod
def sm4_encrypt_decrypt_demo():
"""SM4加解密"""
key = os.urandom(16)
iv = os.urandom(16)
message = b"SM4分组加密测试数据"
# CBC模式加密
sm4_enc = sm4.CryptSM4()
sm4_enc.set_key(key, sm4.SM4_ENCRYPT)
ciphertext = sm4_enc.crypt_cbc(iv, message)
# CBC模式解密
sm4_dec = sm4.CryptSM4()
sm4_dec.set_key(key, sm4.SM4_DECRYPT)
plaintext = sm4_dec.crypt_cbc(iv, ciphertext)
print(f"原始: {message}")
print(f"解密: {plaintext}")
assert message == plaintext
# 运行所有国密演示
suite = GMSuite()
suite.sm2_encrypt_decrypt_demo()
suite.sm3_hash_demo()
suite.sm4_encrypt_decrypt_demo()
12.4 国密合规要求
text
国密合规要求要点:
1. 关键信息基础设施必须使用国密算法
- 金融、政务、能源、交通等关键领域
- SM2替代RSA/ECC
- SM3替代SHA-256
- SM4替代AES
2. 商密产品认证
- 商用密码产品需通过国家密码管理局认证
- 获得商密产品型号证书
3. 等保2.0密码要求
- 三级以上系统需使用密码技术保护
- 数据传输和存储加密
- 身份认证使用密码技术
4. 密码应用安全性评估(密评)
- 对密码算法、协议、密钥、产品的合规性评估
- 依据GM/T 0054标准
5. SSL/IPSec中的国密套件
- ECC-SM4-SM3(国密TLS套件)
- ECDHE-SM4-SM3
- 国密双证书(签名证书+加密证书)
十三、量子计算与后量子密码
13.1 量子计算对密码学威胁
| 算法类型 | 代表算法 | 量子威胁 | 量子算法 | 影响 |
|---|---|---|---|---|
| RSA | RSA-2048 | 严重 | Shor算法 | 多项式时间分解大整数 |
| ECC | P-256 | 严重 | Shor算法 | 多项式时间解ECDLP |
| DH | DH-2048 | 严重 | Shor算法 | 多项式时间解DLP |
| AES | AES-128 | 中等 | Grover算法 | 安全性减半(128→64位) |
| AES | AES-256 | 低 | Grover算法 | 安全性减半(256→128位) |
| SHA-256 | SHA-256 | 低 | Grover算法 | 碰撞安全性减半 |
| ChaCha20 | ChaCha20 | 低 | Grover算法 | 安全性减半 |
13.2 Shor算法与Grover算法原理
text
Shor算法(大整数分解):
1. 选择随机数a,计算gcd(a, N)
2. 若gcd != 1,已找到因子
3. 使用量子傅里叶变换找a的阶r(a^r ≡ 1 mod N)
4. 若r为偶数,gcd(a^(r/2) + 1, N)或gcd(a^(r/2) - 1, N)可能是N的因子
5. 量子计算机可在多项式时间内执行步骤3
经典复杂度:O(e^(logN)^(1/3))
量子复杂度:O((logN)^3) ← 指数级加速
Grover算法(无序搜索):
1. 经典搜索N个元素的数据库需O(N)次查询
2. Grover算法仅需O(sqrt(N))次量子查询
3. 对密码学的影响:
- AES-128的密钥空间2^128 → 2^64次量子操作(仍安全但余量减小)
- AES-256仍然安全(2^128次量子操作)
- 哈希碰撞搜索:2^(n/2) → 2^(n/3)(轻微影响)
13.3 NIST后量子密码标准
NIST于2016年发起后量子密码标准化竞赛,2024年发布了第一批标准:
| 算法 | 类型 | 标准编号 | 数学基础 | 说明 |
|---|---|---|---|---|
| ML-KEM (CRYSTALS-Kyber) | 密钥封装 | FIPS 203 | 模格学习(MLWE) | 替代RSA/ECDH密钥交换 |
| ML-DSA (CRYSTALS-Dilithium) | 数字签名 | FIPS 204 | 模格学习(MLWE) | 替代RSA/ECDSA签名 |
| SLH-DSA (SPHINCS+) | 数字签名 | FIPS 205 | 哈希签名 | 基于哈希,最保守 |
| Falcon | 数字签名 | FIPS 206(草案) | NTRU格 | 紧凑签名尺寸 |
python
"""
后量子密码迁移策略
1. 混合模式(Hybrid Mode)
- 同时使用经典算法和后量子算法
- 安全性等于两者交集(任一安全即安全)
- 平滑过渡,兼容现有系统
2. 密码敏捷性(Crypto Agility)
- 系统设计时预留算法替换能力
- 配置化而非硬编码算法选择
- 便于快速切换到新标准
3. 优先级排序
- 长期数据(>10年保密期):优先迁移
- 签名/证书:需要提前规划(证书有效期长)
- 实时通信:最后迁移(前向保密已提供保护)
4. TLS中的后量子
- Cloudflare已部署Kyber+X25519混合密钥交换
- Google Chrome已支持后量子TLS
- 预计2025-2030年广泛部署
"""
# 使用liboqs进行后量子加密(实验性)
# pip install oqs
def post_quantum_demo():
"""后量子密钥封装示例"""
try:
import oqs
# 使用ML-KEM (Kyber)
with oqs.KeyEncapsulation('ML-KEM-768') as client:
public_key = client.generate_keypair()
ciphertext, shared_secret_server = client.encap_secret(public_key)
shared_secret_client = client.decap_secret(ciphertext)
print(f"ML-KEM-768公钥长度: {len(public_key)}字节")
print(f"密文长度: {len(ciphertext)}字节")
print(f"共享密钥匹配: {shared_secret_client == shared_secret_server}")
except ImportError:
print("请安装liboqs-python: pip install oqs")
【提示】 量子计算威胁是真实但渐进的。目前最强大的量子计算机(IBM Condor,1121量子比特)仍远不足以破解RSA-2048(需要数百万逻辑量子比特)。但"先收集后解密"(Harvest Now, Decrypt Later)攻击已经在进行------攻击者现在收集加密数据,等量子计算机成熟后再解密。因此长期保密数据需要尽快采用后量子密码。
十四、总结与参考资源
14.1 密码学安全检查清单
| 检查项 | 要求 | 状态 |
|---|---|---|
| 对称加密算法 | 使用AES-GCM或ChaCha20-Poly1305 | 需检查 |
| 加密模式 | 禁止ECB,推荐AEAD模式 | 需检查 |
| 对称密钥长度 | AES至少128位,推荐256位 | 需检查 |
| 非对称密钥长度 | RSA至少2048位,ECC至少256位 | 需检查 |
| 哈希算法 | 禁止MD5/SHA-1用于安全用途 | 需检查 |
| 密码存储 | 使用Argon2id/bcrypt/scrypt | 需检查 |
| 随机数生成 | 使用CSPRNG(os.urandom/secrets) | 需检查 |
| TLS版本 | 仅允许TLS 1.2和1.3 | 需检查 |
| 证书签名 | 使用SHA-256以上签名算法 | 需检查 |
| IV/Nonce使用 | 加密模式下IV/Nonce不可重用 | 需检查 |
| 密钥管理 | 密钥不硬编码,使用KMS/HSM | 需检查 |
| 填充方案 | 使用OAEP而非PKCS1v1.5 | 需检查 |
| HMAC比较 | 使用恒定时间比较 | 需检查 |
| 前向保密 | TLS使用ECDHE密钥交换 | 需检查 |
14.2 哈希破解速查表
| 任务 | hashcat命令 |
|---|---|
| MD5字典攻击 | hashcat -m 0 -a 0 hash.txt rockyou.txt |
| SHA-256字典攻击 | hashcat -m 1400 -a 0 hash.txt rockyou.txt |
| NTLM破解 | hashcat -m 1000 -a 0 hash.txt rockyou.txt |
| bcrypt破解 | hashcat -m 3200 -a 0 hash.txt rockyou.txt |
| 8位数字MD5 | hashcat -m 0 -a 3 hash.txt ?d?d?d?d?d?d?d?d |
| 首字母大写+小写+4数字 | hashcat -m 0 -a 3 hash.txt ?u?l?l?l?l?d?d?d?d |
| 字典+规则变换 | hashcat -m 0 hash.txt dict.txt -r best64.rule |
| 字典+4位数字后缀 | hashcat -m 0 -a 6 hash.txt dict.txt ?d?d?d?d |
| WPA2握手包 | hashcat -m 22000 hash.hccapx rockyou.txt |
| 性能测试 | hashcat -m 0 --benchmark |
14.3 OpenSSL速查表
| 任务 | OpenSSL命令 |
|---|---|
| 生成RSA私钥 | openssl genrsa -out key.pem 2048 |
| 生成CSR | openssl req -new -key key.pem -out req.csr |
| 自签名证书 | openssl req -x509 -key key.pem -out cert.pem -days 365 |
| 查看证书 | openssl x509 -in cert.pem -text -noout |
| 验证证书链 | openssl verify -CAfile ca.pem cert.pem |
| PEM转PKCS12 | openssl pkcs12 -export -out cert.p12 -inkey key.pem -in cert.pem |
| 查看远程证书 | `echo |
| 计算文件SHA256 | openssl dgst -sha256 file.txt |
| AES加密文件 | openssl enc -aes-256-cbc -in file.txt -out enc.bin |
| 生成随机数 | openssl rand -hex 32 |
14.4 参考资源
| 资源类型 | 名称 | 说明 |
|---|---|---|
| 标准 | NIST FIPS 197 | AES标准文档 |
| 标准 | NIST FIPS 203/204/205 | 后量子密码标准 |
| 标准 | GB/T 32907/32905/32918 | 国密SM4/SM3/SM2标准 |
| RFC | RFC 8446 | TLS 1.3规范 |
| RFC | RFC 8032 | EdDSA签名算法 |
| 书籍 | 《应用密码学》Bruce Schneier | 密码学经典教材 |
| 书籍 | 《Real-World Cryptography》 | 现代密码学实践 |
| 书籍 | 《Serious Cryptography》JP Aumasson | 密码学工程实践 |
| 工具 | OpenSSL/GmSSL | 密码学工具箱 |
| 工具 | hashcat | GPU密码破解 |
| 工具 | John the Ripper | 密码破解 |
| 在线 | SSL Labs | TLS配置检测 |
| 在线 | CrackStation | 在线哈希查询 |
| 在线 | crt.sh | 证书透明度查询 |
| 库 | PyCryptodome | Python密码学库 |
| 库 | libsodium | 现代密码学库 |
| 库 | Tink | Google密码学库 |
【提示】 本文所有技术内容仅用于授权测试、安全研究和学习目的。密码学是安全体系的最后一道防线,正确使用密码学技术可以有效保护数据安全,但密码学的任何误用都可能导致灾难性的安全事件。在实际项目中,建议使用经过广泛验证的密码学库(如libsodium、Tink),而非自行实现密码算法。始终遵循"不要自己发明密码学"的原则,并定期关注NIST、IETF等标准组织的最新安全建议,及时更新算法和配置以应对新的安全威胁。

