root/lib/getrandom.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. initialize
  2. getrandom

     1 /* Obtain a series of random bytes.
     2 
     3    Copyright 2020-2023 Free Software Foundation, Inc.
     4 
     5    This file is free software: you can redistribute it and/or modify
     6    it under the terms of the GNU Lesser General Public License as
     7    published by the Free Software Foundation; either version 2.1 of the
     8    License, or (at your option) any later version.
     9 
    10    This file is distributed in the hope that it will be useful,
    11    but WITHOUT ANY WARRANTY; without even the implied warranty of
    12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13    GNU Lesser General Public License for more details.
    14 
    15    You should have received a copy of the GNU Lesser General Public License
    16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
    17 
    18 /* Written by Paul Eggert.  */
    19 
    20 #include <config.h>
    21 
    22 #include <sys/random.h>
    23 
    24 #include <errno.h>
    25 #include <fcntl.h>
    26 #include <unistd.h>
    27 
    28 #if defined _WIN32 && ! defined __CYGWIN__
    29 # define WIN32_LEAN_AND_MEAN
    30 # include <windows.h>
    31 # if HAVE_BCRYPT_H
    32 #  include <bcrypt.h>
    33 # else
    34 #  define NTSTATUS LONG
    35 typedef void * BCRYPT_ALG_HANDLE;
    36 #  define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002
    37 #  if HAVE_LIB_BCRYPT
    38 extern NTSTATUS WINAPI BCryptGenRandom (BCRYPT_ALG_HANDLE, UCHAR *, ULONG, ULONG);
    39 #  endif
    40 # endif
    41 # if !HAVE_LIB_BCRYPT
    42 #  include <wincrypt.h>
    43 #  ifndef CRYPT_VERIFY_CONTEXT
    44 #   define CRYPT_VERIFY_CONTEXT 0xF0000000
    45 #  endif
    46 # endif
    47 #endif
    48 
    49 #include "minmax.h"
    50 
    51 #if defined _WIN32 && ! defined __CYGWIN__
    52 
    53 /* Don't assume that UNICODE is not defined.  */
    54 # undef LoadLibrary
    55 # define LoadLibrary LoadLibraryA
    56 # undef CryptAcquireContext
    57 # define CryptAcquireContext CryptAcquireContextA
    58 
    59 # if !HAVE_LIB_BCRYPT
    60 
    61 /* Avoid warnings from gcc -Wcast-function-type.  */
    62 #  define GetProcAddress \
    63     (void *) GetProcAddress
    64 
    65 /* BCryptGenRandom with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag works only
    66    starting with Windows 7.  */
    67 typedef NTSTATUS (WINAPI * BCryptGenRandomFuncType) (BCRYPT_ALG_HANDLE, UCHAR *, ULONG, ULONG);
    68 static BCryptGenRandomFuncType BCryptGenRandomFunc = NULL;
    69 static BOOL initialized = FALSE;
    70 
    71 static void
    72 initialize (void)
    73 {
    74   HMODULE bcrypt = LoadLibrary ("bcrypt.dll");
    75   if (bcrypt != NULL)
    76     {
    77       BCryptGenRandomFunc =
    78         (BCryptGenRandomFuncType) GetProcAddress (bcrypt, "BCryptGenRandom");
    79     }
    80   initialized = TRUE;
    81 }
    82 
    83 # else
    84 
    85 #  define BCryptGenRandomFunc BCryptGenRandom
    86 
    87 # endif
    88 
    89 #else
    90 /* These devices exist on all platforms except native Windows.  */
    91 
    92 /* Name of a device through which the kernel returns high quality random
    93    numbers, from an entropy pool.  When the pool is empty, the call blocks
    94    until entropy sources have added enough bits of entropy.  */
    95 # ifndef NAME_OF_RANDOM_DEVICE
    96 #  define NAME_OF_RANDOM_DEVICE "/dev/random"
    97 # endif
    98 
    99 /* Name of a device through which the kernel returns random or pseudo-random
   100    numbers.  It uses an entropy pool, but, in order to avoid blocking, adds
   101    bits generated by a pseudo-random number generator, as needed.  */
   102 # ifndef NAME_OF_NONCE_DEVICE
   103 #  define NAME_OF_NONCE_DEVICE "/dev/urandom"
   104 # endif
   105 
   106 #endif
   107 
   108 /* Set BUFFER (of size LENGTH) to random bytes under the control of FLAGS.
   109    Return the number of bytes written (> 0).
   110    Upon error, return -1 and set errno.  */
   111 ssize_t
   112 getrandom (void *buffer, size_t length, unsigned int flags)
   113 #undef getrandom
   114 {
   115 #if defined _WIN32 && ! defined __CYGWIN__
   116   /* BCryptGenRandom, defined in <bcrypt.h>
   117      <https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom>
   118      with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag
   119      works in Windows 7 and newer.  */
   120   static int bcrypt_not_working /* = 0 */;
   121   if (!bcrypt_not_working)
   122     {
   123 # if !HAVE_LIB_BCRYPT
   124       if (!initialized)
   125         initialize ();
   126 # endif
   127       if (BCryptGenRandomFunc != NULL
   128           && BCryptGenRandomFunc (NULL, buffer, length,
   129                                   BCRYPT_USE_SYSTEM_PREFERRED_RNG)
   130              == 0 /*STATUS_SUCCESS*/)
   131         return length;
   132       bcrypt_not_working = 1;
   133     }
   134 # if !HAVE_LIB_BCRYPT
   135   /* CryptGenRandom, defined in <wincrypt.h>
   136      <https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom>
   137      works in older releases as well, but is now deprecated.
   138      CryptAcquireContext, defined in <wincrypt.h>
   139      <https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecontexta>  */
   140   {
   141     static int crypt_initialized /* = 0 */;
   142     static HCRYPTPROV provider;
   143     if (!crypt_initialized)
   144       {
   145         if (CryptAcquireContext (&provider, NULL, NULL, PROV_RSA_FULL,
   146                                  CRYPT_VERIFY_CONTEXT))
   147           crypt_initialized = 1;
   148         else
   149           crypt_initialized = -1;
   150       }
   151     if (crypt_initialized >= 0)
   152       {
   153         if (!CryptGenRandom (provider, length, buffer))
   154           {
   155             errno = EIO;
   156             return -1;
   157           }
   158         return length;
   159       }
   160   }
   161 # endif
   162   errno = ENOSYS;
   163   return -1;
   164 #elif HAVE_GETRANDOM
   165   return getrandom (buffer, length, flags);
   166 #else
   167   static int randfd[2] = { -1, -1 };
   168   bool devrandom = (flags & GRND_RANDOM) != 0;
   169   int fd = randfd[devrandom];
   170 
   171   if (fd < 0)
   172     {
   173       static char const randdevice[][MAX (sizeof NAME_OF_NONCE_DEVICE,
   174                                           sizeof NAME_OF_RANDOM_DEVICE)]
   175         = { NAME_OF_NONCE_DEVICE, NAME_OF_RANDOM_DEVICE };
   176       int oflags = (O_RDONLY + O_CLOEXEC
   177                     + (flags & GRND_NONBLOCK ? O_NONBLOCK : 0));
   178       fd = open (randdevice[devrandom], oflags);
   179       if (fd < 0)
   180         {
   181           if (errno == ENOENT || errno == ENOTDIR)
   182             errno = ENOSYS;
   183           return -1;
   184         }
   185       randfd[devrandom] = fd;
   186     }
   187 
   188   return read (fd, buffer, length);
   189 #endif
   190 }

/* [<][>][^][v][top][bottom][index][help] */