-1

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 ?

  • 3
    A hash is not "encryption", and MD5 is not secure. Have you considered https://en.wikipedia.org/wiki/Bcrypt? (Though actually there's no indication in your code or choice of library that you're really using MD5). – Lightness Races in Orbit Feb 16 '19 at 16:44
  • https://stackoverflow.com/q/3782519/560648 – Lightness Races in Orbit Feb 16 '19 at 16:47
  • `AutoSeededRandomPool` produces a uniform stream of bytes, meaning each byte is in the range `[0-255]`. You can store it directly in the database using a `BLOB`, or you can encode it using a [`HexEncoder`](https://cryptopp.com/wiki/HexEncoder) or [`Base64Encoder`](https://www.cryptopp.com/wiki/Base64Encoder). Encoding the salt does not matter because it still has the same amount of entropy. And it does not matter what you feed to the hash function as long as you do it consistently. You can feed binary data or encoded data. Just do the same all the time. – jww Feb 16 '19 at 17:09
  • @ЯрославМашко That would limit you to _one_ salt for all your users. Not good. Furthermore, security that relies on the attacker not knowing your encryption scheme is not security at all. The answer you appear to cite does go on to say all of this. – Lightness Races in Orbit Feb 17 '19 at 16:56

1 Answers1

1

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.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263