From 0f32155fa496796b367e739084b2db2fa39c73b0 Mon Sep 17 00:00:00 2001 From: Peter Elliott Date: Mon, 22 Jun 2020 20:23:35 -0600 Subject: [PATCH] Kernel: Replace existing random implementation with Fortuna --- Kernel/CMakeLists.txt | 6 ++++++ Kernel/Random.cpp | 47 +++++++++++++++++++++---------------------- Kernel/Random.h | 26 ++++++++++++++++++------ 3 files changed, 49 insertions(+), 30 deletions(-) diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index c6e8fc24dc..4c25ce009f 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -148,12 +148,18 @@ set(KEYBOARD_SOURCES ../Libraries/LibKeyboard/CharacterMap.cpp ) +set(CRYPTO_SOURCES + ../Libraries/LibCrypto/Cipher/AES.cpp + ../Libraries/LibCrypto/Hash/SHA2.cpp +) + set(SOURCES ${KERNEL_SOURCES} ${AK_SOURCES} ${ELF_SOURCES} ${VT_SOURCES} ${KEYBOARD_SOURCES} + ${CRYPTO_SOURCES} ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DKERNEL") diff --git a/Kernel/Random.cpp b/Kernel/Random.cpp index 288af64b8f..0b95698a90 100644 --- a/Kernel/Random.cpp +++ b/Kernel/Random.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2020, Peter Elliott * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,37 +31,35 @@ namespace Kernel { -static u32 random32() +static KernelRng* s_the; + +KernelRng& KernelRng::the() +{ + if (!s_the) { + s_the = new KernelRng; + } + return *s_the; +} + +KernelRng::KernelRng() { if (g_cpu_supports_rdrand) { - u32 value = 0; - asm volatile( - "1:\n" - "rdrand %0\n" - "jnc 1b\n" - : "=r"(value)); - return value; + for (size_t i = 0; i < KernelRng::pool_count * KernelRng::reseed_threshold; ++i) { + u32 value = 0; + asm volatile( + "1:\n" + "rdseed %0\n" + "jnc 1b\n" + : "=r"(value)); + + this->add_random_event(value, i % 32); + } } - // FIXME: This sucks lol - static u32 next = 1; - next = next * 1103515245 + 12345; - return next; } void get_good_random_bytes(u8* buffer, size_t buffer_size) { - union { - u8 bytes[4]; - u32 value; - } u; - size_t offset = 4; - for (size_t i = 0; i < buffer_size; ++i) { - if (offset >= 4) { - u.value = random32(); - offset = 0; - } - buffer[i] = u.bytes[offset++]; - } + KernelRng::the().get_random_bytes(buffer, buffer_size); } void get_fast_random_bytes(u8* buffer, size_t buffer_size) diff --git a/Kernel/Random.h b/Kernel/Random.h index 513fc7cfa7..5876b76370 100644 --- a/Kernel/Random.h +++ b/Kernel/Random.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018-2020, Andreas Kling - * Copyright (c) 2020, Peter Elliott * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,11 +32,14 @@ #include #include #include +#include +#include namespace Kernel { template class FortunaPRNG { +public: constexpr static size_t pool_count = 32; constexpr static size_t reseed_threshold = 16; @@ -45,7 +48,6 @@ class FortunaPRNG { using HashType = HashT; using DigestType = HashT::DigestType; -public: void get_random_bytes(u8* buffer, size_t n) { if (m_p0_len >= reseed_threshold) { @@ -57,7 +59,7 @@ public: // FIXME: More than 2^20 bytes cannot be generated without refreshing the key. ASSERT(n < (1 << 20)); - CipherType cipher(m_key, m_key.size()); + CipherType cipher(m_key, KeySize); size_t block_size = CipherType::BlockSizeInBits / 8; @@ -67,9 +69,10 @@ public: // Extract a new key from the prng stream. - for (size_t i = 0; i < KeySize; i += block_size) { + for (size_t i = 0; i < KeySize/8; i += block_size) { this->generate_block(cipher, &(m_key[i]), min(block_size, KeySize - i)); } + } template @@ -79,13 +82,14 @@ public: if (pool == 0) { m_p0_len++; } - m_pools[pool].update(reinterpret_cast(&event_data), sizeof(T)); + m_pools[pool].update(reinterpret_cast(&event_data), sizeof(T)); } private: void generate_block(CipherType cipher, u8* buffer, size_t size) { - BlockType input((u8*)m_counter, sizeof(m_counter)); + + BlockType input((u8*)&m_counter, sizeof(m_counter)); BlockType output; cipher.encrypt_block(input, output); m_counter++; @@ -119,6 +123,16 @@ private: HashType m_pools[pool_count]; }; +class KernelRng : public FortunaPRNG { + AK_MAKE_ETERNAL; +public: + static KernelRng& the(); + +private: + KernelRng(); + +}; + // NOTE: These API's are primarily about expressing intent/needs in the calling code. // We don't make any guarantees about actual fastness or goodness yet.