哈希与加密算法速查表

哈希与加密算法速查:MD5/SHA-1/SHA-256/SHA-3/HMAC 等哈希算法,bcrypt/scrypt/Argon2 等密码哈希,AES/RSA/ECC 加密算法的输出长度、安全性与最佳用途。

原理解析

哈希(散列)把任意长度输入映射为固定长度的摘要,且是单向的:从原文容易算摘要,从摘要几乎无法反推原文。理想哈希具备雪崩效应(输入改 1 位,输出彻底改变)与强抗碰撞性。

常见家族:MD5/SHA-1 已因碰撞攻击被淘汰于安全场景;SHA-256 属 SHA-2 仍安全;SHA-3 为另一设计。用途涵盖完整性校验、数字签名、口令存储(须加盐防彩虹表)。安全场景切勿再用 MD5/SHA-1。

什么时候该查这张表

这张表在你要为某处数据选择哈希算法时有用。它列出 MD5、SHA-1、SHA-2 系列、SHA-3 系列、CRC、xxHash 等算法的类型、输出长度、安全性与最佳用途。选哈希前先分清是「要防篡改」还是「仅做分片/去重」。

不该查的情况:你在设计密码存储方案,或需要抗碰撞的签名。哈希算法的碰撞概率与「防篡改」是不同维度的问题;密码存储要用专门的 KDF(Argon2、bcrypt、scrypt),而不是任何摘要算法。

判断标准:先问用途。数据完整性校验(文件是否损坏、下载是否被改)⇒ CRC32 或 xxHash 快且够用;防伪与签名(攻击者会主动构造碰撞)⇒ SHA-256 以上;已不该用于安全目的的 MD5/SHA-1 只在兼容老系统时保留。

特别注意长度扩展攻击:SHA-256 本身不抵抗长度扩展攻击(SHA-3、Blake2 抵抗)。如果你的协议是「H(secret || message)」这种构造,攻击者能在不知道 secret 的情况下扩展出 H(secret || message || padding || extra)。需要 MAC 就直接用 HMAC,不要自己拼。

边界与常见陷阱

  • MD5 与 SHA-1 已不安全,碰撞是可构造的

    MD5 与 SHA-1 都已出现实用可行的碰撞构造(MD5 几秒内可造出两个不同文件同哈希;SHA-1 的 SHAttered 攻击 2017 年公开且成本已降至约 4.5 万美元并持续下降)。后果是:文件签名、证书完整性、去重键校验全部可被绕过。碰撞不一定能直接用于第二原像攻击,但签名场景已经足够。新代码一律用 SHA-256 或 SHA-3/BLAKE2。

  • 自拼 H(secret || data) 不等于 MAC

    「hash(secret + message)」 存在长度扩展弱点:攻击者即使不知道 secret,也能给出 hash(secret + msg + padding + extra) 的合法值,从而篡改「追加」部分。SHA-256 抗碰撞但不抗长度扩展(SHA-3、BLAKE2 抗)。正确做法是用 HMAC(「HMAC-SHA256」),它从设计上处理了这个问题;Node 里用 crypto.createHmac。

  • 加密散列不代表能存密码

    通用哈希(哪怕 SHA-256)设计目标是快,这正是密码存储最不需要的性质 —— 攻击者用 GPU 每秒能算几十亿次。密码必须用故意慢且自带盐与成本参数的 KDF:Argon2id(首选)、bcrypt、scrypt、PBKDF2。这三者内部再加盐并可调迭代次数,让暴力破解成本高到不可行。迁移旧哈希时也要用「登录时重新计算并升级」的渐进方案。

与相邻内容的分工

要生成或校验哈希值,用站内哈希工具类;本页是算法选型对照,不提供计算能力。

要处理 UUID 与各种标识符的生成与选择,用站内 UUID 与随机工具;哈希不能替代唯一标识符。

涉及数字签名与证书链的完整设计,属密码学体系范畴,本表不覆盖。

若目的是排查某个系统为何仍用 MD5/SHA-1,通常是兼容性约束(老数据、第三方对接),要先确认来源再谈替换。

实战片段

要点:① 按用途选算法 —— 完整性校验可用 CRC32/xxHash,对抗性场景必须 SHA-256 以上,密码绝不用通用哈希;② 自拼 hash(secret + data) 存在长度扩展攻击,密钥场景一律用 crypto.createHmac;③ 密码存储必须用带盐与成本参数的 KDF(Argon2id/bcrypt/scrypt/PBKDF2),通用哈希太快,GPU 每秒几十亿次;④ 任何 token 或签名比较都要用 timingSafeEqual,防时序侧信道;⑤ 迁移旧哈希用渐进方案,登录成功时顺手升级为 KDF 格式。

import { createHash, createHmac, randomBytes, scryptSync, timingSafeEqual } from 'crypto'

// ① 按用途选算法
const BY_PURPOSE = {
  integrity:  'sha256',   // 校验数据是否被改(可配 HMAC)
  signature:  'sha256',   // 对抗性场景:碰撞必须难构造
  password:   null,       // 🔴 密码绝不用 createHash,走 KDF
  dedup:      'xxhash64', // 仅做分片/去重,可以快
}

// ② 内容指纹:数据量大时可只取前 8 字节十六进制
function fingerprint(data, algo = 'sha256') {
  const hex = createHash(algo).update(data).digest('hex')
  return hex.slice(0, 16)   // 16 字符 = 64 bit,亿级条目碰撞率可接受
}

