128 lines
2.8 KiB
C++
128 lines
2.8 KiB
C++
#include "SafeRNG.h"
|
||
|
||
#include <random>
|
||
#include <chrono>
|
||
#include <cstring>
|
||
#include <openssl/err.h>
|
||
#include <openssl/rand.h>
|
||
|
||
bool RandomNumberGenerator::FillWithOpenSSLRandom(unsigned char* dst, size_t len) noexcept
|
||
{
|
||
try
|
||
{
|
||
while (len > 0)
|
||
{
|
||
int chunk = (len > static_cast<std::size_t>(INT_MAX)) ? INT_MAX : static_cast<int>(len);
|
||
// RAND_bytes 返回 1 成功
|
||
int rc = RAND_bytes(dst, chunk);
|
||
if (rc != 1)
|
||
return false;
|
||
dst += chunk;
|
||
len -= static_cast<std::size_t>(chunk);
|
||
}
|
||
return true;
|
||
}
|
||
catch (...)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
bool RandomNumberGenerator::FillWithSTDMT19937_64(unsigned char* dst, size_t len) noexcept
|
||
{
|
||
try
|
||
{
|
||
// 先尝试用 random_device 为 mt19937_64 提供种子
|
||
std::mt19937_64 gen;
|
||
try
|
||
{
|
||
std::random_device rd;
|
||
// 将几个 rd() 的值混合到一个 seed 中
|
||
uint64_t seed = 0;
|
||
for (int i = 0; i < 4; ++i)
|
||
seed ^= (static_cast<uint64_t>(rd()) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2));
|
||
gen.seed(seed);
|
||
}
|
||
catch (...)
|
||
{
|
||
// random_device 可能抛或不可靠;退回到时间戳种子(不可预测性较低)
|
||
uint64_t seed = static_cast<uint64_t>(std::chrono::high_resolution_clock::now().time_since_epoch().count());
|
||
gen.seed(seed);
|
||
}
|
||
|
||
// 逐 8 字节生成并拷贝;最后处理剩余字节
|
||
while (len >= 8)
|
||
{
|
||
uint64_t v = gen();
|
||
std::memcpy(dst, &v, 8);
|
||
dst += 8;
|
||
len -= 8;
|
||
}
|
||
if (len > 0)
|
||
{
|
||
uint64_t v = gen();
|
||
std::memcpy(dst, &v, len);
|
||
}
|
||
return true;
|
||
}
|
||
catch (...)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
std::string RandomNumberGenerator::Bytes2HexString(const unsigned char* data, size_t len) noexcept
|
||
{
|
||
try
|
||
{
|
||
const char* hex_chars = "0123456789ABCDEF";
|
||
std::string out;
|
||
out.resize(len * 2);
|
||
for (std::size_t i = 0; i < len; ++i)
|
||
{
|
||
unsigned char v = data[i];
|
||
out[2 * i] = hex_chars[(v >> 4) & 0xF];
|
||
out[2 * i + 1] = hex_chars[v & 0xF];
|
||
}
|
||
return out;
|
||
}
|
||
catch (...)
|
||
{
|
||
return std::string();
|
||
}
|
||
}
|
||
|
||
std::string RandomNumberGenerator::SecureRandomHex(size_t bytes)
|
||
{
|
||
if (bytes == 0)
|
||
return std::string();
|
||
|
||
// 分配原始缓冲区(可能抛 bad_alloc -> catch below)
|
||
unsigned char* buf = nullptr;
|
||
try
|
||
{
|
||
buf = static_cast<unsigned char*>(::operator new(bytes));
|
||
}
|
||
catch (...)
|
||
{
|
||
return std::string(); // 无法分配内存,返回空字符串表示失败
|
||
}
|
||
|
||
bool ok = FillWithOpenSSLRandom(buf, bytes);
|
||
if (!ok)
|
||
{
|
||
//printf_s("OpenSSL Failure!\n");
|
||
// OpenSSL 失败:使用伪随机兜底(保证会产出数据)
|
||
bool ok2 = FillWithSTDMT19937_64(buf, bytes);
|
||
if (!ok2)
|
||
{
|
||
// 极端失败:释放并返回空字符串
|
||
::operator delete(buf);
|
||
return std::string();
|
||
}
|
||
}
|
||
// 转 hex 并返回(Bytes2HexString 会在异常时返回空字符串)
|
||
std::string hex = Bytes2HexString(buf, bytes);
|
||
::operator delete(buf);
|
||
return hex;
|
||
} |