密码学速查指南

适合这样的读者: 需要在 Python 中处理加密、编码、哈希操作的开发者。本文按用途分类整理------先分清"编码/哈希/加密"的区别,再给出各场景的实操代码。

前置知识: 了解字节与字符串的区别即可。


密码学操作可以按三个维度分类:

类别 是否可逆 是否需要密钥 常见用途
编码 可逆 URL 传输、二进制文本化
哈希摘要 不可逆 密码存储、数据完整性校验
加密 可逆 数据保密传输

编码

不依赖密钥,仅改变数据表示形式,任何人都可以解码

URL 编码

将非 ASCII 字符或特殊字符转为 %XX 格式,使其能在 URL 中安全传输

py 复制代码
from urllib.parse import quote, urlencode, unquote

# 1. 编码字符串
print(quote('米饭怎么吃'))                     # %E7%B1%B3%E9%A5%AD%E6%80%8E%E4%B9%88%E5%90%83
print(quote('米饭怎么吃', encoding="gbk"))     # %C3%D7%B7%B9%D4%F5%C3%B4%B3%D4

# 2. 编码字典
dic = {"wq": "米饭怎么吃", "new_wq": "想怎么吃就怎么吃"}
print(urlencode(dic))

# 3. 解码
print(unquote("http://www.baidu.com/s?wd=%E5%A4%A7%E7%8E%8B"))
# http://www.baidu.com/s?wd=大王

Base64

将二进制数据转为 64 个可打印字符表示,常用于图片/附件传输

Base64 字符串长度是 4 的倍数,不足时需要填充 =。如果解码时遇到 Incorrect padding 错误,说明缺少填充字符。

py 复制代码
import base64

# 编码:字节 → Base64 字符串
print(base64.b64encode("我要吃饭".encode("utf-8")).decode())

# 解码:Base64 字符串 → 字节
print(base64.b64decode("5oiR6KaB5ZCD6aWt").decode("utf-8"))

手动处理填充不足:

py 复制代码
s = "ztKwrsTj0b0"
s += ("=" * (4 - len(s) % 4))
print("填充后", s)

bb = base64.b64decode(s).decode("gbk")
print(bb)

哈希摘要

将任意长度的数据映射为固定长度的哈希值,不可逆。同样的输入总是同样的输出。

哈希不可逆是重要特性:无法从哈希值反推出原文。常用于密码存储和文件完整性校验。

MD5

输出 128 位(32 位十六进制),速度快,但已不再安全,不应用于密码存储

py 复制代码
from hashlib import md5

# 不加盐
obj = md5()
obj.update("明文".encode("utf-8"))
print(obj.hexdigest())

# 加盐(防止彩虹表攻击)
obj = md5("固定盐值".encode("utf-8"))
obj.update("明文".encode("utf-8"))
print(obj.hexdigest())

SHA-1 / SHA-256

输出更长,安全性更高。SHA-256 是目前推荐的哈希算法

py 复制代码
from hashlib import sha1, sha256

sha = sha256()
sha.update('明文'.encode("utf-8"))
print(sha.hexdigest())

# 加盐
sha = sha256('固定盐值'.encode("utf-8"))
sha.update('明文'.encode("utf-8"))
print(sha.hexdigest())

HMAC(基于哈希的消息认证码)

用密钥对消息签名,同时验证消息完整性和来源身份。API 接口签名最常用的方式

HMAC = 哈希函数 + 密钥。和哈希的区别:哈希任何人都能计算,HMAC 需要密钥才能验证。这在数据采集场景中很常见------很多 API 要求对请求参数做 HMAC 签名。

py 复制代码
import hmac
import hashlib

key = b"api_secret_key"
msg = b"param1=value1&param2=value2"

# 生成签名
sig = hmac.new(key, msg, hashlib.sha256).hexdigest()
print(sig)  # 输出 64 位十六进制字符串

# 验证签名(服务端用相同 key 和 msg 重新计算,比对是否一致)
expected = hmac.new(key, msg, hashlib.sha256).hexdigest()
print(hmac.compare_digest(sig, expected))  # True

实际场景: 爬虫请求需要签名的 API 时,找到签名算法(通常是 HMAC-SHA256),用抓到的 key 对请求参数排序后计算签名,拼到请求头中发送。


对称加密

加密和解密使用同一个密钥。速度快,适合大量数据的加密传输。

关键参数:

  • 密钥长度:越长越安全(AES-128 / AES-192 / AES-256)
  • 加密模式
    • ECB:每个分组独立加密,不推荐(相同明文产生相同密文)
    • CBC:前一分组的密文参与下一分组加密,推荐
    • CFB / OFB:将块密码转为流密码模式

对称加密的安全前提:密钥只能由通信双方知晓,不能通过网络明文传输。

AES

当前最广泛使用的对称加密标准

python 复制代码
from Crypto.Cipher import AES

key = b"0123456789abcdef"     # 16 字节 = AES-128
IV  = b"0102030405060708"     # 初始向量,CBC 模式必需

# 加密
aes = AES.new(key, mode=AES.MODE_CBC, IV=IV)
data = "明文"
data_bs = data.encode("utf-8")

# 数据长度必须是 16 的倍数,不足补位
pad_len = 16 - len(data_bs) % 16
data_bs += (pad_len * chr(pad_len)).encode("utf-8")

bs = aes.encrypt(data_bs)
print(bs)

# 解密
aes = AES.new(key, mode=AES.MODE_CBC, IV=IV)
result = aes.decrypt(bs)
print(result.decode("utf-8"))

DES

密钥仅 56 位(8 字节),已可被暴力破解。不建议在新项目中使用,了解即可

python 复制代码
from Crypto.Cipher import DES

key = b"01234567"            # 8 字节
IV  = b"01020304"

# 加密
des = DES.new(key, mode=DES.MODE_CBC, IV=IV)
data = "我要吃饭".encode("utf-8")
pad_len = 8 - len(data) % 8
data += (pad_len * chr(pad_len)).encode("utf-8")
bs = des.encrypt(data)
print(bs)

# 解密
des = DES.new(key, mode=DES.MODE_CBC, IV=IV)
result = des.decrypt(bs)
print(result.decode("utf-8"))

非对称加密

使用公钥加密、私钥解密。公钥可公开,私钥必须保密。

对称加密的问题在于"密钥如何安全传输"------非对称加密解决了这个问题:发送方用接收方的公钥加密数据,只有接收方的私钥能解密。

RSA

最常用的非对称加密算法,安全性基于大整数分解的难度

py 复制代码
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto import Random
import base64

gen_random = Random.new

# 1. 生成密钥对
rsakey = RSA.generate(1024)
with open("rsa_public.pem", mode="wb") as f:
    f.write(rsakey.publickey().exportKey())
with open("rsa_private.pem", mode="wb") as f:
    f.write(rsakey.exportKey())

# 2. 加密(使用公钥)
data = "需要加密的敏感数据"
with open("rsa_public.pem", mode="r") as f:
    pk = f.read()
    rsa_pk = RSA.importKey(pk)
    rsa = PKCS1_v1_5.new(rsa_pk)
    result = rsa.encrypt(data.encode("utf-8"))
    b64_result = base64.b64encode(result).decode("utf-8")
    print(b64_result)

# 3. 解密(使用私钥)
with open("rsa_private.pem", mode="r") as f:
    prikey = f.read()
    rsa_pk = RSA.importKey(prikey)
    rsa = PKCS1_v1_5.new(rsa_pk)
    result = rsa.decrypt(base64.b64decode(b64_result), gen_random)
    print(result.decode("utf-8"))

如何选择

需求 推荐方案
URL 传输非 ASCII 字符 URL 编码
二进制数据文本化(如图片传输) Base64
密码存储 SHA-256 + 盐值(或 bcrypt / argon2)
文件完整性校验 SHA-256
大量数据传输加密 AES-256-CBC
密钥分发与数字签名 RSA
端到端加密(性能要求高) 非对称加密交换密钥 → 对称加密传输数据

安全提示

  1. 不要自己造加密算法------使用经过验证的标准库
  2. 不要用 ECB 模式------相同明文产生相同密文,信息泄漏风险
  3. 哈希密码必须加盐------防止彩虹表攻击
  4. RSA 密钥长度不低于 2048 位------1024 位已被认为不安全
相关推荐
Draina2 天前
CBC填充预言攻击-CBC Padding Oracle Crypto Attack
python·安全·web安全·网络安全·密码学·安全性测试
二宝哥4 天前
MySQL 修改密码策略详解:从基础到高级配置
mysql·密码学
Sagittarius_A*9 天前
现代密码学的数学地基:从模运算到离散对数
网络·算法·密码学
AI科技星12 天前
基于全域数学公理体系求解三元约束极值题【乖乖数学】
人工智能·算法·机器学习·密码学·拓扑学·乖乖数学·全域数学
云水一下15 天前
DVWA从入门到精通(十八):Cryptography(密码学问题)
web安全·密码学·dvwa
MartinYeung515 天前
W3C Agent Identity 最新标准:从密码学视角的深度解析
密码学
风行南方15 天前
弄懂有限域,AES加密核心GF(2⁸)数学原理详解
密码学
想你依然心痛18 天前
量子计算对嵌入式密码学的挑战与后量子算法准备
算法·密码学·量子计算
AI科技星20 天前
超复数全域经济周期场与信息谱场——金融与密码学底层理论重构《0·1·∞三元一体全域超复数统一场论》系列全集(六一字不漏完整合订终版)
人工智能·算法·金融·密码学·拓扑学·乖乖数学·全域数学