MD5 哈希的密码盐字符串的格式是什么?
What is the format of a Password Salt string for MD5 hash?
我正在使用 C++ 创建一个简单的数据库访问应用程序,我添加了用户 Table,其中包含:ID、USER、PASSWORD 和 SALT,我正在使用 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 64、HEX 中加密盐字符串还是将其保留为 纯文本 在 MD5 哈希之前将其与纯密码字符串连接时?
我应该在 Base 64、HEX 中加密盐字符串还是将其保留为 纯文本 保存到数据库时 ?
你有什么建议?
不,你的做法不对。 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 个字节就过头了。
我正在使用 C++ 创建一个简单的数据库访问应用程序,我添加了用户 Table,其中包含:ID、USER、PASSWORD 和 SALT,我正在使用 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 64、HEX 中加密盐字符串还是将其保留为 纯文本 在 MD5 哈希之前将其与纯密码字符串连接时?
我应该在 Base 64、HEX 中加密盐字符串还是将其保留为 纯文本 保存到数据库时 ?
你有什么建议?
不,你的做法不对。 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 个字节就过头了。