首页 > 解决方案 > Crypto++ PKCS5_PBKDF2_HMAC 类签名的原因?

问题描述

在PKCS5_PBKDF2_HMAC的 Crypto++ 手册中,有两个 DeriveKey 签名。

第一的:

size_t  DeriveKey (byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const NameValuePairs &params=g_nullNameValuePairs) const

第二:

size_t  DeriveKey (byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const

我想了解第一个签名中最后一个参数的用途。 NameValuePairs &params=g_nullNameValuePairs.

不幸的是,在文档中我没有找到使用示例。一般来说,我的目标是用 nullptr salts 替换第二个函数的调用,但同时我需要发送 unsigned int iterations, double timeInSecond

标签: c++interfacecrypto++

解决方案


对于您的第一个案例,此签名是KeyDerivationFunction界面的一部分。几乎所有的 KDF 都源自它。唯一不从它派生的 KDF 是P1363_KDF2,它在填充方案中用作掩码生成函数。

size_t  DeriveKey (byte *derived, size_t derivedLen,
                   const byte *secret, size_t secretLen,
                   const NameValuePairs &params=g_nullNameValuePairs) const

选择此签名是因为 KDF 的本质是获取种子或秘密,并输出派生的密钥材料。其他参数,如使用情况、迭代次数或内存成本,是增值参数。

NameValuePairs允许传递任意参数。它是必需的,因为 KDF 参数变化很大。例如,早期的 PBKDF 在其推导中经常使用单个“使用”八位字节和“迭代计数”;而 Scrypt 在其推导中使用“记忆硬度”或“成本”。随着NameValuePairs那些变化的参数可以通过一致的接口传递。

该类KeyDerivationFunction还提供了一些帮助程序,例如MinDerivedKeyLengthMaxDerivedKeyLength和。是一个虚函数,所有派生类都必须实现它。GetValidDerivedLengthIsValidDerivedLengthGetValidDerivedLength

对于您的第二种情况,此签名更专业。它被保留是因为它存在于 Crypto++ 的早期。它可以处理几个旧的 KDF,例如P1363_KDF2, PKCS12_PBKDF, PKCS5_PBKDF2_HMAC,但无法处理较新的 KDF,例如 Argon、HKDF 和 Scrypt。

size_t  DeriveKey (byte *derived, size_t derivedLen,
                   byte purpose,
                   const byte *secret, size_t secretLen,
                   const byte *salt, size_t saltLen,
                   unsigned int iterations, double timeInSeconds=0) const

如果我们想处理现代 KDF,那么具有更多参数的新签名将如下所示:

size_t  DeriveKey (byte *derived, size_t derivedLen,
                   byte purpose,
                   const byte *secret, size_t secretLen,
                   const byte *salt, size_t saltLen,
                   const byte *pepper, size_t pepperLen,  // additional data
                   const byte *info, size_t infoLen,      // additional data
                   word32 iterations,
                   word32 version,           // Argon2
                   word32 type,              // Argon2
                   word32 rho,               // Argon2
                   word64 memsize,           // Argon2
                   word64 cost,              // Scrypt
                   word64 blockSize,         // Scrypt
                   word64 parallelization    // Scrypt
                   double timeInSeconds=0 ) const

如您所见,这很快就会失控。

所以我们现在要做的是,使用KeyDerivationFunction接口并通过以下方式传递参数NameValuePairs

std::string pass("password"), salt("NaCl");
word64 cost=1024, blockSize=8, parallelization=16;

AlgorithmParameters params = MakeParameters("Cost", cost)
    ("BlockSize", blockSize)("Parallelization", parallelization)
    ("Salt", ConstByteArrayParameter((const byte*)&salt[0], salt.size()));

SecByteBlock derived(64);
scrypt.DeriveKey(derived, derived.size(), ConstBytePtr(pass), BytePtrSize(pass), params);

然而,没有什么禁止像 HKDF 或 Scrypt 这样的派生类提供DeriveKey只接受其确切参数的重载,这就是 HKDF、Scrypt 和其他 KDF 所做的。

这是 Scrypt 的重载。这些是 中使用的确切参数DeriveKey

size_t  DeriveKey (byte *derived, size_t derivedLen,
                   const byte *secret, size_t secretLen,
                   const byte *salt, size_t saltLen, 
                   word64 cost=2, word64 blockSize=8,
                   word64 parallelization=1) const

这是 HKDF 的重载DeriveKey。这些是其派生函数中使用的确切参数:

size_t  DeriveKey (byte *derived, size_t derivedLen, 
                   const byte *secret, size_t secretLen,
                   const byte *salt, size_t saltLen,
                   const byte *info, size_t infoLen) const

请注意,在 Crypto++ 6.2 的 Issue 610 下添加了带有的新KeyDerivationFunction接口:NameValuePair

以下是来自 Crypto++ wiki 的更多内容:


推荐阅读