密码学速查指南

📅 2026/7/27 15:28:41
密码学速查指南
适合这样的读者需要在 Python 中处理加密、编码、哈希操作的开发者。本文按用途分类整理——先分清编码/哈希/加密的区别再给出各场景的实操代码。前置知识了解字节与字符串的区别即可。密码学操作可以按三个维度分类类别是否可逆是否需要密钥常见用途编码可逆否URL 传输、二进制文本化哈希摘要不可逆否密码存储、数据完整性校验加密可逆是数据保密传输编码不依赖密钥仅改变数据表示形式任何人都可以解码URL 编码将非 ASCII 字符或特殊字符转为 %XX 格式使其能在 URL 中安全传输fromurllib.parseimportquote,urlencode,unquote# 1. 编码字符串print(quote(米饭怎么吃))# %E7%B1%B3%E9%A5%AD%E6%80%8E%E4%B9%88%E5%90%83print(quote(米饭怎么吃,encodinggbk))# %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错误说明缺少填充字符。importbase64# 编码字节 → Base64 字符串print(base64.b64encode(我要吃饭.encode(utf-8)).decode())# 解码Base64 字符串 → 字节print(base64.b64decode(5oiR6KaB5ZCD6aWt).decode(utf-8))手动处理填充不足sztKwrsTj0b0s(*(4-len(s)%4))print(填充后,s)bbbase64.b64decode(s).decode(gbk)print(bb)哈希摘要将任意长度的数据映射为固定长度的哈希值不可逆。同样的输入总是同样的输出。哈希不可逆是重要特性无法从哈希值反推出原文。常用于密码存储和文件完整性校验。MD5输出 128 位32 位十六进制速度快但已不再安全不应用于密码存储fromhashlibimportmd5# 不加盐objmd5()obj.update(明文.encode(utf-8))print(obj.hexdigest())# 加盐防止彩虹表攻击objmd5(固定盐值.encode(utf-8))obj.update(明文.encode(utf-8))print(obj.hexdigest())SHA-1 / SHA-256输出更长安全性更高。SHA-256 是目前推荐的哈希算法fromhashlibimportsha1,sha256 shasha256()sha.update(明文.encode(utf-8))print(sha.hexdigest())# 加盐shasha256(固定盐值.encode(utf-8))sha.update(明文.encode(utf-8))print(sha.hexdigest())HMAC基于哈希的消息认证码用密钥对消息签名同时验证消息完整性和来源身份。API 接口签名最常用的方式HMAC 哈希函数 密钥。和哈希的区别哈希任何人都能计算HMAC 需要密钥才能验证。这在数据采集场景中很常见——很多 API 要求对请求参数做 HMAC 签名。importhmacimporthashlib keybapi_secret_keymsgbparam1value1param2value2# 生成签名sighmac.new(key,msg,hashlib.sha256).hexdigest()print(sig)# 输出 64 位十六进制字符串# 验证签名服务端用相同 key 和 msg 重新计算比对是否一致expectedhmac.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当前最广泛使用的对称加密标准fromCrypto.CipherimportAES keyb0123456789abcdef# 16 字节 AES-128IVb0102030405060708# 初始向量CBC 模式必需# 加密aesAES.new(key,modeAES.MODE_CBC,IVIV)data明文data_bsdata.encode(utf-8)# 数据长度必须是 16 的倍数不足补位pad_len16-len(data_bs)%16data_bs(pad_len*chr(pad_len)).encode(utf-8)bsaes.encrypt(data_bs)print(bs)# 解密aesAES.new(key,modeAES.MODE_CBC,IVIV)resultaes.decrypt(bs)print(result.decode(utf-8))DES密钥仅 56 位8 字节已可被暴力破解。不建议在新项目中使用了解即可fromCrypto.CipherimportDES keyb01234567# 8 字节IVb01020304# 加密desDES.new(key,modeDES.MODE_CBC,IVIV)data我要吃饭.encode(utf-8)pad_len8-len(data)%8data(pad_len*chr(pad_len)).encode(utf-8)bsdes.encrypt(data)print(bs)# 解密desDES.new(key,modeDES.MODE_CBC,IVIV)resultdes.decrypt(bs)print(result.decode(utf-8))非对称加密使用公钥加密、私钥解密。公钥可公开私钥必须保密。对称加密的问题在于密钥如何安全传输——非对称加密解决了这个问题发送方用接收方的公钥加密数据只有接收方的私钥能解密。RSA最常用的非对称加密算法安全性基于大整数分解的难度fromCrypto.PublicKeyimportRSAfromCrypto.CipherimportPKCS1_v1_5fromCryptoimportRandomimportbase64 gen_randomRandom.new# 1. 生成密钥对rsakeyRSA.generate(1024)withopen(rsa_public.pem,modewb)asf:f.write(rsakey.publickey().exportKey())withopen(rsa_private.pem,modewb)asf:f.write(rsakey.exportKey())# 2. 加密使用公钥data需要加密的敏感数据withopen(rsa_public.pem,moder)asf:pkf.read()rsa_pkRSA.importKey(pk)rsaPKCS1_v1_5.new(rsa_pk)resultrsa.encrypt(data.encode(utf-8))b64_resultbase64.b64encode(result).decode(utf-8)print(b64_result)# 3. 解密使用私钥withopen(rsa_private.pem,moder)asf:prikeyf.read()rsa_pkRSA.importKey(prikey)rsaPKCS1_v1_5.new(rsa_pk)resultrsa.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端到端加密性能要求高非对称加密交换密钥 → 对称加密传输数据安全提示不要自己造加密算法——使用经过验证的标准库不要用 ECB 模式——相同明文产生相同密文信息泄漏风险哈希密码必须加盐——防止彩虹表攻击RSA 密钥长度不低于 2048 位——1024 位已被认为不安全