1 /* Obtain a series of random bytes.
3 Copyright 2020-2024 Free Software Foundation, Inc.
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.
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.
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/>. */
18 /* Written by Paul Eggert. */
22 #include <sys/random.h>
28 #if defined _WIN32 && ! defined __CYGWIN__
29 # define WIN32_LEAN_AND_MEAN
34 # define NTSTATUS LONG
35 typedef void * BCRYPT_ALG_HANDLE
;
36 # define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002
38 extern NTSTATUS WINAPI
BCryptGenRandom (BCRYPT_ALG_HANDLE
, UCHAR
*, ULONG
, ULONG
);
42 # include <wincrypt.h>
43 # ifndef CRYPT_VERIFY_CONTEXT
44 # define CRYPT_VERIFY_CONTEXT 0xF0000000
51 #if defined _WIN32 && ! defined __CYGWIN__
53 /* Don't assume that UNICODE is not defined. */
55 # define LoadLibrary LoadLibraryA
56 # undef CryptAcquireContext
57 # define CryptAcquireContext CryptAcquireContextA
61 /* Avoid warnings from gcc -Wcast-function-type. */
62 # define GetProcAddress \
63 (void *) GetProcAddress
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
;
74 HMODULE bcrypt
= LoadLibrary ("bcrypt.dll");
78 (BCryptGenRandomFuncType
) GetProcAddress (bcrypt
, "BCryptGenRandom");
85 # define BCryptGenRandomFunc BCryptGenRandom
90 /* These devices exist on all platforms except native Windows. */
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"
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"
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. */
112 getrandom (void *buffer
, size_t length
, unsigned int flags
)
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
)
123 # if !HAVE_LIB_BCRYPT
127 if (BCryptGenRandomFunc
!= NULL
128 && BCryptGenRandomFunc (NULL
, buffer
, length
,
129 BCRYPT_USE_SYSTEM_PREFERRED_RNG
)
130 == 0 /*STATUS_SUCCESS*/)
132 bcrypt_not_working
= 1;
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> */
141 static int crypt_initialized
/* = 0 */;
142 static HCRYPTPROV provider
;
143 if (!crypt_initialized
)
145 if (CryptAcquireContext (&provider
, NULL
, NULL
, PROV_RSA_FULL
,
146 CRYPT_VERIFY_CONTEXT
))
147 crypt_initialized
= 1;
149 crypt_initialized
= -1;
151 if (crypt_initialized
>= 0)
153 if (!CryptGenRandom (provider
, length
, buffer
))
165 return getrandom (buffer
, length
, flags
);
167 static int randfd
[2] = { -1, -1 };
168 bool devrandom
= (flags
& GRND_RANDOM
) != 0;
169 int fd
= randfd
[devrandom
];
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
);
181 if (errno
== ENOENT
|| errno
== ENOTDIR
)
185 randfd
[devrandom
] = fd
;
188 return read (fd
, buffer
, length
);