3Q工具箱
首页 / 教程中心 / 开发辅助

哈希不是加密:MD5、SHA-256、HMAC 与 AES/RSA 怎么选

开发辅助发布于 2026-09-12

绝大多数「加密」相关的事故,起点都是把三个不同的东西混成了一个词:摘要、消息认证码、加密。它们的输入输出、密钥有无、可逆与否完全不同,用错一个就没有安全性可谈。

这篇按「先分清概念,再讲参数取舍」的顺序写。文中用到的运算都在浏览器本地完成,密钥、明文、私钥 PEM 不会离开你的设备,但请先记住最后一条建议:生产环境的真实私钥不要粘贴到任何在线页面,包括本站。

一、哈希、消息认证码、加密是三件事

哈希(摘要)是单向压缩。任意长度的输入映射到固定长度输出,SHA-256 永远输出 32 字节,MD5 永远输出 16 字节。它没有密钥,也没有逆运算,所以「MD5 解密」从定义上就不存在。网上那些自称能解的站点做的是查表:预先把常见口令算好摘要存进库里,你粘贴摘要它回查原文。123456 能查到,一串 24 位随机字符查不到,这说明被破的不是算法而是弱口令本身。

消息认证码(MAC)是「哈希加密钥」。HMAC-SHA256 需要一个密钥参与运算,只有持有同一密钥的人才能算出相同结果,因此它能回答「这段数据是不是我认识的那一方发出的、有没有被改过」。哈希单独用则回答不了这个问题,因为任何人都能重算。

加密是可逆的。AES 用同一把密钥加解密,RSA 用公钥加密私钥解密,目标是保密性,不负责完整性。这三类工具解决的问题分别是「一致性」「真实性」「保密性」,不能互相替代。

需要一次看清同一段输入在九种算法下的结果时,用哈希与HMAC计算MD5SHA-1SHA-224SHA-256SHA-384SHA-512SHA3-256SHA3-512RIPEMD-160 会同时列出,输出可切换十六进制大小写或 Base64

二、MD5 与 SHA-1 为什么不能再用于安全场景

这两个算法的输出长度不是主要问题,问题是碰撞已经能被主动构造。碰撞指两段不同的输入算出相同摘要。MD5 的碰撞在普通机器上几秒钟就能造出来,SHA-1 的碰撞也在 2017 年被实际演示。一旦攻击者能构造碰撞,任何「靠摘要相等来判断内容没被换掉」的机制都失效了,包括数字签名、代码签名、证书链、防篡改校验。

但它们并没有完全退休,判断标准是「有没有对手」。

  • 可以继续用的场景:给缓存算 key、给文件做去重指纹、检测传输过程中的偶发损坏。这些场景里没有人故意构造碰撞。
  • 必须换掉的场景:签名、防篡改、令牌校验、密码存储。这里存在有动机的攻击者,请至少用 SHA-256
  • 不要用任何普通哈希的场景:用户口令存储。MD5 加盐也不行。口令必须用 bcryptscryptArgon2,它们的核心不是安全性更强的压缩函数,而是可调的工作因子,让每次校验都慢到显卡集群也批量算不动。

MD5加密适合的是快速拿一个短指纹,比如核对同事发来的一段配置和你手上的是不是同一份。把它当成密码保护手段就是误用。

三、加盐哈希与 HMAC 不是一回事

两者都是「哈希 + 一个额外字符串」,形似而目标完全不同。

  • 盐是公开的、每条记录一份的随机值,和口令拼接后再哈希。它的唯一目的是让预计算的彩虹表失效,并让两个用相同口令的用户存出不同摘要。盐可以明文存在数据库里,泄露了也不算事故。
  • HMAC 的密钥是保密的、全系统共享或按调用方分配的。它的目的是身份与完整性,密钥一泄露,攻击者就能伪造任意签名。

另外,HMAC 不是简单的 hash(key + message)。它的结构是两层嵌套,配合 ipadopad 两个常量对密钥做异或,这样设计是为了抵抗长度扩展攻击:对于 MD5SHA-1SHA-256 这类 Merkle-Damgård 结构的算法,攻击者知道 hash(secret + data)data 的长度后,可以在不知道 secret 的情况下算出 hash(secret + data + 任意追加内容) 的有效摘要。自己拼字符串做签名,就是踩这个坑。

对接开放平台接口时,HMAC 有两个高频出错点。一是密钥编码,对方要求的可能是 UTF-8 原文、也可能是 Base64Hex 解码后的字节,三种解读算出的签名互不相同,工具里可以逐一切换比对。二是待签字符串的末尾换行,多一个 \n 结果就全变,本地调试时把字符串完整贴进来比对最省时间。比对签名时服务端还应使用恒定时间比较函数,逐字节短路返回会泄露时序信息。

四、AES 的模式、IV 与填充怎么选

