Python 加密与安全:hashlib、hmac、pycryptodome、RSA/AES 实战

小飞兽 Python 7 次阅读 2026-07-24

Introduction

密码哈希、数据完整性、数字签名是安全开发的核心技能。本文讲解 Python 标准库 hashlib、hmac 的用法,以及 pycryptodome 实现 AES/RSA 加密、JWT 签名、安全密码存储的最佳实践。

---

哈希(不可逆加密)

import hashlib

# MD5(不安全,仅用于文件校验)
md5 = hashlib.md5(b'hello world').hexdigest()
print(f'MD5: {md5}')  # 5eb63bbbe01eeed093cb22bb8f5acdc3

# SHA-256(推荐)
sha256 = hashlib.sha256(b'hello world').hexdigest()
print(f'SHA256: {sha256}')

# SHA-512(更高安全需求)
sha512 = hashlib.sha512(b'hello world').hexdigest()

# 文件哈希(校验文件完整性)
def file_hash(filepath, algorithm='sha256'):
    h = hashlib.new(algorithm)
    with open(filepath, 'rb') as f:
        while chunk := f.read(8192):
            h.update(chunk)
    return h.hexdigest()

print(file_hash('big_file.zip'))  # 可以处理任意大小文件

HMAC(消息认证码)

import hmac, hashlib

secret_key = b'super_secret_key'
message = b'{"user_id": 1, "action": "login"}'

# HMAC-SHA256(验证消息完整性和来源)
mac = hmac.new(secret_key, message, hashlib.sha256).hexdigest()
print(f'HMAC: {mac}')

# 验证
def verify_mac(message, mac, key):
    expected_mac = hmac.new(key, message, hashlib.sha256).hexdigest()
    return hmac.compare_digest(mac, expected_mac)

print(verify_mac(message, mac, secret_key))  # True(正确)
print(verify_mac(message, 'wrong_mac', secret_key))  # False(被篡改)

密码存储(bcrypt)

pip install bcrypt
import bcrypt

# 哈希密码
def hash_password(password: str) -> str:
    salt = bcrypt.gensalt(rounds=12)
    return bcrypt.hashpw(password.encode(), salt).decode()

# 验证密码
def verify_password(password: str, hashed: str) -> bool:
    return bcrypt.checkpw(password.encode(), hashed.encode())

# 使用
hashed = hash_password('MySecure123!')
print(hashed)  # $2b$12$...
print(verify_password('MySecure123!', hashed))  # True
print(verify_password('wrong', hashed))          # False

AES 对称加密

pip install pycryptodome
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import base64

def aes_encrypt(data: str, key: bytes) -> tuple:
    cipher = AES.new(key, AES.MODE_GCM)
    ciphertext, tag = cipher.encrypt_and_digest(data.encode())
    return base64.b64encode(ciphertext).decode(), base64.b64encode(cipher.nonce).decode(), base64.b64encode(tag).decode()

def aes_decrypt(ciphertext_b64: str, key: bytes, nonce_b64: str, tag_b64: str) -> str:
    cipher = AES.new(key, AES.MODE_GCM, nonce=base64.b64decode(nonce_b64))
    data = cipher.decrypt_and_verify(
        base64.b64decode(ciphertext_b64),
        base64.b64decode(tag_b64)
    )
    return data.decode()

# 使用
key = get_random_bytes(16)  # 128位密钥
ct, nonce, tag = aes_encrypt('机密内容', key)
plain = aes_decrypt(ct, key, nonce, tag)
print(plain)  # '机密内容'

RSA 非对称加密

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import base64

# 生成密钥对(一次性)
key = RSA.generate(2048)
private_key = key.export_key()
public_key = key.publickey().export_key()

# 加密(用公钥)
recipient_key = RSA.import_key(public_key)
cipher = PKCS1_OAEP.new(recipient_key)
ciphertext = cipher.encrypt(b'机密消息')
print(base64.b64encode(ciphertext).decode())

# 解密(用私钥)
sender_key = RSA.import_key(private_key)
cipher = PKCS1_OAEP.new(sender_key)
plaintext = cipher.decrypt(ciphertext)
print(plaintext.decode())

JWT 签名

pip install pyjwt
import jwt, datetime

secret = 'your-secret-key'
payload = {
    'user_id': 1,
    'username': 'admin',
    'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=24)
}

# 签发
token = jwt.encode(payload, secret, algorithm='HS256')
print(token)

# 验证
try:
    decoded = jwt.decode(token, secret, algorithms=['HS256'])
    print(decoded)
except jwt.ExpiredSignatureError:
    print('Token 已过期')
except jwt.InvalidTokenError:
    print('Token 无效')

常见问题

Q1: MD5 还安全吗?不安全,MD5 有已知碰撞攻击,不能用于密码存储。可用于文件校验(检测意外损坏,不防攻击)。

Q2: AES-128 和 AES-256 哪个好?AES-256 密钥空间更大,更抗暴力破解;但 AES-128 在实际中已足够安全(AES 本身无已知弱点的实战算法)。

Q3: 对称加密和非对称加密怎么选?混合方案:数据用 AES 对称加密,AES 密钥用 RSA 非对称加密传输。JWT 用私钥签名,公钥验证。

延伸阅读

  • TLS/SSL 原理
  • Python 安全编码规范(OWASP)
  • JWT 最佳实践

---

作者:小马 | 绍大技术网 shaoda.net