c++ - 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 ¶ms=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 ¶ms=g_nullNameValuePairs
.
不幸的是,在文档中我没有找到使用示例。一般来说,我的目标是用 nullptr salts 替换第二个函数的调用,但同时我需要发送 unsigned int iterations, double timeInSecond
。
解决方案
对于您的第一个案例,此签名是KeyDerivationFunction
界面的一部分。几乎所有的 KDF 都源自它。唯一不从它派生的 KDF 是P1363_KDF2
,它在填充方案中用作掩码生成函数。
size_t DeriveKey (byte *derived, size_t derivedLen,
const byte *secret, size_t secretLen,
const NameValuePairs ¶ms=g_nullNameValuePairs) const
选择此签名是因为 KDF 的本质是获取种子或秘密,并输出派生的密钥材料。其他参数,如使用情况、迭代次数或内存成本,是增值参数。
NameValuePairs
允许传递任意参数。它是必需的,因为 KDF 参数变化很大。例如,早期的 PBKDF 在其推导中经常使用单个“使用”八位字节和“迭代计数”;而 Scrypt 在其推导中使用“记忆硬度”或“成本”。随着NameValuePairs
那些变化的参数可以通过一致的接口传递。
该类KeyDerivationFunction
还提供了一些帮助程序,例如MinDerivedKeyLength
、MaxDerivedKeyLength
和。是一个虚函数,所有派生类都必须实现它。GetValidDerivedLength
IsValidDerivedLength
GetValidDerivedLength
对于您的第二种情况,此签名更专业。它被保留是因为它存在于 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 的更多内容: