MD5 哈希的密码盐字符串的格式是什么?

What is the format of a Password Salt string for MD5 hash?

我正在使用 C++ 创建一个简单的数据库访问应用程序,我添加了用户 Table,其中包含:IDUSERPASSWORDSALT,我正在使用 Crypto++ 作为加密后端。所以我创建了这个函数:

#include "crypto.h"

#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include <md5.h>
#include <hex.h>
#include <osrng.h>

using namespace std;
using namespace CryptoPP;

string MyCrypto::MD5(const string strMessage)
{
    byte arrbyDigest[Weak::MD5::DIGESTSIZE];
    Weak::MD5 hash;
    hash.CalculateDigest(arrbyDigest, /*(const byte*)*/strMessage.c_str(), strMessage.length());

    HexEncoder encoder;
    string strOutput;

    encoder.Attach(new StringSink(strOutput));
    encoder.Put(arrbyDigest, sizeof(arrbyDigest));
    encoder.MessageEnd();

    return strOutput;
}

string MyCrypto::GenerateSalt(const size_t length /*= 16*/)
{
    SecByteBlock arrbySalt(length);
    AutoSeededRandomPool asrp;
    asrp.GenerateBlock(arrbySalt, length);

    string strSalt(arrbySalt);
    strSalt.ToAscii();

    return strSalt;
}

到目前为止一切正常,直到我意识到生成的 salt 字符串可以包含 不可打印的字符 甚至 空终止符

所以我的问题是:

我的做法正确吗?

salt的长度16跟我做的一样实用吗?

我应该在 Base 64HEX 中加密盐字符串还是将其保留为 纯文本 在 MD5 哈希之前将其与纯密码字符串连接时?

我应该在 Base 64HEX 中加密盐字符串还是将其保留为 纯文本 保存到数据库时 ?

你有什么建议?

不,你的做法不对。 MD5 是 - 或者更确切地说 - 一种加密安全散列。它不直接适用于哈希密码。要散列密码,您需要一个包含随机盐和工作因子(成本或迭代计数,取决于使用的密码散列)的密码散列。这些示例包括 bcrypt、PBKDF2 和较新的 Argon2。 Here 是一篇讨论密码哈希使用的随机文章。

至于编码,我总是尽量遵守现有的标准。对于密码散列,适用的标准是 Modular Crypt Format. If you are designing a new scheme without strong interoperability requirements then you may also use the Password Hashing Format.

两者都使用类型的 base 64 编码作为盐和密码的输出格式。一个例子是 bcrypt 输出 a$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy,其中 2a 表示 bcrypt 和格式,10 是成本(工作因子),N9qo8uLOickgx2ZMRZoMye 是盐的基数 64 编码;其余的是密码哈希。请注意,salt 和密码之间没有美元符号分隔符。

我从 bcrypt Wikipedia page 中获取了上面的示例,这是获取更多信息的有趣起点,可能包括 crypt 的 MD5 哈希输出(如前所述,您不应使用)。

差点忘了,是的,16 个随机字节/128 位盐是 很多;如果您使用 8 个字节,没有人会眨眼,超过 32 个字节就过头了。