密码学速查指南

适合这样的读者: 需要在 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 位已被认为不安全
相关推荐
Sagittarius_A*5 小时前
公钥密码基础(一):从对称密码到公钥密码——密钥分发问题
信息安全·密码学·公钥密码·密钥分发
Sagittarius_A*3 天前
后量子密码|前置基础 03|数字签名运行逻辑:签名签发、核验原理与实际业务应用
算法·信息安全·密码学·数字签名·后量子密码
CodeJourney_J5 天前
网络安全简述-加密技术
网络·安全·密码学
Sagittarius_A*5 天前
后量子密码|前置基础 01|PQC 极简数学:模运算、有限域、多项式环、矩阵、范数与小系数噪声
线性代数·信息安全·矩阵·密码学·量子计算·pqc·后量子密码
要开心吖ZSH6 天前
公钥加密,私钥解密?私钥加密,公钥解密?哪个对?
密码学·aes·sha·rsa·sm2·sm3·签名验签
Sagittarius_A*7 天前
哈希与认证基础(一):哈希函数的安全目标:原像、第二原像与碰撞
算法·安全·信息安全·密码学·哈希算法
Sagittarius_A*8 天前
后量子密码|通识认知 03|量子威胁辟谣:Grover 算法对对称密码的影响与误区
算法·信息安全·密码学·量子计算·pqc·后量子密码
砚凝霜8 天前
软考网络工程师|第 6 章 密码学、哈希、数字签名、数字证书 PKI 完整备考笔记
笔记·密码学·哈希算法
Sagittarius_A*9 天前
后量子密码|通识认知 02|量子威胁核心原理:Shor 算法如何击穿传统公钥密码
算法·信息安全·密码学·量子计算
笨鸟先飞,勤能补拙9 天前
密码学深度指南 — SecOps 工程师实战手册
人工智能·vscode·python·安全·github·密码学·visual studio