【问题标题】:What are optimal scrypt work factors?什么是最佳 scrypt 工作因素?
【发布时间】:2012-06-22 23:43:34
【问题描述】:

我使用Java scrypt library 来存储密码。当我加密事物时,它需要Nrp 值,其文档将其称为“CPU 成本”、“内存成本”和“并行化成本”参数。唯一的问题是,我实际上并不知道它们的具体含义,或者对它们有什么好的价值;也许它们以某种方式对应于Colin Percival's original app 上的-t、-m 和-M 开关?

有人对此有什么建议吗?库本身列出了 N = 16384, r = 8 和 p = 1,但我不知道这是强还是弱还是什么。

【问题讨论】:

  • 提示:如果密码存储数据可能被劫持(即如果有备份),则不要存储密码的加密,而是与访问密钥连接的密码。这可以防止字典攻击。
  • 我已经为这个问题发布了一个通用的答案,但我当然欢迎更详细的答案,包括一些 CPU 计时和内存使用统计数据。
  • @JoopEggen 不知道你想说什么
  • @Joop Eggen:没有。 SHA1 不是密钥派生函数,即使使用盐也是如此。 不要使用。另一方面,SCrypt 是一个非常好的加密货币。很高兴,OP 意识到了基本问题。
  • @JoopEggen 在这篇文章中没有说明,但 scrypt +需要+一个明确的盐作为参数传递(在 N/r/p 旁边)。顺便说一句,强烈建议使用由加密安全 PRNG 提供的 +random+ salt(我经常使用 16 或 32 字节的 salt)

标签: java cryptography scrypt


【解决方案1】:

作为开始:

cpercival提到了in his slides from 2009周围的东西

  • (N = 2^14, r = 8, p = 1) for
  • (N = 2^20, r = 8, p = 1) for

即使在今天(2012 年 9 月),这些值对于一般用途(某些 WebApp 的密码数据库)也足够好。当然,具体取决于应用程序。

此外,这些值(大部分)意味着:

  • N:一般工作因素,迭代次数。
  • r:用于底层哈希的块大小;微调相对内存成本。
  • p:并行化因子;微调相对 CPU 成本。

rp 旨在解决 CPU 速度、内存大小和带宽未按预期增加的潜在问题。如果 CPU 性能提高得更快,你增加p,如果内存技术的突破提供一个数量级的改进,你增加rN 是为了跟上每某些时间跨度的一般性能翻倍。

重要提示:所有值都会改变结果。 (已更新:)这就是为什么所有 scrypt 参数都存储在结果字符串中的原因。

