Files
UNSWebServerCore_LinuxSO/SafeRNG.cpp
T
2026-06-30 17:49:51 +08:00

128 lines
2.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;
}