“加密”不是一个单一需求:保护传输中的数据、存储用户的密码、校验文件是否被篡改,需要的是完全不同的算法。选错工具,看似加了密,实则形同虚设。本文把常用算法分为对称加密、非对称加密、哈希、消息认证四类,讲清各自的定位与典型误用。

先想清楚要解决什么问题

密码学算法不是 interchangeable 的零件,每一类回答一个特定问题:

  • 机密性:数据不能被旁观者读懂 → 用对称或非对称加密。
  • 完整性:数据有没有被改动过 → 用哈希做指纹。
  • 真实性:消息确实来自持有密钥的人,且没被改动 → 用 HMAC 或数字签名。
  • 口令验证:能判断用户输入对不对,但服务器自己也不该知道原密码 → 用加盐慢哈希。

先把目标说清楚,算法选型基本就定了一半。

四类算法的定位

对称加密:AES 保护大量数据

对称加密(Symmetric Encryption)用同一把密钥加密和解密。AES 是目前事实标准,分组长度 128 位,密钥可选 128/192/256 位。它速度极快(CPU 有 AES-NI 硬件指令),适合加密数据库字段、文件、TLS 会话里的业务数据。

使用时的两个关键点:

  1. 选对模式。ECB 模式下相同明文块产生相同密文块,会泄露数据结构,必须禁用。推荐带认证的 AEAD 模式 AES-GCM,加密的同时产出认证标签,密文被篡改会解密失败。
  2. IV 不能重复。GCM 模式下同一密钥复用同一个 IV 是灾难性的,每次加密应随机生成 12 字节 IV,随密文一起存储即可(IV 不需要保密)。

非对称加密:RSA 与 ECC 解决密钥分发

非对称加密(Asymmetric Encryption)使用公钥/私钥对:公钥可以公开,私钥自己保管。它解决的是对称加密的死穴——密钥怎么安全地交给对方。

  • RSA 基于大数分解难题,可加密也可签名,2048 位起步。运算慢、密文长度受限,实际项目里几乎不直接加密业务数据,而是加密一把随机对称密钥(即”混合加密”),HTTPS 握手就是这么干的。
  • ECC(椭圆曲线密码,如 ECDSA、Ed25519、ECDHE)在同等安全强度下密钥更短、运算更快,256 位 ECC 约等于 3072 位 RSA,移动端和区块链领域用得更多。

签名方向恰好相反:发送方用私钥签名,接收方用公钥验证,用于证明身份与防抵赖。

哈希:SHA-256 做数据指纹

哈希算法把任意长度输入映射为固定长度摘要,是单向过程——严格说它不属于”加密”,因为不存在解密。MD5、SHA-1 已被证明可碰撞,禁止再用于安全场景;SHA-256、SHA-512 及 SHA-3 系列是当前主力,典型用途是文件完整性校验、Git 对象标识、签名前的摘要。

消息认证:HMAC 证明”自己人发的”

普通哈希谁都能算,无法证明消息来源。HMAC 把密钥混入哈希计算(如 HMAC-SHA-256),只有持有同一把密钥的双方才能算出正确的认证码,常用于 API 请求签名、Webhook 回调验签。注意 HMAC 双方共享密钥,不能防抵赖;要防抵赖得用非对称签名。

常见误用:MD5 存密码为什么不行

这是最经典也最常见的错误。用 MD5(甚至加盐的 SHA-256)存密码,问题出在三点:

  1. 算得太快。通用哈希的设计目标就是快,一张消费级显卡每秒能试几十亿次 MD5。数据库泄露后,攻击者离线穷举弱口令字典,几小时就能还原大量账号。
  2. 相同密码哈希相同。不加盐时,全网用 123456 的用户哈希值一模一样,彩虹表(预先算好的哈希对照表)一查一个准。
  3. MD5 本身已破。碰撞攻击早已实用化,它连”完整性校验”这个本职都不合格了。

正确姿势是加盐 + 慢哈希:

  • 盐(Salt):每个用户独立生成的随机值,与密码一起参与哈希,随哈希结果一起存储。盐不需要保密,它的作用是让彩虹表失效——攻击者必须为每个盐单独建表,预计算优势归零。
  • 慢哈希:bcrypt、scrypt、Argon2 专为口令设计,故意消耗可观的 CPU 和内存。Argon2id 是当下首选,可分别调节时间、内存和并行度;bcrypt 通过 cost 参数控制迭代轮次,还能随硬件升级调高。对登录接口来说每次多花几十毫秒无所谓,对离线爆破者来说成本却放大了亿倍。

Spring Security 里一行配置即可:

@Bean
public PasswordEncoder passwordEncoder() {
// cost 需结合服务器性能压测确定,并定期上调
return new BCryptPasswordEncoder(12);
}

另外记住:口令哈希只做”验证”,比对时用库提供的 matches 方法,不要自己拼盐、不要直接字符串比较。

实践要点

  • 不要自己发明算法或协议,用成熟实现(JDK 自带 JCE、Bouncy Castle、Tink)。
  • 密钥不进代码仓库、不写日志,交给 KMS 或 KeyStore 保管,按用途隔离并定期轮换。
  • 密文旁边记录算法与版本号,未来升级时按版本迁移,避免一次性停机重加密。
  • 加密防的是”外人读不懂”,防不了越权访问、XSS、SQL 注入,别把它当万能安全层。

小结

  • AES(GCM 模式)负责数据机密性,RSA/ECC 负责密钥分发与签名,SHA-256 做完整性指纹,HMAC 在共享密钥下证明消息来源。
  • 哈希不可逆、无密钥;加密可逆、有密钥——两者解决的问题不同。
  • 密码存储永远用加盐慢哈希(Argon2id/bcrypt),MD5、SHA-256 这类快哈希在此场景下加盐也不合格。