Search code examples
c++cryptographymd5salt-cryptographycrypto++

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


I am creating a simple DB access application using C++, and I have added Users Table containing: ID, USER, PASSWORD and SALT, and I am using Crypto++ as crypto backend. So I created this function:

#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;
}

So good so far, all is working fine until I realized that the generated salt string can contain non-printable characters even null termination character

So my questions are:

Am I doing it the right way ?

Is the length of the salt 16 as I did the practical way ?

Should I encrypt the salt string in Base 64, HEX or leave it as plain text when concatenating it with the plain password string before the MD5 hash ?

Should I encrypt the salt string in Base 64, HEX or leave it as plain text when saving it to the database ?

What are your suggestions ?


Solution

  • No, you're not doing it the right way. MD5 is - or rather was - a cryptographically secure hash. It is not directly applicable to hash passwords. To hash passwords you need a password hash that contains a random salt and work factor (cost or iteration count, depending on the password hash used). Examples of these are bcrypt, PBKDF2 and the newer Argon2. Here is a random article that discusses the use of password hashes.

    As for the encoding, I would always try to keep to existing standards, where they exist. For password hashing the applicable standard is the Modular Crypt Format. If you are designing a new scheme without strong interoperability requirements then you may also use the Password Hashing Format.

    Both use a type of base 64 encoding as output format for the salt and password. An example is the bcrypt output $2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy where 2a indicates bcrypt and the format, 10 is the cost (work factor) and N9qo8uLOickgx2ZMRZoMye is the radix 64 encoding of the salt; the rest is the password hash. Note that there is no dollar sign separator between the salt and the password.

    I've taken the above example from the bcrypt Wikipedia page which is an interesting starting point for getting more information, including possibly the MD5 hash output for crypt (which as indicated, you should not use).

    Almost forgot, yes, 16 random bytes / 128 bits of salt is plenty; nobody would blink an eye if you used 8 bytes, more than 32 bytes is overdoing it.