LCOV - code coverage report
Current view: top level - src/bcrypt - random.cpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 61.5 % 13 8 5
Test Date: 2026-06-13 19:44:58 Functions: 100.0 % 1 1

           TLA  Line data    Source code
       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/http
       8                 : //
       9                 : 
      10                 : #include "random.hpp"
      11                 : #include <boost/http/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 http {
      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                 :         http::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 HIT          20 : fill_random(void* buf, std::size_t n)
     103                 : {
     104              20 :     auto* p = static_cast<unsigned char*>(buf);
     105              40 :     while (n > 0)
     106                 :     {
     107              20 :         ssize_t r = getrandom(p, n, 0);
     108              20 :         if (r < 0)
     109                 :         {
     110 MIS           0 :             if (errno == EINTR)
     111               0 :                 continue;
     112               0 :             http::detail::throw_system_error(
     113               0 :                 system::error_code(
     114               0 :                     errno,
     115                 :                     system::system_category()));
     116                 :         }
     117 HIT          20 :         p += r;
     118              20 :         n -= static_cast<std::size_t>(r);
     119                 :     }
     120              20 : }
     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                 :         http::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                 :             http::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                 :             http::detail::throw_system_error(
     165                 :                 system::error_code(
     166                 :                     errno,
     167                 :                     system::system_category()));
     168                 :         }
     169                 :         if (r == 0)
     170                 :         {
     171                 :             http::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                 : } // http
     184                 : } // boost
        

Generated by: LCOV version 2.3