Python 加密与安全:hashlib、hmac、pycryptodome、RSA/AES 实战
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