Use cryptographic RNG to generate the shard connection serial key

This commit is contained in:
dongresource 2022-07-24 00:29:19 +02:00
parent 741bfb675b
commit ca0d608a87
3 changed files with 56 additions and 1 deletions

View File

@ -1,4 +1,5 @@
#include "Rand.hpp"
#include "core/Core.hpp"
std::unique_ptr<std::mt19937> Rand::generator;
@ -33,6 +34,58 @@ float Rand::randFloat() {
return Rand::randFloat(0.0f, 1.0f);
}
#define RANDBYTES 8
/*
* Cryptographically secure RNG. Borrowed from bcrypt_gensalt().
*/
uint64_t Rand::cryptoRand() {
uint8_t buf[RANDBYTES];
#ifdef _WIN32
HCRYPTPROV p;
// Acquire a crypt context for generating random bytes.
if (CryptAcquireContext(&p, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == FALSE) {
goto fail;
}
if (CryptGenRandom(p, RANDBYTES, (BYTE*)buf) == FALSE) {
goto fail;
}
if (CryptReleaseContext(p, 0) == FALSE) {
goto fail;
}
#else
int fd;
// Get random bytes on Unix/Linux.
fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
perror("open");
goto fail;
}
if (read(fd, buf, RANDBYTES) < RANDBYTES) {
perror("read");
close(fd);
goto fail;
}
close(fd);
#endif
return *(uint64_t*)buf;
fail:
std::cout << "[FATAL] Failed to generate cryptographic random number" << std::endl;
terminate(0);
/* not reached */
return 0;
}
void Rand::init(uint64_t seed) {
Rand::generator = std::make_unique<std::mt19937>(std::mt19937(seed));
}

View File

@ -14,6 +14,8 @@ namespace Rand {
int32_t randWeighted(const std::vector<int32_t>& weights);
uint64_t cryptoRand();
float randFloat(float startInclusive, float endExclusive);
float randFloat(float endExclusive);
float randFloat();

View File

@ -477,7 +477,7 @@ void CNLoginServer::characterSelect(CNSocket* sock, CNPacketData* data) {
if (lm->plr.iID == 0)
return invalidCharacter(sock);
resp.iEnterSerialKey = Rand::rand(); // TODO: cryptographic RNG
resp.iEnterSerialKey = Rand::cryptoRand();
// transfer ownership of connection data to CNShared
CNShared::storeLoginMetadata(resp.iEnterSerialKey, lm);