如何从 OpenSSL 中获取随机盐 std::string

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

我想用 OpenSSL 生成一个随机字符串,然后将其用作散列函数中的盐(将是 Argon2)。目前我正在以这种方式生成随机数据:

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;

但是 std::cout 的盐似乎不是正确的字符串(包含控制符号和其他内容)。这很可能只是我的错。

我是否使用了错误的 OpenSSL 函数来生成随机数据?

或者我从 buf 到字符串的转换有误吗?

随机数据就是随机数据。这就是您所要求的,而这正是您所得到的。您的 salt 变量是一个正确的字符串,恰好包含不可打印的字符。如果你希望有可打印的字符,实现它的一种方法是使用 base64 编码,但这会增加它的长度。另一种选择是以某种方式丢弃不可打印的字符,但我没有看到任何强制 RAND_bytes 执行此操作的机制。我猜你可以简单地在一个循环中获取随机字节,直到你得到 length 个可打印字符。

如果您可以接受 base64 编码,这里有一个如何使用 OpenSSL base64 编码器的示例,摘自 Joe Linoff 的 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;
}

对于此代码,我建议添加 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL),否则您将在每 64 个字符后插入一个换行符。有关详细信息,请参阅 OpenSSL 的 -A 开关。