加密模块
Python 标准库提供了 hashlib(哈希摘要)和 hmac(消息认证码)两个加密相关模块,用于密码存储、数据完整性校验和通信认证。
hashlib — 哈希摘要
哈希(摘要)算法将任意长度的数据映射为固定长度的字节串,具有单向性(不可逆)和雪崩效应(原文微小改动导致摘要完全不同)。
常用算法:
| 算法 | 摘要长度 | 安全性 | 适用场景 |
|---|---|---|---|
| MD5 | 128 bit / 32 hex | 弱(已碰撞) | 文件校验(非安全场景) |
| SHA-1 | 160 bit / 40 hex | 弱 | 遗留系统 |
| SHA-256 | 256 bit / 64 hex | 强 | 密码存储、数字签名 |
| SHA-512 | 512 bit / 128 hex | 很强 | 高安全要求 |
基本用法
import hashlib
# MD5
h = hashlib.md5()
h.update("hello world".encode("utf-8"))
print(h.hexdigest()) # 5eb63bbbe01eeed093cb22bb8f5acdc3(32 hex)
# SHA-256(推荐)
h = hashlib.sha256("hello world".encode("utf-8"))
print(h.hexdigest()) # 十六进制字符串,64 位
# 等价的简写形式
digest = hashlib.sha256(b"hello world").hexdigest()
print(digest)加盐(Salt)
直接对密码哈希容易被彩虹表破解,加盐可以提高安全性:
import hashlib
import os
def hash_password(password: str, salt: bytes | None = None) -> tuple[str, bytes]:
"""对密码加盐哈希,返回 (hexdigest, salt)。"""
if salt is None:
salt = os.urandom(32) # 随机生成 32 字节盐值
h = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt, iterations=260_000)
return h.hex(), salt
def verify_password(password: str, stored_hash: str, salt: bytes) -> bool:
"""验证密码是否正确。"""
h, _ = hash_password(password, salt)
return h == stored_hash
# 存储密码
pwd_hash, salt = hash_password("my_secret_password")
print(f"Hash: {pwd_hash}")
# 验证密码
ok = verify_password("my_secret_password", pwd_hash, salt)
print(f"验证通过: {ok}") # True生产环境存储密码推荐使用
hashlib.pbkdf2_hmac(PBKDF2)或第三方库 bcrypt/argon2-cffi,而非直接使用 MD5/SHA。文件完整性校验
import hashlib
from pathlib import Path
def file_checksum(filepath: str | Path, algorithm: str = "sha256", chunk_size: int = 65536) -> str:
"""计算文件的哈希值(分块读取,适合大文件)。"""
h = hashlib.new(algorithm)
with open(filepath, "rb") as f:
while chunk := f.read(chunk_size):
h.update(chunk)
return h.hexdigest()
# 校验两个文件是否相同
f1 = file_checksum("file1.bin")
f2 = file_checksum("file2.bin")
print("文件相同" if f1 == f2 else f"文件不同: {f1} vs {f2}")支持的算法
import hashlib
# 查看所有可用算法
print(hashlib.algorithms_available)
print(hashlib.algorithms_guaranteed) # 保证在所有平台可用
# 动态选择算法
h = hashlib.new("sha512", b"data")
print(h.hexdigest())hmac — 消息认证码
HMAC(Hash-based Message Authentication Code)在哈希基础上引入共享密钥,可以同时验证数据完整性和来源真实性。
import hmac
import os
# 双方共享的密钥(需通过安全渠道交换)
secret_key = os.urandom(32)
def sign(message: bytes, key: bytes) -> bytes:
"""对消息签名。"""
return hmac.new(key, message, digestmod="sha256").digest()
def verify(message: bytes, signature: bytes, key: bytes) -> bool:
"""验证消息签名(使用 compare_digest 防止时序攻击)。"""
expected = sign(message, key)
return hmac.compare_digest(expected, signature)
# 发送方签名
msg = b"transfer: $100 to Alice"
sig = sign(msg, secret_key)
print(f"签名: {sig.hex()}")
# 接收方验证
ok = verify(msg, sig, secret_key)
print(f"签名有效: {ok}") # True
# 消息被篡改时
tampered = b"transfer: $9999 to Eve"
print(f"篡改后验证: {verify(tampered, sig, secret_key)}") # FalseTCP 通信中的身份验证
使用 HMAC 实现服务端对客户端的挑战-应答认证:
import socket
import hmac
import os
SECRET_KEY = b"shared_secret_key_for_demo"
# --- 服务端 ---
def server_auth(conn: socket.socket) -> bool:
"""向客户端发送随机挑战,验证其知道共享密钥。"""
challenge = os.urandom(32)
conn.sendall(challenge) # 发送挑战
response = conn.recv(64) # 等待客户端的 HMAC 响应
expected = hmac.new(SECRET_KEY, challenge, digestmod="sha256").digest()
return hmac.compare_digest(response, expected)
# --- 客户端 ---
def client_auth(conn: socket.socket) -> None:
"""接收挑战,计算 HMAC 发回服务端。"""
challenge = conn.recv(32) # 接收服务端挑战
response = hmac.new(SECRET_KEY, challenge, digestmod="sha256").digest()
conn.sendall(response)最后更新于