random.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include "crucible/core/random.hpp" #include "crucible/core/platform.hpp" #if CRUCIBLE_PLATFORM_IS_POSIX_LIKE #include <cerrno> #include <fcntl.h> #include <unistd.h> #endif // CRUCIBLE_PLATFORM_IS_POSIX_LIKE namespace crucible { auto read_random_bytes(std::size_t const count) -> random_result<heap_buffer<std::byte>> { auto buffer { make_heap_buffer<std::byte>(count) }; CRUCIBLE_TRY(read_random_bytes_into(buffer.view())); return make_success(std::move(buffer)); } auto read_random_bytes_into(mutable_view<std::byte> sink) -> random_result<none> { int const fd = ::open("/dev/urandom", O_RDONLY); if (fd < 0) { return make_failure<random_error>(randomness_source_unavailable {}); } int read_status { 0 }; std::size_t bytes_read { 0 }; // ::read() is allowed to not read the whole buffer, so we do it in a loop until we're sure we're done do { errno = 0; read_status = ::read(fd, sink.data() + bytes_read, sink.size() - bytes_read); if (read_status > 0) { bytes_read += read_status; } } while (bytes_read < sink.size() && read_status > 0); if (read_status < 0 || bytes_read < sink.size()) { return make_failure<random_error>(randomness_source_read_failed {}); } return make_success<none>(); } }