diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp
index cc8f0f317..95d601959 100644
--- a/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp
@@ -33,24 +33,10 @@ namespace ams::kern {
class KResourceLimit;
- struct CtrDrbgContext {
- u8 v[16];
- u8 key[16];
- u8 seed[32];
- u8 temp[32];
- u32 reseed_counter;
- u8 output[128];
- u32 remaining;
- };
-
class KSystemControlBase {
public:
/* This can be overridden as needed. */
static constexpr size_t SecureAppletMemorySize = 0;
- protected:
- static constinit inline bool s_uninitialized_random_generator{true};
- static constinit inline CtrDrbgContext s_random_generator{};
- static constinit inline KSpinLock s_random_lock;
private:
/* Randomness helpers. */
static void InitializeRandomGenerator(const void *seed, size_t size);
diff --git a/libraries/libmesosphere/source/kern_k_system_control_base.cpp b/libraries/libmesosphere/source/kern_k_system_control_base.cpp
index ffe172846..c92bbe60e 100644
--- a/libraries/libmesosphere/source/kern_k_system_control_base.cpp
+++ b/libraries/libmesosphere/source/kern_k_system_control_base.cpp
@@ -14,7 +14,8 @@
* along with this program. If not, see .
*/
#include
-#include
+#include
+#include
#if defined(ATMOSPHERE_ARCH_ARM64)
#include
#endif
@@ -46,33 +47,19 @@ namespace ams::kern {
}
};
- ALWAYS_INLINE void CtrDrbgIncrementCounter(u8 *v) {
- for (size_t i = 16; i > 0; --i) {
- if ((++v[i - 1]) != 0) {
- break;
- }
- }
- }
+ using RandomGenerator = ::ams::crypto::impl::CtrDrbg<::ams::crypto::AesEncryptor128, 16, false>;
- void CtrDrbgUpdate(CtrDrbgContext &ctx, const u8 *data) {
- /* Initialize the block cipher with the current key. */
- ams::crypto::impl::AesImpl<16> aes;
- aes.Initialize(ctx.key, sizeof(ctx.key), true);
+ constexpr size_t RandomGeneratorOutputSize = 8 * RandomGenerator::OutSize;
+ constexpr u32 RandomGeneratorOutputCount = RandomGeneratorOutputSize / sizeof(u32);
- /* Generate two blocks of new key/counter material. */
- CtrDrbgIncrementCounter(ctx.v);
- aes.EncryptBlock(ctx.temp + 0, 16, ctx.v, 16);
- CtrDrbgIncrementCounter(ctx.v);
- aes.EncryptBlock(ctx.temp + 16, 16, ctx.v, 16);
+ constinit util::TypedStorage s_random_generator = {};
+ constinit bool s_uninitialized_random_generator = true;
+ constinit u8 s_random_output[RandomGeneratorOutputSize] = {};
+ constinit u32 s_random_remaining = 0;
+ constinit KSpinLock s_random_lock;
- /* Mix in the provided data. */
- for (size_t i = 0; i < sizeof(ctx.temp); ++i) {
- ctx.temp[i] ^= data[i];
- }
-
- /* Update the key and counter. */
- std::memcpy(ctx.key, ctx.temp, sizeof(ctx.key));
- std::memcpy(ctx.v, ctx.temp + sizeof(ctx.key), sizeof(ctx.v));
+ void GenerateRandomSeed(void *dst, size_t size) {
+ KSystemControl::GenerateRandomBytesForUninitialized(dst, size);
}
}
@@ -255,72 +242,52 @@ namespace ams::kern {
/* Randomness helpers. Assume the caller holds the random lock. */
void KSystemControlBase::InitializeRandomGenerator(const void *seed, size_t size) {
- MESOSPHERE_ASSERT(size == sizeof(s_random_generator.seed));
+ MESOSPHERE_ASSERT(size == RandomGenerator::SeedSize);
KScopedFpuEnable fp_enabled;
- auto &ctx = s_random_generator;
- /* Zero the counter and key, then derive the initial state from the seed. */
- std::memset(ctx.v, 0, sizeof(ctx.v));
- std::memset(ctx.key, 0, sizeof(ctx.key));
- std::memcpy(ctx.seed, seed, sizeof(ctx.seed));
+ /* Construct the generator, and derive the initial state from the seed. */
+ util::ConstructAt(s_random_generator);
+ util::GetReference(s_random_generator).Initialize(seed, size, nullptr, 0, nullptr, 0);
- CtrDrbgUpdate(ctx, ctx.seed);
-
- ctx.reseed_counter = 1;
- ctx.remaining = 0;
+ s_random_remaining = 0;
}
void KSystemControlBase::ReseedRandomGeneratorInternal() {
KScopedFpuEnable fp_enabled;
- auto &ctx = s_random_generator;
/* Pull fresh entropy, then derive a new state from it. */
- KSystemControl::GenerateRandomBytesForUninitialized(ctx.seed, sizeof(ctx.seed));
- CtrDrbgUpdate(ctx, ctx.seed);
+ u8 seed[RandomGenerator::SeedSize];
+ GenerateRandomSeed(seed, sizeof(seed));
+ util::GetReference(s_random_generator).Reseed(seed, sizeof(seed), nullptr, 0);
- ctx.remaining = 0;
- ctx.reseed_counter = 1;
+ s_random_remaining = 0;
}
u32 KSystemControlBase::GenerateRandomU32() {
- auto &ctx = s_random_generator;
-
- if (ctx.remaining == 0) {
+ if (s_random_remaining == 0) {
KScopedFpuEnable fp_enabled;
- /* Reseed if we've exhausted this generation's entropy, otherwise use zero additional input. */
- if (ctx.reseed_counter <= 0x7FFFFFF0) {
- std::memset(ctx.seed, 0, sizeof(ctx.seed));
- } else {
- KSystemControl::GenerateRandomBytesForUninitialized(ctx.seed, sizeof(ctx.seed));
- CtrDrbgUpdate(ctx, ctx.seed);
- ctx.remaining = 0;
- std::memset(ctx.seed, 0, sizeof(ctx.seed));
- ctx.reseed_counter = 1;
+ auto &drbg = util::GetReference(s_random_generator);
+
+ /* Derive the next state, or reseed if we've exhausted this generation's entropy. */
+ if (AMS_UNLIKELY(!drbg.Generate(s_random_output, sizeof(s_random_output), nullptr, 0))) {
+ u8 seed[RandomGenerator::SeedSize];
+ GenerateRandomSeed(seed, sizeof(seed));
+ drbg.Reseed(seed, sizeof(seed), nullptr, 0);
+
+ MESOSPHERE_ABORT_UNLESS(drbg.Generate(s_random_output, sizeof(s_random_output), nullptr, 0));
}
- /* Generate eight blocks of output. */
- ams::crypto::impl::AesImpl<16> aes;
- aes.Initialize(ctx.key, sizeof(ctx.key), true);
- for (size_t i = 0; i < 8; ++i) {
- CtrDrbgIncrementCounter(ctx.v);
- aes.EncryptBlock(ctx.output + 16 * i, 16, ctx.v, 16);
- }
-
- /* Derive the next state. */
- CtrDrbgUpdate(ctx, ctx.seed);
-
- ++ctx.reseed_counter;
- ctx.remaining = 32;
+ s_random_remaining = RandomGeneratorOutputCount;
}
/* Consume a word from the output buffer, zeroizing it in place for backtracking resistance. */
- const size_t index = 32 - ctx.remaining;
+ const size_t index = RandomGeneratorOutputCount - s_random_remaining;
u32 value;
- std::memcpy(std::addressof(value), ctx.output + 4 * index, sizeof(value));
- std::memset(ctx.output + 4 * index, 0, sizeof(value));
- --ctx.remaining;
+ std::memcpy(std::addressof(value), s_random_output + sizeof(value) * index, sizeof(value));
+ std::memset(s_random_output + sizeof(value) * index, 0, sizeof(value));
+ --s_random_remaining;
return value;
}