如何从 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
开关。
我想用 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
开关。