// ③ 🔴 密钥场景必须用 HMAC,不能自己拼 hash(secret + data)
function mac(data, secret) {
  return createHmac('sha256', secret).update(data).digest()
}
// ❌ 有长度扩展攻击:
//   const bad = createHash('sha256').update(secret + data).digest('hex')
//   攻击者可算出 hash(secret + data + padding + extra) 的合法值

// ④ 密码存储:用 KDF + 随机盐,绝不用 sha256
function hashPassword(password) {
  const salt = randomBytes(16)
  const key = scryptSync(password, salt, 64, { N: 16384, r: 8, p: 1 })
  return { salt: salt.toString('hex'), key: key.toString('hex') }
}
function verifyPassword(password, stored) {
  const key = scryptSync(password, Buffer.from(stored.salt, 'hex'), 64, { N: 16384, r: 8, p: 1 })
  // 定长比较,防时序侧信道
  return timingSafeEqual(key, Buffer.from(stored.key, 'hex'))
}

// ⑤ 常量时间比较:任何 token / 签名校验都要用
function safeEqual(a, b) {
  const ba = Buffer.from(a), bb = Buffer.from(b)
  return ba.length === bb.length && timingSafeEqual(ba, bb)
}

// ⑥ 迁移旧哈希:登录成功时升级为 KDF
function upgradeIfNeeded(password, legacyMd5) {
  const mine = createHash('md5').update(password).digest('hex')
  if (!safeEqual(mine, legacyMd5)) return null
  return hashPassword(password)   // 登录时顺手换成 KDF 格式

实践注解

  • MD5 与 SHA-1 已不适用于安全场景两者都存在实用化的碰撞攻击(MD5 碰撞已可秒级构造),可用于校验传输完整性,但不可用于签名、口令或防篡改。安全场景一律 SHA-256 起步。
  • 直接哈希口令等于把口令库送给攻击者无盐的 SHA-256 在 GPU 上每秒可试数十亿次。口令必须使用带工作因子的算法(bcrypt、scrypt、Argon2),并保证每个用户独立盐值;哈希与口令校验是两件不同的事。
  • HMAC 不是「哈希加盐」HMAC = H(K ⊕ opad ‖ H(K ⊕ ipad ‖ m)),结构上防长度扩展攻击,而简单的 H(secret ‖ message) 存在长度扩展弱点。用哈希拼接密钥做签名是不安全的替代品。

数据来源

  • NIST FIPS 180-4 (SHA family)
  • RFC 1321 (MD5)
  • RFC 9106 (Argon2)
  • RFC 8018 (PBKDF2)
  • FIPS 197 (AES)
  • RFC 8017 (RSA)

上述编号、名称与定义均来自公开规范,本站不主张对规范数据本身的独创性;本页的编排方式、中文释义与实践注解由本站撰写。

算法类型输出 / 长度安全性最佳用途
MD5哈希128 bit已破解文件校验和(非安全用途)
SHA-1哈希160 bit已碰撞,弃用旧系统兼容、Git 对象
SHA-224哈希 (SHA-2)224 bit安全较少使用的 SHA-2 变体
SHA-256哈希 (SHA-2)256 bit安全证书、区块链、数字签名(最常用)
SHA-384哈希 (SHA-2)384 bit安全高安全等级场景
SHA-512哈希 (SHA-2)512 bit安全高安全等级场景
SHA-3哈希 (Keccak)224/256/384/512 bit安全SHA-2 的标准化备选
RIPEMD-160哈希160 bit基本安全比特币地址生成
HMAC消息认证码随底层哈希安全(需密钥)API 签名、webhook 校验
bcrypt密码哈希60 字符安全(可调 cost)密码存储(支持广泛)
scrypt密码哈希可变安全(内存硬)抗 ASIC 的密码存储
Argon2密码哈希可变安全(现代首选)新项目密码存储首选
PBKDF2密码哈希可变安全(靠迭代)兼容性要求高的场景
AES对称加密128/192/256 bit安全数据加密(推荐 GCM 模式)
RSA非对称加密2048/4096 bit安全(密钥够长)密钥交换、数字签名
ECC非对称加密256 bit 起安全(短密钥)移动端与 TLS,效率高
TOTP一次性口令6-8 位安全(短时效)两步验证 2FA
CRC32校验和32 bit非加密传输完整性校验
Base64编码(非加密)变长非加密二进制转文本传输

常见问题

MD5 还能用吗?

不能用于任何安全目的:MD5 已被证实可人为制造碰撞,可被伪造签名与证书。它只适合非恶意场景的文件完整性校验(如下载包校验)。安全用途应选 SHA-256 及以上。

密码存储该用什么算法?

必须用专门的密码哈希函数,优先级:Argon2(现代首选)> scrypt > bcrypt > PBKDF2。绝不能用 MD5、SHA-1、SHA-256 这类快速哈希裸存密码(即使加盐),因为它们计算太快、易被 GPU 暴力破解;盐值与 cost 参数交给成熟库处理。

哈希(Hash)和加密(Encrypt)有什么区别?

哈希是单向的:任意长度输入映射为固定长度摘要,无法反推原文,用于完整性校验与密码存储。加密是双向的:用密钥把明文变成密文,持有密钥可解密还原,用于保密传输与存储。Base64 只是编码,两者都不是。

SHA-256 和 SHA-3 该怎么选?

默认选 SHA-256:性能与生态最好,硬件加速普及,库支持最全。SHA-3 内部结构与 SHA-2 完全不同,适合做算法多样化备选(防止 SHA-2 未来被攻破时的单点风险)。二者当前都被认为是安全的。