Crypto++ PKCS5_PBKDF2_HMAC class 签名的原因?

Reason for the signature of Crypto++ PKCS5_PBKDF2_HMAC class?

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 盐,但同时我需要发送 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 &params=g_nullNameValuePairs) const

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

NameValuePairs 允许传递任意参数。它是必需的,因为 KDF 参数变化很大。例如,早期的 PBKDF 在其推导中经常使用单个 "usage" 八位字节和 "iteration count";而 Scrypt 在其推导中使用 "memory hardness" 或 "cost"。使用 NameValuePairs 可以通过一致的接口传递那些不同的参数。

KeyDerivationFunction class 还提供了一些帮助程序,如 MinDerivedKeyLengthMaxDerivedKeyLengthGetValidDerivedLengthIsValidDerivedLengthGetValidDerivedLength是一个虚函数,所有派生的classes都必须实现它。

对于你的第二种情况,这个签名更专业。它被保留是因为它出现在 Crypto++ 的早期。它处理几个旧的 KDF,如 P1363_KDF2PKCS12_PBKDFPKCS5_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 这样的派生 class 提供仅接受其确切参数的重载 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

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

以下是 Crypto++ wiki 的更多阅读资料: