little_planet
little_planet

Reputation: 1035

How to get random salt from OpenSSL as std::string

I would like to generate a random string with OpenSSL and use this as a salt in a hashing function afterwards (will be Argon2). Currently I'm generating the random data this way:

if(length < CryptConfig::sMinSaltLen){        
    return 1;
}
if (!sInitialized){
    RAND_poll();
    sInitialized = true;
}

unsigned char * buf = new unsigned char[length];
if (!sInitialized || !RAND_bytes(buf, length)) {      
    return 1;
}

salt = std::string (reinterpret_cast<char*>(buf));
delete buf;

return 0;

But a std::cout of salt doesn't seem to be a proper string (contains control symbols and other stuff). This is most likely only my fault.

Am I using the wrong functions of OpenSSL to generate the random data?

Or is my conversion from buf to string faulty?

Upvotes: 0

Views: 3100

Answers (1)

Mihai Todor
Mihai Todor

Reputation: 8239

Random data is random data. That's what you're asking for and that's exactly what you are getting. Your salt variable is a proper string that happens to contain unprintable characters. If you wish to have printable characters, one way of achieving that is using base64 encoding, but that will blow up its length. Another option is to somehow discard non-printable characters, but I don't see any mechanism to force RAND_bytes to do this. I guess you could simply fetch random bytes in a loop until you get length printable characters.

If encoding base64 is acceptable for you, here is an example of how to use the OpenSSL base64 encoder, extracted from Joe Linoff's Cipher library:

string Cipher::encode_base64(uchar* ciphertext,
                 uint   ciphertext_len) const
{
  DBG_FCT("encode_base64");
  BIO* b64 = BIO_new(BIO_f_base64());
  BIO* bm  = BIO_new(BIO_s_mem());
  b64 = BIO_push(b64,bm);
  if (BIO_write(b64,ciphertext,ciphertext_len)<2) {
    throw runtime_error("BIO_write() failed");
  }
  if (BIO_flush(b64)<1) {
    throw runtime_error("BIO_flush() failed");
  }
  BUF_MEM *bptr=0;
  BIO_get_mem_ptr(b64,&bptr);
  uint len=bptr->length;
  char* mimetext = new char[len+1];
  memcpy(mimetext, bptr->data, bptr->length-1);
  mimetext[bptr->length-1]=0;
  BIO_free_all(b64);

  string ret = mimetext;
  delete [] mimetext;
  return ret;
}

To this code, I suggest adding BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL), because otherwise you'll get a new line character inserted after every 64 characters. See OpenSSL's -A switch for details.

Upvotes: 2

Related Questions