跳至内容

加密模块

Python 标准库提供了 hashlib(哈希摘要)和 hmac(消息认证码)两个加密相关模块,用于密码存储、数据完整性校验和通信认证。

hashlib — 哈希摘要

哈希(摘要)算法将任意长度的数据映射为固定长度的字节串,具有单向性(不可逆)和雪崩效应(原文微小改动导致摘要完全不同)。

常用算法:

算法摘要长度安全性适用场景
MD5128 bit / 32 hex弱(已碰撞)文件校验(非安全场景)
SHA-1160 bit / 40 hex遗留系统
SHA-256256 bit / 64 hex密码存储、数字签名
SHA-512512 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)}")   # False

TCP 通信中的身份验证

使用 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)
最后更新于