#include "crypto_int.h"
krb5_error_code KRB5_CALLCONV
krb5_c_random_seed(krb5_context context, krb5_data *data)
{
return krb5_c_random_add_entropy(context, KRB5_C_RANDSOURCE_OLDAPI, data);
}
#if defined(_WIN32)
static krb5_boolean
get_os_entropy(unsigned char *buf, size_t len)
{
krb5_boolean result;
HCRYPTPROV provider;
if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
return FALSE;
result = CryptGenRandom(provider, len, buf);
(void)CryptReleaseContext(provider, 0);
return result;
}
#else
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_SYS_RANDOM_H
#include <sys/random.h>
#endif
#ifdef __linux__
#include <sys/syscall.h>
#endif
static krb5_boolean
read_entropy_from_device(const char *device, unsigned char *buf, size_t len)
{
struct stat sb;
int fd;
unsigned char *bp;
size_t left;
ssize_t count;
krb5_boolean result = FALSE;
fd = open(device, O_RDONLY);
if (fd == -1)
return FALSE;
set_cloexec_fd(fd);
if (fstat(fd, &sb) == -1 || S_ISREG(sb.st_mode))
goto cleanup;
for (bp = buf, left = len; left > 0;) {
count = read(fd, bp, left);
if (count <= 0)
goto cleanup;
left -= count;
bp += count;
}
result = TRUE;
cleanup:
close(fd);
return result;
}
static krb5_boolean
get_os_entropy(unsigned char *buf, size_t len)
{
#if defined(HAVE_GETENTROPY)
int r;
size_t seg;
while (len > 0) {
seg = (len > 256) ? 256 : len;
r = getentropy(buf, seg);
if (r != 0)
break;
len -= seg;
buf += seg;
}
if (len == 0)
return TRUE;
#elif defined(__linux__) && defined(SYS_getrandom)
int r;
while (len > 0) {
errno = 0;
r = syscall(SYS_getrandom, buf, len, 0);
if (r <= 0) {
if (errno == EINTR)
continue;
break;
}
len -= r;
buf += r;
}
if (len == 0)
return TRUE;
#endif
return read_entropy_from_device("/dev/urandom", buf, len);
}
#endif
krb5_error_code KRB5_CALLCONV
krb5_c_random_make_octets(krb5_context context, krb5_data *outdata)
{
krb5_boolean res;
res = get_os_entropy((uint8_t *)outdata->data, outdata->length);
return res ? 0 : KRB5_CRYPTO_INTERNAL;
}
krb5_error_code KRB5_CALLCONV
krb5_c_random_add_entropy(krb5_context context, unsigned int randsource,
const krb5_data *indata)
{
return 0;
}
krb5_error_code KRB5_CALLCONV
krb5_c_random_os_entropy(krb5_context context, int strong, int *success)
{
*success = 0;
return 0;
}