【讨论】:

  • 顺便说一句,scrypt 参数会自动存储在生成的密钥中,因此不需要单独存储。这意味着您可以在密码存储中为用户密码中的参数设置不同的值,随着时间的推移,当用户更改密码时,将使用当前参数值生成密钥(=散列密码)。
  • 感谢您指出这一点;我没有意识到链接的 Java 实现以一种理智的方式做到了这一点。
  • “顺便说一句,scrypt 参数会自动存储在生成的密钥中,因此不需要单独存储。” - 只是为了澄清(对于其他读者)这仅适用于 Java 实现. scrypt 标准和其他实现不需要将成本/参数与生成的哈希一起存储。
  • 为了澄清@elithrar 的评论,Colin Percival 本人(scrypt 的作者)使用的格式将工作因素存储在结果密钥中(详见security.stackexchange.com/questions/88678#answer-91050
  • @elithrar scrypt paper 没有详细列出格式(在定义 4,p11 中建议),但可以在 code 中看到,或者在 Colin 的 @ 中更有用987654325@(抱歉回复晚了)。
【解决方案2】:

简答

因此验证密码需要 250 毫秒

长答案

scrypt运行所需的内存计算如下:

128 字节 × cost (N) × blockSizeFactor (r)

对于您引用的参数(N=16384r=8p=1

128×16384×8 = 16,777,216 字节 = 16 MB

您在选择参数时必须考虑到这一点。

Bcrypt 比 Scrypt“弱”(尽管仍然是 three orders of magnitude stronger than PBKDF2),因为它只需要 4 KB 的内存。你想让硬件中的并行破解变得困难。例如,如果显卡有 1.5 GB 的板载内存,而您将 scrypt 调整为消耗 1 GB 内存:

128×16384×512 = 1,073,741,824 字节 = 1 GB

然后攻击者无法在他们的视频卡上并行化它。但是,您的应用程序/电话/服务器每次计算密码时都需要使用 1 GB 的 RAM。

这有助于我将 scrypt 参数视为一个矩形。地点:

  • 宽度是所需的内存量 (128*N*r)
  • 高度是执行的迭代次数
  • 得到的区域是整体硬度

  • cost (N) 增加了内存使用量迭代次数
  • blockSizeFactor (r) 增加了内存使用量

剩余的参数parallelization (p) 表示你必须将整个事情做 2、3 次或更多次:

如果您的内存比 CPU 多,您可以并行计算三个单独的路径 - 需要三倍的内存:

但在所有现实世界的实现中,它都是按顺序计算的,需要的计算量是原来的三倍:

实际上,除了p=1 之外,没有人选择过p 因素。

理想的因素是什么?

  • 尽可能多的 RAM
  • 尽您所能!

奖金图表

以上的图形版本;你的目标是~250ms:

注意事项:

  • 纵轴是对数刻度
  • 成本因子(水平)本身是对数(迭代次数 = 2CostFactor
  • r=8 曲线中突出显示

并将上述版本放大到合理区域,再次查看 ~250ms 幅度:

奖金聊天

  • 如果 scrypt 配置为使用少于 4 MB 的空间,scrypt 的密码存储比 bcrypt 弱1
  • Argon2 (i/d/id) 在用于身份验证的密码散列方面比 bcrypt 弱(即 2

【讨论】:

  • 谢谢你的分析,真的很有用。只有一个问题:我目前正在使用 Bouncy Castle 实现在 Android 上进行测试 - bouncycastle.org/docs/docs1.5on/org/bouncycastle/crypto/… 并且内存使用量恰好高出 2 倍 (128× N× r× 2)。知道为什么...?
  • @Tron 我猜是因为它会将内存复制到另一个缓冲区(即将 16MB 传递给 PBKDF2,它执行实际的最终密钥派生)。
  • 需要改进:虽然 N 确实是影响大内存块周围伪随机跳转次数的唯一因素,但计算成本仍然由 N 和 r 决定,因为有N 次迭代中的每一次迭代 4*r Salsa20/8 次(2*r 生成内存块,然后在内存块周围跳跃时 2*r)。
  • 请问为什么 r=1 不超过 2^14?
  • 但是这个答案真的很好,很好地解释了 scrypt,很棒的东西。
【解决方案3】:

我不想踩到上面提供的出色答案,但没有人真正谈论为什么“r”具有它所具有的价值。 Colin Percival 的 Scrypt 论文提供的低级答案是它与“内存延迟-带宽乘积”有关。但这实际上意味着什么?

如果你正确地使用 Scrypt,你应该有一个大的内存块,它主要位于主内存中。主内存需要时间来提取。当块跳跃循环的迭代首先从大块中选择一个元素以混合到工作缓冲区中时,它必须等待大约 100 ns 的时间才能让第一个数据块到达。然后它必须请求另一个,并等待它到达。

对于 r = 1,您将执行 4nr Salsa20/8 迭代从主内存进行 2n 延迟填充的读取。

这不好,因为这意味着攻击者可以通过构建一个对主内存的延迟减少的系统来获得优势。

但是,如果您增加 r 并按比例减少 N,您就能够实现与以前相同的内存需求并执行相同数量的计算——除了您已经将一些随机访问换成顺序访问。扩展顺序访问允许 CPU 或库有效地预取下一个所需的数据块。虽然初始延迟仍然存在,但后期块的减少或消除延迟将初始延迟平均到最低水平。因此,攻击者从改进他们的内存技术中获益甚微。

但是,随着 r 的增加,收益递减点,这与前面提到的“内存延迟-带宽乘积”有关。该产品表示的是在任何给定时间从主存储器到处理器可以传输多少字节的数据。这与高速公路的想法相同——如果从 A 点行驶到 B 点需要 10 分钟(延迟),而道路从 A 点(带宽)以 10 辆/分钟的速度运送到 B 点,则 A 点和 B 点之间的道路B 包含 100 辆汽车。因此,最佳 r 与您一次可以请求多少个 64 字节数据块有关,以掩盖初始请求的延迟。

这提高了算法的速度,允许您根据需要增加 N 以获得更多内存和计算量,或者增加 p 以获得更多计算量。

还有一些关于“r”增加太多的其他问题,我没有看到太多讨论:

  1. 增加 r 而减少 N 会减少内存周围的伪随机跳转次数。顺序访问更容易优化,并且可以给攻击者一个窗口。正如 Colin Percival 在 Twitter 上向我指出的那样,更大的 r 可以让攻击者使用成本更低、速度更慢的存储技术,从而大大降低他们的成本 (https://twitter.com/cperciva/status/661373931870228480)。
  2. 工作缓冲区的大小为 1024r 位,因此最终将被送入 PBKDF2 以生成 Scrypt 输出密钥的可能最终产品的数量为 2^1024r。围绕大内存块跳转的排列(可能的序列)数为 2^NlogN。这意味着内存跳跃循环有 2^NlogN 个可能的产品。如果 1024r > NlogN,这似乎表明工作缓冲区混合不足。虽然我不确定这一点,并且希望看到证明或反证,但可能可以在工作缓冲区的结果和跳转序列之间找到相关性,这可能允许攻击者有机会减少他们的内存需求,而不会大大增加计算成本。同样,这是基于数字的观察——可能每一轮中的一切都混合得很好,这不是问题。 r = 8 远低于标准 N = 2^14 的这个潜在阈值 - 对于 N = 2^14,这个阈值将是 r = 224。

总结所有建议:

  1. 选择的 r 大到足以平均 您设备上的内存延迟,仅此而已。请记住, Colin Percival 推荐的值,r = 8,似乎保持相当 广泛适用于内存技术,而这显然不是 8年来变化很大; 16 可能会稍微好一点。
  2. 决定每个线程要使用多大的内存块, 请记住,这也会影响计算时间,并设置 N 相应地。
  3. 将 p 增加到您的使用可以容忍的任意高值(注意: 在我的系统上并使用我自己的实现,p = 250 (4 线程)与 N = 16384 和 r = 8 需要〜5秒),并启用 如果您可以处理增加的内存成本,请使用线程。
  4. 调整时,更喜欢大的 N 和内存块大小,而不是增加 p 和 计算时间。 Scrypt 的主要优势来自其庞大的 内存块大小。

我自己在具有 i5-4300(2 核,4 线程)的 Surface Pro 3 上实现 Scrypt 的基准测试,使用常数 128Nr = 16 MB 和 p = 230;左轴是秒,下轴是 r 值,误差线是 +/- 1 标准偏差:

【讨论】:

  • 很棒的桌子!看起来有 1 个线程,N=8192,r=16,p=1(使用 16MB 内存),每次在您的系统和实现上尝试进行身份验证的时间成本约为 40 毫秒。这真是一笔不错的费用。 N=16834, r=8, p=1 只是稍微慢了一点,但看起来确实比更大的 r 有轻微但一致的优势。
猜你喜欢
  • 2011-05-25
  • 1970-01-01
  • 2012-03-20
  • 2016-10-12
  • 2012-06-25
  • 2010-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多