GCC Code Coverage Report


Directory: ./
File: libs/capy/src/bcrypt/random.cpp
Date: 2025-12-30 20:31:36
Exec Total Coverage
Lines: 8 13 61.5%
Functions: 1 1 100.0%
Branches: 3 6 50.0%

Line Branch Exec Source
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/capy
8 //
9
10 #include "random.hpp"
11 #include <boost/capy/detail/except.hpp>
12 #include <boost/system/error_code.hpp>
13
14 #if defined(_WIN32)
15 # ifndef WIN32_LEAN_AND_MEAN
16 # define WIN32_LEAN_AND_MEAN
17 # endif
18 # include <windows.h>
19 # include <bcrypt.h>
20 # ifdef _MSC_VER
21 # pragma comment(lib, "bcrypt.lib")
22 # endif
23 #elif defined(__linux__)
24 # include <sys/random.h>
25 #elif defined(__APPLE__)
26 # include <Security/SecRandom.h>
27 #else
28 # include <fcntl.h>
29 # include <unistd.h>
30 #endif
31
32 namespace boost {
33 namespace capy {
34 namespace bcrypt {
35 namespace detail {
36
37 #if defined(_WIN32)
38
39 namespace {
40
41 class rng_provider
42 {
43 BCRYPT_ALG_HANDLE h_ = nullptr;
44
45 public:
46 rng_provider()
47 {
48 NTSTATUS status = BCryptOpenAlgorithmProvider(
49 &h_,
50 BCRYPT_RNG_ALGORITHM,
51 nullptr,
52 0);
53 if (!BCRYPT_SUCCESS(status))
54 h_ = nullptr;
55 }
56
57 ~rng_provider()
58 {
59 if (h_)
60 BCryptCloseAlgorithmProvider(h_, 0);
61 }
62
63 rng_provider(rng_provider const&) = delete;
64 rng_provider& operator=(rng_provider const&) = delete;
65
66 bool generate(void* buf, std::size_t n) const
67 {
68 if (!h_)
69 return false;
70 NTSTATUS status = BCryptGenRandom(
71 h_,
72 static_cast<PUCHAR>(buf),
73 static_cast<ULONG>(n),
74 0);
75 return BCRYPT_SUCCESS(status);
76 }
77 };
78
79 rng_provider& get_rng()
80 {
81 static rng_provider rng;
82 return rng;
83 }
84
85 } // namespace
86
87 void
88 fill_random(void* buf, std::size_t n)
89 {
90 if (!get_rng().generate(buf, n))
91 {
92 capy::detail::throw_system_error(
93 system::error_code(
94 static_cast<int>(GetLastError()),
95 system::system_category()));
96 }
97 }
98
99 #elif defined(__linux__)
100
101 void
102 14 fill_random(void* buf, std::size_t n)
103 {
104 14 auto* p = static_cast<unsigned char*>(buf);
105
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
28 while (n > 0)
106 {
107 14 ssize_t r = getrandom(p, n, 0);
108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (r < 0)
109 {
110 if (errno == EINTR)
111 continue;
112 capy::detail::throw_system_error(
113 system::error_code(
114 errno,
115 system::system_category()));
116 }
117 14 p += r;
118 14 n -= static_cast<std::size_t>(r);
119 }
120 14 }
121
122 #elif defined(__APPLE__)
123
124 void
125 fill_random(void* buf, std::size_t n)
126 {
127 int err = SecRandomCopyBytes(kSecRandomDefault, n, buf);
128 if (err != errSecSuccess)
129 {
130 capy::detail::throw_system_error(
131 system::error_code(
132 err,
133 system::system_category()));
134 }
135 }
136
137 #else
138
139 // Fallback: /dev/urandom
140 void
141 fill_random(void* buf, std::size_t n)
142 {
143 static int fd = -1;
144 if (fd < 0)
145 {
146 fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
147 if (fd < 0)
148 {
149 capy::detail::throw_system_error(
150 system::error_code(
151 errno,
152 system::system_category()));
153 }
154 }
155
156 auto* p = static_cast<unsigned char*>(buf);
157 while (n > 0)
158 {
159 ssize_t r = read(fd, p, n);
160 if (r < 0)
161 {
162 if (errno == EINTR)
163 continue;
164 capy::detail::throw_system_error(
165 system::error_code(
166 errno,
167 system::system_category()));
168 }
169 if (r == 0)
170 {
171 capy::detail::throw_runtime_error(
172 "unexpected EOF from /dev/urandom");
173 }
174 p += r;
175 n -= static_cast<std::size_t>(r);
176 }
177 }
178
179 #endif
180
181 } // detail
182 } // bcrypt
183 } // capy
184 } // boost
185
186