Scrypt

ScryptRFC 7914)是一种强密码学密钥派生函数(KDF)。它属于内存密集型算法,旨在防御 GPUASICFPGA 攻击(高效的密码破解硬件)。

Scrypt 算法接受多个输入参数,并输出派生密钥

key = Scrypt(password, salt, N, r, p, derived-key-len)

Scrypt 参数

Scrypt 配置参数包括:

  • N——迭代次数(影响内存和 CPU 用量),例如 16384 或 2048
  • r——分组大小(影响内存和 CPU 用量),例如 8
  • p——并行因子(并行运行的线程数,会影响内存和 CPU 用量),通常为 1
  • password——输入密码(建议最短长度为 8-10 个字符)
  • salt——安全生成的随机字节(至少 64 位,建议 128 位)
  • derived-key-length——要生成并输出的字节数,例如 32 字节(256 位)

Scrypt 在每一步都以高度依赖的顺序访问内存,因此内存访问速度是算法的瓶颈。计算 Scrypt 密钥派生的所需内存如下:

Memory required = 128 * N * r * p bytes

示例:128 * N * r * p = 128 * 16384 * 8 * 1 = 16 MB\ (或 128 * N * r * p = 128 * 2048 * 8 * 1 = 2 MB)

参数选择取决于愿意等待多长时间,以及希望达到何种安全级别(密码破解抵抗力):

  • 交互式登录的示例参数:N=16384, r=8, p=1(RAM = 16 MB)。进行交互式登录时,你很可能不愿等待超过 0.5 秒,因此计算不应过慢。此外,服务器端通常会有许多用户同时登录,缓慢的 Scrypt 计算将拖慢整个系统。
  • 文件加密的示例参数:N=1048576, r=8, p=1(RAM = 1 GB)。加密硬盘时,很少需要解锁加密数据,通常每天不超过 2-3 次,因此可以接受等待 2-3 秒来提高安全性。

在设计和开发应用或系统时,可以自行测试并选择 Scrypt 参数。务必尽量为所用语言和平台选择速度最快的 Scrypt 实现,因为破解者必然也会这样做。某些实现(如 Python 实现)可能比最快实现慢 100 倍!

MyEtherWallet 加密货币钱包中,默认 Scrypt 参数为 N=8192, r=8, p=1。这些设置对加密货币钱包来说不够强,但其实际实现就是如此。解决办法是使用长而复杂的密码,以避免密码破解攻击。

Scrypt——示例

可以在这里在线试用 Scrypt 密钥派生:https://8gwifi.org/scrypt.jsp

在 Python 中计算 Scrypt——示例

现在编写一些 Python 代码,使用 Scrypt 算法从密码派生密钥。

首先,使用以下命令安装 Python 包 scrypt

pip install scrypt

请注意,scrypt 包依赖 OpenSSL,因此应先将 OpenSSL 安装到默认位置(例如 Windows 中的 C:\OpenSSL-Win64),再安装 scrypt Python 包。

成功安装 scrypt 包后,编写用于计算 Scrypt 哈希的 Python 代码:\ (注意,我们选择了较小的迭代次数,只是为了提高以下示例的执行速度。在一般用法中,建议采用更高的迭代次数,例如 16384——参见上文。

import pyscrypt

salt = b'aa1f2d3f4d23ac44e9c5a6c3d8f9ee8c'
passwd = b'p@$Sw0rD~7'
key = pyscrypt.hash(passwd, salt, 2048, 8, 1, 32)
print("Derived key:", key.hex())

运行上面的代码示例:https://repl.it/@nakov/Scrypt-in-Python

Scrypt 计算函数接受多个输入参数密码(字节序列)、(字节序列)、迭代次数、每次迭代的分组大小并行因子和输出密钥长度(派生密钥的字节数)。

上述代码执行的输出如下:

Derived key: b'e813a6f6ccc4e9110193bf9efb7c0a489d76655f9e36629dccbeaf2a73bc0c6f'

尝试修改迭代次数或分组大小,观察它们如何影响执行时间。请注意,上述 Python 实现速度并不快,可以在互联网上寻找更快的 Scrypt 实现。

将算法设置 + 盐 + 哈希一同存储

在许多应用、框架和工具中,Scrypt 密码哈希会与算法设置和盐一同存储在一个具有特定格式的字符串中。该字符串由多个部分组成,以 $ 字符分隔。例如,密码 p@ss~123 可以按如下 Scrypt 标准格式存储(这里给出多个示例,以便看清其模式):

16384$8$1$kytG1MHY1KU=$afc338d494dc89be40e317788e3cd9166d066709db0e6481f0801bd918710f46
16384$8$1$5gFGlElztY0=$560f6229356c281a525fad4e2fc4c209bb55c21dec789381335a32bb84888a5a
32768$8$4$VGhlIHF1aWo=$54d657cec8b3aaca675b407e790bccf1dddb0a23665cd5f994820a736d4b58ba

何时使用 Scrypt?

正确配置时,Scrypt 被认为是一种高度安全的 KDF 函数,因此可以把它用作通用的基于密码的密钥派生算法,例如用于加密钱包、文件或应用密码。

results matching ""

    No results matching ""