OpenSSL

密码学与SSL/TLS工具包

EVP_KDF-SCRYPT

名称

EVP_KDF-SCRYPT - scrypt EVP_KDF 实现

描述

通过EVP_KDF API 支持计算scrypt 基于密码的密钥派生函数。

EVP_KDF-SCRYPT 算法实现了 scrypt 基于密码的密钥派生函数,如 RFC 7914 中所述。它在内存方面是困难的,因为它故意需要大量的 RAM 才能进行高效计算。这样做的目的是使在缺乏大量主内存(如 GPU 或 ASIC)的系统上对密码进行暴力破解在计算上不可行。

scrypt 提供了三个可以自定义的工作因子:N、r 和 p。N 必须是 2 的正整数次幂,是通用工作因子,并以近似线性的方式扩展 CPU 时间。r 是内部使用的哈希函数的块大小,p 是并行因子。r 和 p 都需要大于零。scrypt 计算所需的 RAM 量大约为 (128 * N * r * p) 字节。

在 Colin Percival 的原始论文(“通过顺序内存困难函数增强密钥派生”,2009 年)中,建议的值在 2.5 GHz 英特尔酷睿 2 Duo 上的计算时间小于 5 秒,N = 2^20 = 1048576、r = 8、p = 1。因此,此计算所需的内存量约为 1 GiB。在更新的 CPU(3.5 GHz 英特尔 i7-5930K)上,此计算大约需要 3 秒。当未指定 N、r 或 p 时,它们分别默认为 1048576、8 和 1。scrypt 使用的最大 RAM 量默认为 1025 MiB。

标识

"SCRYPT" 是此实现的名称;它可以与 EVP_KDF_fetch() 函数一起使用。

支持的参数

支持的参数为:

"pass" (OSSL_KDF_PARAM_PASSWORD) <八位字节串>
"salt" (OSSL_KDF_PARAM_SALT) <八位字节串>

这些参数的工作方式如 "EVP_KDF(3) 中的参数" 中所述。

"n" (OSSL_KDF_PARAM_SCRYPT_N) <无符号整数>
"r" (OSSL_KDF_PARAM_SCRYPT_R) <无符号整数>
"p" (OSSL_KDF_PARAM_SCRYPT_P) <无符号整数>
"maxmem_bytes" (OSSL_KDF_PARAM_SCRYPT_MAXMEM) <无符号整数>

这些参数配置 scrypt 工作因子 N、r、maxmem 和 p。N 和 maxmem_bytes 都是 uint64_t 类型的参数。r 和 p 都是 uint32_t 类型的参数。

"properties" (OSSL_KDF_PARAM_PROPERTIES) <UTF8 字符串>

这可用于在内部获取固定摘要时设置属性查询字符串。如果未设置此值,则使用 NULL。

注释

可以通过调用以下命令获取 scrypt 的上下文:

EVP_KDF *kdf = EVP_KDF_fetch(NULL, "SCRYPT", NULL);
EVP_KDF_CTX *kctx = EVP_KDF_CTX_new(kdf);

scrypt 密钥派生的输出长度通过 EVP_KDF_derive(3) 函数的 "keylen" 参数指定。

示例

此示例使用密码 "password"、盐 "NaCl" 和 N = 1024、r = 8、p = 16 使用 scrypt 派生 64 字节长的测试向量。

EVP_KDF *kdf;
EVP_KDF_CTX *kctx;
unsigned char out[64];
OSSL_PARAM params[6], *p = params;

kdf = EVP_KDF_fetch(NULL, "SCRYPT", NULL);
kctx = EVP_KDF_CTX_new(kdf);
EVP_KDF_free(kdf);

*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD,
                                         "password", (size_t)8);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
                                         "NaCl", (size_t)4);
*p++ = OSSL_PARAM_construct_uint64(OSSL_KDF_PARAM_SCRYPT_N, (uint64_t)1024);
*p++ = OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_SCRYPT_R, (uint32_t)8);
*p++ = OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_SCRYPT_P, (uint32_t)16);
*p = OSSL_PARAM_construct_end();
if (EVP_KDF_derive(kctx, out, sizeof(out), params) <= 0) {
    error("EVP_KDF_derive");
}

{
    const unsigned char expected[sizeof(out)] = {
        0xfd, 0xba, 0xbe, 0x1c, 0x9d, 0x34, 0x72, 0x00,
        0x78, 0x56, 0xe7, 0x19, 0x0d, 0x01, 0xe9, 0xfe,
        0x7c, 0x6a, 0xd7, 0xcb, 0xc8, 0x23, 0x78, 0x30,
        0xe7, 0x73, 0x76, 0x63, 0x4b, 0x37, 0x31, 0x62,
        0x2e, 0xaf, 0x30, 0xd9, 0x2e, 0x22, 0xa3, 0x88,
        0x6f, 0xf1, 0x09, 0x27, 0x9d, 0x98, 0x30, 0xda,
        0xc7, 0x27, 0xaf, 0xb9, 0x4a, 0x83, 0xee, 0x6d,
        0x83, 0x60, 0xcb, 0xdf, 0xa2, 0xcc, 0x06, 0x40
    };

    assert(!memcmp(out, expected, sizeof(out)));
}

EVP_KDF_CTX_free(kctx);

符合标准

RFC 7914

参见

EVP_KDF(3)EVP_KDF_CTX_new(3)EVP_KDF_CTX_free(3)EVP_KDF_CTX_set_params(3)EVP_KDF_derive(3)"EVP_KDF(3) 中的参数"

历史

此功能在 OpenSSL 3.0 中添加。

版权所有 2017-2021 OpenSSL 项目作者。保留所有权利。

根据 Apache 许可证 2.0(“许可证”)授权。除非符合许可证,否则您不得使用此文件。您可以在源代码分发中的 LICENSE 文件或 https://www.openssl.org/source/license.html 中获取副本。