kern: use CTR_DRBG from vapours

This commit is contained in:
Alula
2026-09-18 07:25:48 +02:00
parent 866c831f7a
commit 1d6e593aba
2 changed files with 36 additions and 83 deletions

View File

@@ -33,24 +33,10 @@ namespace ams::kern {
class KResourceLimit; 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 { class KSystemControlBase {
public: public:
/* This can be overridden as needed. */ /* This can be overridden as needed. */
static constexpr size_t SecureAppletMemorySize = 0; 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: private:
/* Randomness helpers. */ /* Randomness helpers. */
static void InitializeRandomGenerator(const void *seed, size_t size); static void InitializeRandomGenerator(const void *seed, size_t size);

View File

@@ -14,7 +14,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <mesosphere.hpp> #include <mesosphere.hpp>
#include <vapours/crypto/impl/crypto_aes_impl.hpp> #include <vapours/crypto/crypto_aes_encryptor.hpp>
#include <vapours/crypto/impl/crypto_ctr_drbg.hpp>
#if defined(ATMOSPHERE_ARCH_ARM64) #if defined(ATMOSPHERE_ARCH_ARM64)
#include <mesosphere/arch/arm64/kern_secure_monitor_base.hpp> #include <mesosphere/arch/arm64/kern_secure_monitor_base.hpp>
#endif #endif
@@ -46,33 +47,19 @@ namespace ams::kern {
} }
}; };
ALWAYS_INLINE void CtrDrbgIncrementCounter(u8 *v) { using RandomGenerator = ::ams::crypto::impl::CtrDrbg<::ams::crypto::AesEncryptor128, 16, false>;
for (size_t i = 16; i > 0; --i) {
if ((++v[i - 1]) != 0) {
break;
}
}
}
void CtrDrbgUpdate(CtrDrbgContext &ctx, const u8 *data) { constexpr size_t RandomGeneratorOutputSize = 8 * RandomGenerator::OutSize;
/* Initialize the block cipher with the current key. */ constexpr u32 RandomGeneratorOutputCount = RandomGeneratorOutputSize / sizeof(u32);
ams::crypto::impl::AesImpl<16> aes;
aes.Initialize(ctx.key, sizeof(ctx.key), true);
/* Generate two blocks of new key/counter material. */ constinit util::TypedStorage<RandomGenerator> s_random_generator = {};
CtrDrbgIncrementCounter(ctx.v); constinit bool s_uninitialized_random_generator = true;
aes.EncryptBlock(ctx.temp + 0, 16, ctx.v, 16); constinit u8 s_random_output[RandomGeneratorOutputSize] = {};
CtrDrbgIncrementCounter(ctx.v); constinit u32 s_random_remaining = 0;
aes.EncryptBlock(ctx.temp + 16, 16, ctx.v, 16); constinit KSpinLock s_random_lock;
/* Mix in the provided data. */ void GenerateRandomSeed(void *dst, size_t size) {
for (size_t i = 0; i < sizeof(ctx.temp); ++i) { KSystemControl::GenerateRandomBytesForUninitialized(dst, size);
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));
} }
} }
@@ -255,72 +242,52 @@ namespace ams::kern {
/* Randomness helpers. Assume the caller holds the random lock. */ /* Randomness helpers. Assume the caller holds the random lock. */
void KSystemControlBase::InitializeRandomGenerator(const void *seed, size_t size) { 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; KScopedFpuEnable fp_enabled;
auto &ctx = s_random_generator;
/* Zero the counter and key, then derive the initial state from the seed. */ /* Construct the generator, and derive the initial state from the seed. */
std::memset(ctx.v, 0, sizeof(ctx.v)); util::ConstructAt(s_random_generator);
std::memset(ctx.key, 0, sizeof(ctx.key)); util::GetReference(s_random_generator).Initialize(seed, size, nullptr, 0, nullptr, 0);
std::memcpy(ctx.seed, seed, sizeof(ctx.seed));
CtrDrbgUpdate(ctx, ctx.seed); s_random_remaining = 0;
ctx.reseed_counter = 1;
ctx.remaining = 0;
} }
void KSystemControlBase::ReseedRandomGeneratorInternal() { void KSystemControlBase::ReseedRandomGeneratorInternal() {
KScopedFpuEnable fp_enabled; KScopedFpuEnable fp_enabled;
auto &ctx = s_random_generator;
/* Pull fresh entropy, then derive a new state from it. */ /* Pull fresh entropy, then derive a new state from it. */
KSystemControl::GenerateRandomBytesForUninitialized(ctx.seed, sizeof(ctx.seed)); u8 seed[RandomGenerator::SeedSize];
CtrDrbgUpdate(ctx, ctx.seed); GenerateRandomSeed(seed, sizeof(seed));
util::GetReference(s_random_generator).Reseed(seed, sizeof(seed), nullptr, 0);
ctx.remaining = 0; s_random_remaining = 0;
ctx.reseed_counter = 1;
} }
u32 KSystemControlBase::GenerateRandomU32() { u32 KSystemControlBase::GenerateRandomU32() {
auto &ctx = s_random_generator; if (s_random_remaining == 0) {
if (ctx.remaining == 0) {
KScopedFpuEnable fp_enabled; KScopedFpuEnable fp_enabled;
/* Reseed if we've exhausted this generation's entropy, otherwise use zero additional input. */ auto &drbg = util::GetReference(s_random_generator);
if (ctx.reseed_counter <= 0x7FFFFFF0) {
std::memset(ctx.seed, 0, sizeof(ctx.seed)); /* Derive the next state, or reseed if we've exhausted this generation's entropy. */
} else { if (AMS_UNLIKELY(!drbg.Generate(s_random_output, sizeof(s_random_output), nullptr, 0))) {
KSystemControl::GenerateRandomBytesForUninitialized(ctx.seed, sizeof(ctx.seed)); u8 seed[RandomGenerator::SeedSize];
CtrDrbgUpdate(ctx, ctx.seed); GenerateRandomSeed(seed, sizeof(seed));
ctx.remaining = 0; drbg.Reseed(seed, sizeof(seed), nullptr, 0);
std::memset(ctx.seed, 0, sizeof(ctx.seed));
ctx.reseed_counter = 1; MESOSPHERE_ABORT_UNLESS(drbg.Generate(s_random_output, sizeof(s_random_output), nullptr, 0));
} }
/* Generate eight blocks of output. */ s_random_remaining = RandomGeneratorOutputCount;
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;
} }
/* Consume a word from the output buffer, zeroizing it in place for backtracking resistance. */ /* 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; u32 value;
std::memcpy(std::addressof(value), ctx.output + 4 * index, sizeof(value)); std::memcpy(std::addressof(value), s_random_output + sizeof(value) * index, sizeof(value));
std::memset(ctx.output + 4 * index, 0, sizeof(value)); std::memset(s_random_output + sizeof(value) * index, 0, sizeof(value));
--ctx.remaining; --s_random_remaining;
return value; return value;
} }