LCOV - code coverage report
Current view: top level - libs/capy/src/bcrypt - random.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 61.5 % 13 8
Test Date: 2025-12-31 15:26:29 Functions: 100.0 % 1 1

            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/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           28 :     while (n > 0)
     106              :     {
     107           14 :         ssize_t r = getrandom(p, n, 0);
     108           14 :         if (r < 0)
     109              :         {
     110            0 :             if (errno == EINTR)
     111            0 :                 continue;
     112            0 :             capy::detail::throw_system_error(
     113            0 :                 system::error_code(
     114            0 :                     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              : 
        

Generated by: LCOV version 2.1