scrypt
本文约需 2 分钟阅读
scrypt 是一种内存困难型密码哈希函数,通过消耗大量内存来抵御 GPU 和 ASIC 的并行攻击。 2009 年由 Colin Percival 为在线备份服务 Tarsnap 的密钥派生而设计。与 CPU 受限的 bcrypt 不同, scrypt 要求内存受限的计算,从而将攻击成本提高数个数量级。它也作为加密货币 Litecoin 的工作量证明算法而广为人知。
历史背景
2000 年代后期, GPU 通用计算 (GPGPU) 迅速普及,针对 bcrypt 这类 CPU 受限哈希函数的暴力破解攻击成为现实威胁。针对这一问题, Colin Percival 以「不仅消耗计算,还大量消耗内存,就能使 GPU 的并行性失效」的思路设计了 scrypt。 2009 年它被用于 Tarsnap 的备份加密, 2012 年作为 RFC 7914 实现标准化。 2011 年问世的 Litecoin 采用 scrypt 后,它也在加密货币社区中获得广泛认知。
ROMix 算法的原理
scrypt 的核心是一种名为 ROMix 的算法。处理大致分为两个阶段。
从初始值生成 N 个伪随机块,并存入一个巨大的数组。当 N = 2^20 (约 100 万) 时,会消耗 1 GB 以上的内存。如果不保留整个数组,就无法进入下一阶段。
一边随机引用数组中的位置 N 次,一边混合数值。由于引用位置依赖于前一步的计算结果,无法事先预测。减少内存就需要重新计算,时间成本会急剧增加。
这种「减少内存就会使计算时间爆炸式增长」的特性,正是 scrypt 内存困难性的本质。当攻击者试图节省内存以提高并行度时,每个实例的计算时间会以平方级增长,因此总的攻击成本并不会降低。
与 Argon2、bcrypt 的比较
| 特性 | bcrypt | scrypt | Argon2id |
|---|---|---|---|
| 问世年份 | 1999 | 2009 | 2015 |
| 内存困难 | ✗ | ✓ | ✓ |
| 旁路攻击抗性 | 高 | 低 (数据依赖访问) | 高 (Argon2id 的混合方式) |
| 参数的直观性 | 只有一个成本参数,简单 | N, r, p 之间的关系复杂 | 内存、时间、并行度相互独立 |
| OWASP 推荐排序 | 第 2 位 | 第 3 位 | 第 1 位 |
| 在加密货币中的采用 | 无 | Litecoin、Dogecoin 等 | 部分抗挖矿设计 |
参数设计 (N, r, p)
scrypt 有 3 个参数,理解各自的作用及相互关系非常重要。
将 N 加倍会使内存用量和计算时间都翻倍。由于参数之间的相互依赖较为复杂,与 Argon2id 这种可独立调整内存、时间、并行度的算法相比,调优难度更高。请使用 16 字节以上的盐,并遵循密码哈希的基本原则进行保存。
Litecoin 中的采用
2011 年问世的 Litecoin 采用 scrypt 取代 Bitcoin 的 SHA-256 作为工作量证明算法。当时的目的是「防止 ASIC 对挖矿的寡头垄断,让普通 PC 也能参与挖矿」。然而 2014 年前后出现了支持 scrypt 的 ASIC,最初的目的并未实现。这一经验留下了一个教训:即使是内存困难型函数,如果没有足够的内存需求量,也无法对抗专用硬件。关于加密货币的安全,我们在加密货币钱包安全中进行了说明。
常见误解
有人认为「scrypt 太老了,不应再使用」,但只要采用适当的参数运行,截至 2025 年它仍能提供足够的安全性。 OWASP 也将其推荐为仅次于 Argon2id、 bcrypt 的第三选择。不过,实务上的做法是:新系统首选 Argon2id,当需要与现有系统兼容时再选择 scrypt。关于加密的基础,请参阅加密基础;关于密码管理的整体概览,也请参考安全密码管理指南。密码技术入门书 (Amazon)可进一步深入学习。
这篇文章对您有帮助吗?