The Pedigree Project 0.1
SecureRandom.cc
1/* Copyright (c) 2026, Pedigree Developers. SPDX-License-Identifier: ISC */
2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/Spinlock.h"
4#include "pedigree/kernel/utilities/SecureRandom.h"
5#include "pedigree/kernel/utilities/lib.h"
6
7namespace {
8Spinlock randomLock{false, true};
9uint8_t randomKey[32] = {};
10bool randomReady = false;
11
12bool initialiseLocked() {
13 if (randomReady)
14 return true;
15 uint8_t seed[32] = {};
16 if (hardware_random_bytes(seed, sizeof(seed)) == sizeof(seed)) {
17 for (size_t i = 0; i < sizeof(seed); ++i)
18 randomKey[i] = seed[i];
19 randomReady = true;
20 }
21 pedigree_random::erase(seed, sizeof(seed));
22 return randomReady;
23}
24} // namespace
25
26extern "C" int secure_random_seed(const void* buffer, size_t length) {
27 if (!buffer || length != sizeof(randomKey))
28 return 0;
29 LockGuard<Spinlock> guard(randomLock);
30 const auto* seed = static_cast<const uint8_t*>(buffer);
31 uint8_t next[32];
32 if (initialiseLocked()) {
33 // Preserve existing secret entropy even if a later trusted source degrades.
34 pedigree_random::hmac_sha256(randomKey, seed, length, next);
35 } else {
36 for (size_t i = 0; i < sizeof(next); ++i)
37 next[i] = seed[i];
38 }
39 for (size_t i = 0; i < sizeof(next); ++i)
40 randomKey[i] = next[i];
41 randomReady = true;
42 pedigree_random::erase(next, sizeof(next));
43 return 1;
44}
45
46extern "C" size_t secure_random_bytes(void* buffer, size_t length) {
47 if (!buffer || !length)
48 return 0;
49 auto* output = static_cast<uint8_t*>(buffer);
50 size_t produced = 0;
51 while (produced < length) {
52 // One block per critical section bounds IRQ latency for large device reads.
53 LockGuard<Spinlock> guard(randomLock);
54 if (!initialiseLocked())
55 return 0;
56 const uint8_t nonce[12] = {};
57 uint8_t block[64];
58 pedigree_random::chacha20_block(randomKey, nonce, 0, block);
59 for (size_t i = 0; i < sizeof(randomKey); ++i)
60 randomKey[i] = block[i];
61 const size_t count = length - produced < 32 ? length - produced : 32;
62 for (size_t i = 0; i < count; ++i)
63 output[produced + i] = block[32 + i];
64 produced += count;
65 // No returned bytes are retained, including the unused tail of a short read.
66 pedigree_random::erase(block, sizeof(block));
67 }
68 return produced;
69}