root/maint/gnulib/lib/getrandom.c

/* [previous][next][first][last][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-2021 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 <stdbool.h>
  27 #include <unistd.h>
  28 
  29 #if defined _WIN32 && ! defined __CYGWIN__
  30 # define WIN32_LEAN_AND_MEAN
  31 # include <windows.h>
  32 # if HAVE_BCRYPT_H
  33 #  include <bcrypt.h>
  34 # else
  35 #  define NTSTATUS LONG
  36 typedef void * BCRYPT_ALG_HANDLE;
  37 #  define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002
  38 #  if HAVE_LIB_BCRYPT
  39 extern NTSTATUS WINAPI BCryptGenRandom (BCRYPT_ALG_HANDLE, UCHAR *, ULONG, ULONG);
  40 #  endif
  41 # endif
  42 # if !HAVE_LIB_BCRYPT
  43 #  include <wincrypt.h>
  44 #  ifndef CRYPT_VERIFY_CONTEXT
  45 #   define CRYPT_VERIFY_CONTEXT 0xF0000000
  46 #  endif
  47 # endif
  48 #endif
  49 
  50 #include "minmax.h"
  51 
  52 #if defined _WIN32 && ! defined __CYGWIN__
  53 
  54 /* Don't assume that UNICODE is not defined.  */
  55 # undef LoadLibrary
  56 # define LoadLibrary LoadLibraryA
  57 # undef CryptAcquireContext
  58 # define CryptAcquireContext CryptAcquireContextA
  59 
  60 # if !HAVE_LIB_BCRYPT
  61 
  62 /* Avoid warnings from gcc -Wcast-function-type.  */
  63 #  define GetProcAddress \
  64     (void *) GetProcAddress
  65 
  66 /* BCryptGenRandom with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag works only
  67    starting with Windows 7.  */
  68 typedef NTSTATUS (WINAPI * BCryptGenRandomFuncType) (BCRYPT_ALG_HANDLE, UCHAR *, ULONG, ULONG);
  69 static BCryptGenRandomFuncType BCryptGenRandomFunc = NULL;
  70 static BOOL initialized = FALSE;
  71 
  72 static void
  73 initialize (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  74 {
  75   HMODULE bcrypt = LoadLibrary ("bcrypt.dll");
  76   if (bcrypt != NULL)
  77     {
  78       BCryptGenRandomFunc =
  79         (BCryptGenRandomFuncType) GetProcAddress (bcrypt, "BCryptGenRandom");
  80     }
  81   initialized = TRUE;
  82 }
  83 
  84 # else
  85 
  86 #  define BCryptGenRandomFunc BCryptGenRandom
  87 
  88 # endif
  89 
  90 #else
  91 /* These devices exist on all platforms except native Windows.  */
  92 
  93 /* Name of a device through which the kernel returns high quality random
  94    numbers, from an entropy pool.  When the pool is empty, the call blocks
  95    until entropy sources have added enough bits of entropy.  */
  96 # ifndef NAME_OF_RANDOM_DEVICE
  97 #  define NAME_OF_RANDOM_DEVICE "/dev/random"
  98 # endif
  99 
 100 /* Name of a device through which the kernel returns random or pseudo-random
 101    numbers.  It uses an entropy pool, but, in order to avoid blocking, adds
 102    bits generated by a pseudo-random number generator, as needed.  */
 103 # ifndef NAME_OF_NONCE_DEVICE
 104 #  define NAME_OF_NONCE_DEVICE "/dev/urandom"
 105 # endif
 106 
 107 #endif
 108 
 109 /* Set BUFFER (of size LENGTH) to random bytes under the control of FLAGS.
 110    Return the number of bytes written (> 0).
 111    Upon error, return -1 and set errno.  */
 112 ssize_t
 113 getrandom (void *buffer, size_t length, unsigned int flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 114 #undef getrandom
 115 {
 116 #if defined _WIN32 && ! defined __CYGWIN__
 117   /* BCryptGenRandom, defined in <bcrypt.h>
 118      <https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom>
 119      with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag
 120      works in Windows 7 and newer.  */
 121   static int bcrypt_not_working /* = 0 */;
 122   if (!bcrypt_not_working)
 123     {
 124 # if !HAVE_LIB_BCRYPT
 125       if (!initialized)
 126         initialize ();
 127 # endif
 128       if (BCryptGenRandomFunc != NULL
 129           && BCryptGenRandomFunc (NULL, buffer, length,
 130                                   BCRYPT_USE_SYSTEM_PREFERRED_RNG)
 131              == 0 /*STATUS_SUCCESS*/)
 132         return length;
 133       bcrypt_not_working = 1;
 134     }
 135 # if !HAVE_LIB_BCRYPT
 136   /* CryptGenRandom, defined in <wincrypt.h>
 137      <https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom>
 138      works in older releases as well, but is now deprecated.
 139      CryptAcquireContext, defined in <wincrypt.h>
 140      <https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecontexta>  */
 141   {
 142     static int crypt_initialized /* = 0 */;
 143     static HCRYPTPROV provider;
 144     if (!crypt_initialized)
 145       {
 146         if (CryptAcquireContext (&provider, NULL, NULL, PROV_RSA_FULL,
 147                                  CRYPT_VERIFY_CONTEXT))
 148           crypt_initialized = 1;
 149         else
 150           crypt_initialized = -1;
 151       }
 152     if (crypt_initialized >= 0)
 153       {
 154         if (!CryptGenRandom (provider, length, buffer))
 155           {
 156             errno = EIO;
 157             return -1;
 158           }
 159         return length;
 160       }
 161   }
 162 # endif
 163   errno = ENOSYS;
 164   return -1;
 165 #elif HAVE_GETRANDOM
 166   return getrandom (buffer, length, flags);
 167 #else
 168   static int randfd[2] = { -1, -1 };
 169   bool devrandom = (flags & GRND_RANDOM) != 0;
 170   int fd = randfd[devrandom];
 171 
 172   if (fd < 0)
 173     {
 174       static char const randdevice[][MAX (sizeof NAME_OF_NONCE_DEVICE,
 175                                           sizeof NAME_OF_RANDOM_DEVICE)]
 176         = { NAME_OF_NONCE_DEVICE, NAME_OF_RANDOM_DEVICE };
 177       int oflags = (O_RDONLY + O_CLOEXEC
 178                     + (flags & GRND_NONBLOCK ? O_NONBLOCK : 0));
 179       fd = open (randdevice[devrandom], oflags);
 180       if (fd < 0)
 181         {
 182           if (errno == ENOENT || errno == ENOTDIR)
 183             errno = ENOSYS;
 184           return -1;
 185         }
 186       randfd[devrandom] = fd;
 187     }
 188 
 189   return read (fd, buffer, length);
 190 #endif
 191 }

/* [previous][next][first][last][top][bottom][index][help] */