AES 本身只会加密固定 16 字节的一个块,把它扩展到任意长度数据靠的是「模式」。

  • GCM:默认首选。它同时提供保密性与完整性,密文被改一个比特,解密会直接失败而不是给出一段垃圾明文。它使用 12 字节随机 nonce,密文通常按「密文 + 16 字节认证标签」拼接传输。同一密钥下 nonce 绝不能重复,重用会同时毁掉保密性和认证性。
  • CBC:老系统里最常见。需要一个 16 字节 IV,IV 不需要保密但必须随机且每次不同,解密方需要拿到同一个 IV,通常做法是把它拼在密文前面。CBC 只保证保密不保证完整,必须额外配一个 HMAC,且顺序应为「先加密再对密文算 MAC」。
  • CTR、CFB、OFB:把块密码当流密码用,不需要填充,密文长度等于明文长度。同样只提供保密性,且和 GCM 一样绝不能重用 IV 与计数器起点。
  • ECB:不要用。它对每个块独立加密,相同明文块产生相同密文块,数据的重复结构会直接从密文里透出来,图片加密后仍能看出轮廓的经典例子就是它。

密钥长度按字节严格对应:16 字节是 AES-128,24 字节是 AES-192,32 字节是 AES-256。填充方式 Pkcs7 是默认选择,NoPadding 只在明文本来就是块长整数倍时才成立。这些参数在AES与RSA在线加解密里都能直接切换,IV 长度不符会明确报错而不是给个错结果,CBC 的 IV 也可以一键随机生成。注意 GCM 与 RSA 依赖浏览器内置的 Web Crypto,要求页面运行在 HTTPS 或 localhost 下。

五、RSA 只适合加密很短的数据

RSA-OAEP 单次能加密的明文上限受模长限制,2048 位密钥大约只有 190 字节,3072 位约 318 字节。超过就必须分块,而分块的 RSA 又慢又容易实现出错。

正确做法是混合加密,这也是 TLS 和几乎所有实际系统的做法:

随机生成一把 AES 密钥 -> 用 AES-GCM 加密真正的数据 -> 用 RSA 公钥加密这把 AES 密钥 -> 两段一起传

接收方先用私钥解出 AES 密钥,再用它解数据。这样非对称算法只承担密钥交换,性能和长度问题一起解决。

另外两点容易忽略:RSA 用于加密时必须带 OAEP 填充,教科书式的裸 RSA 是不安全的;RSA 用于签名时用的是另一套填充(PKCS#1 v1.5PSS),签名和加密不要共用同一对密钥。工具支持在本地生成 2048/3072/4096 位密钥对并导出 SPKI 与 PKCS8 格式的 PEM,用来搭联调环境很方便,但请把它当成测试用密钥。

六、下载文件校验 SHA-256 的实际做法

从镜像站下载操作系统镜像、数据库安装包时,官方通常在下载页旁边挂一个 SHA256SUMS 文件或一串十六进制值。校验它是为了防两件事:传输中断导致的文件不完整,以及镜像站被替换导致的投毒。

流程很短:把文件拖进文件哈希校验,勾选 SHA-256,把官方公布的值粘进比对框,等进度跑完看结论。大小写和多余空格不影响判断。工具采用分块流式读取,GB 级镜像也不会把内存占满,整个过程只是在本地读文件计算,文件不会被上传。

三个实操细节:

  • 哈希值本身也可能被换掉。如果攻击者能改下载文件,往往也能改同一页面上的校验值。强度更高的做法是核对官方的 GPG 签名,或从另一个渠道(官方社交账号、Git 仓库的 tag)交叉确认哈希值。
  • 只出 MD5 的下载站要留个心。它至少能发现传输损坏,但防不了刻意替换。
  • 多个文件一起算能顺手发现重复。批量选中后内容完全相同的文件会被标出来,整理备份和素材目录时比按文件名比对可靠。

常见问题

摘要反查真的能还原原文吗? 不能。工具里的「摘要反查」只做一件事:拿你当前输入的内容用九种算法各算一遍,看哪个结果等于你粘贴的期望值,从而告诉你对方用的是哪种算法。它的用途是排查签名算法不一致,不是破解。

同一段文本在不同工具里算出的 HMAC 不一样,谁错了? 通常都没错,是输入不同。先查密钥编码是按 UTF-8 还是 HexBase64 解读,再查待签字符串有没有多余的换行、空格或 BOM,最后确认输出是十六进制还是 Base64。这三处任意一处不同,结果都完全不同。

AES 的 IV 需要保密吗?丢了还能解密吗? IV 不需要保密,可以明文拼在密文前面传输,但必须随机且不重复。丢了就解不开了,CBC 模式下缺 IV 意味着第一个明文块无法恢复,实践中就是整段数据报废,所以务必和密文一起存。

为什么不建议把生产私钥粘到在线工具里? 即使运算完全在本地执行、内容不上传,你也无法在使用现场证明这一点,而私钥一旦有泄露嫌疑就必须整体轮换,代价远大于省下的几分钟。请用本地生成的测试密钥对做联调,真实密钥只在服务器上用命令行工具处理。

文中用到的工具

同类教程