我正在使用C ++创建一个简单的数据库访问应用程序,并且添加了包含以下内容的用户表: ID , USER , PASSWORD 和< strong> 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;
}
到目前为止,一切正常,直到我意识到生成的盐串可以包含不可打印的字符,甚至空终止符
所以我的问题是:
我做对了吗?
像我实际操作的那样,盐的长度是 16 吗?
在与普通密码字符串连接之前,应该在 Base 64 , HEX 中对盐字符串进行加密还是将其保留为纯文本 MD5哈希?
在将盐字符串保存到数据库时,应该在 Base 64 , HEX 中将其加密还是保留为纯文本? >
您有什么建议?
答案 0 :(得分:2)
不,您的做法不正确。 MD5是-或更确切地说是-是加密安全的哈希。它不适用于哈希密码。要对密码进行哈希处理,您需要一个密码哈希,其中包含随机的盐和工作因数(成本或迭代次数,取决于所使用的密码哈希)。这些示例包括bcrypt,PBKDF2和较新的Argon2。 Here是一篇随机文章,讨论了密码散列的使用。
对于编码,我将始终尝试遵守现有标准(存在标准)。对于密码哈希,适用的标准是Modular Crypt Format。如果要设计对互操作性要求不高的新方案,则也可以使用Password Hashing Format。
都使用 base 类型的编码作为盐和密码的输出格式。一个示例是bcrypt输出$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
,其中2a
表示bcrypt和格式,10
是成本(工作因子),N9qo8uLOickgx2ZMRZoMye
是盐的基数64编码;其余的是密码哈希。请注意,盐和密码之间没有美元符号分隔符。
我从bcrypt Wikipedia page中获取了上面的示例,这是获取更多信息的有趣起点,其中可能包括crypt的MD5哈希输出(如所示,您不应使用)。
几乎忘记了,是的,大量是16个随机字节/ 128位盐。如果您使用8个字节,没有人会眨眼,但超过32个字节的字节数就超过了。