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