Python加密与解密操作
加密是保护数据机密性的核心手段。使用cryptography库实现安全的加密操作。
cryptography 库概述
Bash
pip install cryptography
Python
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes, symmetric, asymmetric
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.backends import default_backend
import base64
import os
# 主要组件:
# - Fernet: 对称加密(简单API)
# - AES: 高级对称加密
# - RSA: 非对称加密
# - 哈希: SHA256等
对称加密 - Fernet
Python
from cryptography.fernet import Fernet
# 生成密钥
key = Fernet.generate_key()
print(key) # base64编码的32字节密钥
# 创建加密器
cipher = Fernet(key)
# 加密
message = "敏感数据"
encrypted = cipher.encrypt(message.encode())
print(encrypted) # bytes
# 解密
decrypted = cipher.decrypt(encrypted)
print(decrypted.decode()) # "敏感数据"
Python
# 密钥管理
from cryptography.fernet import Fernet
import os
class SecureKeyManager:
"安全密钥管理"
def __init__(self, key_file: str):
self.key_file = key_file
self.key = self._load_or_create_key()
self.cipher = Fernet(self.key)
def _load_or_create_key(self):
"加载或创建密钥"
if os.path.exists(self.key_file):
with open(self.key_file, 'rb') as f:
return f.read()
else:
key = Fernet.generate_key()
# 安全存储密钥
with open(self.key_file, 'wb') as f:
f.write(key)
os.chmod(self.key_file, 0o600) # 仅所有者可读写
return key
def encrypt_data(self, data: str) -> bytes:
"加密数据"
return self.cipher.encrypt(data.encode())
def decrypt_data(self, encrypted: bytes) -> str:
"解密数据"
return self.cipher.decrypt(encrypted).decode()
manager = SecureKeyManager('/secure/key.key')
encrypted = manager.encrypt_data("敏感信息")
从密码生成密钥
Python
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
from cryptography.fernet import Fernet
import base64
import os
def generate_key_from_password(password: str, salt: bytes = None) -> tuple:
"从密码生成加密密钥"
if salt is None:
salt = os.urandom(16)
# PBKDF2密钥派生
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
backend=default_backend()
)
key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
return key, salt
def encrypt_with_password(data: str, password: str) -> dict:
"使用密码加密"
key, salt = generate_key_from_password(password)
cipher = Fernet(key)
encrypted = cipher.encrypt(data.encode())
return {
'encrypted': encrypted,
'salt': salt # 需要存储盐以解密
}
def decrypt_with_password(encrypted: bytes, password: str, salt: bytes) -> str:
"使用密码解密"
key, _ = generate_key_from_password(password, salt)
cipher = Fernet(key)
return cipher.decrypt(encrypted).decode()
# 使用
result = encrypt_with_password("敏感数据", "user_password")
decrypted = decrypt_with_password(
result['encrypted'],
"user_password",
result['salt']
)
AES 高级加密
Python
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import os
class AESCipher:
"AES加密器"
def __init__(self, key: bytes = None):
self.key = key or os.urandom(32) # AES-256需要32字节密钥
def encrypt(self, data: bytes) -> dict:
"AES-CBC加密"
# 生成随机IV
iv = os.urandom(16)
cipher = Cipher(
algorithms.AES(self.key),
modes.CBC(iv),
backend=default_backend()
)
encryptor = cipher.encryptor()
# PKCS7填充
padded_data = self._pad(data)
encrypted = encryptor.update(padded_data) + encryptor.finalize()
return {'encrypted': encrypted, 'iv': iv}
def decrypt(self, encrypted: bytes, iv: bytes) -> bytes:
"AES-CBC解密"
cipher = Cipher(
algorithms.AES(self.key),
modes.CBC(iv),
backend=default_backend()
)
decryptor = cipher.decryptor()
decrypted = decryptor.update(encrypted) + decryptor.finalize()
return self._unpad(decrypted)
def _pad(self, data: bytes) -> bytes:
"PKCS7填充"
block_size = 16
padding_length = block_size - len(data) % block_size
return data + bytes([padding_length]) * padding_length
def _unpad(self, data: bytes) -> bytes:
"移除填充"
padding_length = data[-1]
return data[:-padding_length]
aes = AESCipher()
encrypted = aes.encrypt(b"敏感数据")
decrypted = aes.decrypt(encrypted['encrypted'], encrypted['iv'])
Python
# AES-GCM(推荐,提供认证加密)
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
class AESGCMCipher:
"AES-GCM认证加密"
def __init__(self, key: bytes = None):
self.key = key or os.urandom(32)
self.aesgcm = AESGCM(self.key)
def encrypt(self, data: bytes, associated_data: bytes = None) -> dict:
"加密"
nonce = os.urandom(12) # GCM推荐12字节nonce
encrypted = self.aesgcm.encrypt(nonce, data, associated_data)
return {
'encrypted': encrypted,
'nonce': nonce,
'associated_data': associated_data
}
def decrypt(self, encrypted: bytes, nonce: bytes,
associated_data: bytes = None) -> bytes:
"解密"
return self.aesgcm.decrypt(nonce, encrypted, associated_data)
gcm = AESGCMCipher()
result = gcm.encrypt(b"敏感数据", b"metadata")
decrypted = gcm.decrypt(result['encrypted'], result['nonce'], result['associated_data'])
RSA 非对称加密
Python
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
class RSACipher:
"RSA加密器"
def __init__(self):
# 生成密钥对
self.private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
self.public_key = self.private_key.public_key()
def encrypt(self, data: bytes) -> bytes:
"公钥加密"
encrypted = self.public_key.encrypt(
data,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return encrypted
def decrypt(self, encrypted: bytes) -> bytes:
"私钥解密"
decrypted = self.private_key.decrypt(
encrypted,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return decrypted
def export_public_key(self) -> bytes:
"导出公钥"
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
return self.public_key.public_bytes(
encoding=Encoding.PEM,
format=PublicFormat.SubjectPublicKeyInfo
)
def export_private_key(self, password: str = None) -> bytes:
"导出私钥"
from cryptography.hazmat.primitives.serialization import (
Encoding, PrivateFormat, BestAvailableEncryption, NoEncryption
)
if password:
encryption = BestAvailableEncryption(password.encode())
else:
encryption = NoEncryption()
return self.private_key.private_bytes(
encoding=Encoding.PEM,
format=PrivateFormat.PKCS8,
encryption_algorithm=encryption
)
rsa_cipher = RSACipher()
encrypted = rsa_cipher.encrypt(b"敏感数据")
decrypted = rsa_cipher.decrypt(encrypted)
数字签名
Python
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes
class DigitalSignature:
"数字签名"
def __init__(self):
self.private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048
)
self.public_key = self.private_key.public_key()
def sign(self, data: bytes) -> bytes:
"签名"
signature = self.private_key.sign(
data,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
return signature
def verify(self, data: bytes, signature: bytes) -> bool:
"验证签名"
try:
self.public_key.verify(
signature,
data,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
return True
except:
return False
signer = DigitalSignature()
signature = signer.sign(b"待签名数据")
is_valid = signer.verify(b"待签名数据", signature)
混合加密
Python
import os
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes
class HybridEncryption:
"混合加密(RSA + AES)"
def __init__(self):
self.rsa_private = rsa.generate_private_key(
public_exponent=65537, key_size=2048
)
self.rsa_public = self.rsa_private.public_key()
def encrypt(self, data: bytes) -> dict:
"加密"
# 生成随机AES密钥
aes_key = Fernet.generate_key()
cipher = Fernet(aes_key)
# AES加密数据
encrypted_data = cipher.encrypt(data)
# RSA加密AES密钥
encrypted_key = self.rsa_public.encrypt(
aes_key,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return {
'encrypted_data': encrypted_data,
'encrypted_key': encrypted_key
}
def decrypt(self, encrypted_data: bytes, encrypted_key: bytes) -> bytes:
"解密"
# RSA解密AES密钥
aes_key = self.rsa_private.decrypt(
encrypted_key,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
# AES解密数据
cipher = Fernet(aes_key)
return cipher.decrypt(encrypted_data)
hybrid = HybridEncryption()
encrypted = hybrid.encrypt(b"大文件数据")
decrypted = hybrid.decrypt(encrypted['encrypted_data'], encrypted['encrypted_key'])
安全哈希
Python
from cryptography.hazmat.primitives import hashes
def secure_hash(data: bytes) -> bytes:
"安全哈希"
digest = hashes.Hash(hashes.SHA256())
digest.update(data)
return digest.finalize()
def secure_hash_file(filepath: str) -> bytes:
"文件哈希"
digest = hashes.Hash(hashes.SHA256())
with open(filepath, 'rb') as f:
while chunk := f.read(8192):
digest.update(chunk)
return digest.finalize()
# HMAC
from cryptography.hazmat.primitives.hmac import HMAC
def hmac_sign(key: bytes, data: bytes) -> bytes:
"HMAC签名"
h = HMAC(key, hashes.SHA256())
h.update(data)
return h.finalize()
def hmac_verify(key: bytes, data: bytes, signature: bytes) -> bool:
"HMAC验证"
h = HMAC(key, hashes.SHA256())
h.update(data)
try:
h.verify(signature)
return True
except:
return False
要点总结
- Fernet提供简单的对称加密API
- AES-GCM推荐用于认证加密
- RSA用于密钥加密和小数据,大数据用AES
- PBKDF2从密码安全派生密钥
- 混合加密结合对称和非对称的优点
📝 发现内容有误?点击此处直接编辑