密码生成单向不可逆-bcrypt算法
BCrypt 是一种基于 Blowfish 加密算法的密码哈希函数,由 Niels Provos 和 David Mazières在 1999 年提出,设计目标是安全地存储密码。
核心特点
自适应成本因子(Cost Factor / Work Factor)
- 可以调整计算难度,随着硬件性能提升,逐步增加迭代次数
- 默认成本因子通常为10(5+),每增加 1,迭代次数翻倍(2¹⁰ → 2¹¹ → 2¹² …)
自动加盐(Salt)
- 每次哈希都自动生成一个随机的 16 字节 salt
- 防止彩虹表攻击(rainbow table attack)
单向不可逆
- 只能验证,不能还原原始密码
算法流程
密码 + 盐 → Blowfish 密钥调度 → 密钥扩展(反复加密空字符串) → 哈希输出
具体步骤:
- 生成 Salt:随机生成 16 字节 salt,与 cost factor 一起编码
- 初始化 Blowfish 状态:使用 Blowfish 的密钥调度算法(Key Schedule),将密码和 salt 混合到 P-array 和 S-box 中
- 密钥扩展(Key Expansion):反复用 Blowfish 加密空字符串,不断重新初始化状态。迭代次数为 2^cost
- 最终编码:将最终的 P-array 和 S-box 状态输出,与 salt 一起用 Modified Oracle’s Base64 编码
输出格式
$2b$12$<22字符salt><31字符hash>
例如:
$2b$12$WApznUPhDubN0oe1fqfQ8OZiQREdiCRt9gOqwllZ1XPJiGNLHjOmq
| 部分 | 说明 |
|---|---|
$2b$ |
算法版本号(2a/2b/2y 有细微差异) |
12 |
cost factor(成本因子) |
| 前22字符 | Base64 编码的 salt(16 字节) |
| 后31字符 | Base64 编码的哈希值(31 字节,来自 72 字节输出截断) |
验证密码
验证时提取盐值,用相同成本因子重新计算哈希,然后与存储的哈希值进行恒定时间比较(timing-safe comparison):
1 | import bcrypt |
安全性
优点
- 抗彩虹表攻击(自动加盐)
- 可通过调整 cost factor 适应硬件发展
- 密码长度上限 72 字节,超出部分被截断
- 实现简单,广泛使用
缺点 / 注意事项
- 内存消耗低,容易被 GPU/ASIC 大规模并行破解
- 72 字节密码截断限制(bcrypt 基于 Blowfish,其子密钥最长 56 字节)
- 在需要抗 GPU 攻击的场景,建议使用 Argon2、scrypt 或 PBKDF2(配合高迭代次数)
- Argon2 已赢得 Password Hashing Competition (PHC),被推荐为新一代标准
与其他算法对比
| 算法 | 抗 GPU | 内存消耗 | 推荐场景 |
|---|---|---|---|
| BCrypt | 弱 | 低 | 传统场景,兼容性要求高 |
| scrypt | 中 | 中高 | 需要抗硬件加速 |
| PBKDF2 | 弱 | 低 | HSM / 合规要求场景 |
| Argon2 | 强 | 高 | 当前推荐首选 |
最佳实践
- cost factor ≥ 12(可根据服务器性能调整,确保哈希耗时 250ms–1s)
- 不要自己生成 salt,让库自动处理
- 使用成熟库(如 Go 的
golang.org/x/crypto/bcrypt、Python 的bcrypt、Java 的jBCrypt) - 传输层加密:bcrypt 只保护存储,传输必须用 TLS
- 新项目优先考虑 Argon2id