/
niceSOFT
/
libxcrypt
Обзор
Документация
Войти
/
niceSOFT
/
libxcrypt
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
lib/util-get-random-bytes.c
154 строки
4 KB
Björn Esser
util-get-random-bytes: Close arc4random conditional at end of function.
24 янв 2025, 20:52
Не верифицирован
24 янв 2025, 20:52
ca15167
Код
Авторство
О чём код?
/* Retrieval of cryptographically random bytes from the operating system. * * Written by Zack Weinberg <zackw at panix.com> in 2017. * * No copyright is claimed, and the software is hereby placed in the public * domain. In case this attempt to disclaim copyright and place the software * in the public domain is deemed null and void, then the software is * Copyright (c) 2017 Zack Weinberg and it is hereby released to the * general public under the following terms: * * Redistribution and use in source and binary forms, with or without * modification, are permitted. * * There's ABSOLUTELY NO WARRANTY, express or implied. */ #include "crypt-port.h" #include <errno.h> #include <stdlib.h> #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif #ifdef HAVE_SYS_RANDOM_H #include <sys/random.h> #endif #ifdef HAVE_SYS_SYSCALL_H #include <sys/syscall.h> #endif #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif /* If we have O_CLOEXEC, we use it, but if we don't, we don't worry about it. */ #ifndef O_CLOEXEC #define O_CLOEXEC 0 #endif /* There is no universally portable way to access a system CSPRNG. If the C library provides any of the following functions, we try them, in order of preference: arc4random_buf, getentropy, getrandom. If none of those are available or they don't work, we attempt to make direct system calls for getentropy and getrandom. If *that* doesn't work, we try opening and reading /dev/urandom. This function returns true if the exact number of requested bytes was successfully read, false otherwise; if it returns false, errno has been set. It may block. It cannot be used to read more than 256 bytes at a time (this is a limitation inherited from getentropy() and enforced regardless of the actual back-end in use). If we fall all the way back to /dev/urandom, we open and close it on each call. */ bool get_random_bytes(void *buf, size_t buflen) { if (buflen == 0) return true; /* Some, but not all, of the primitives below are limited to producing no more than 256 bytes of random data. Impose this constraint on our callers regardless of which primitive is actually used. */ if (buflen > 256) { errno = EIO; return false; } /* To eliminate the possibility of one of the primitives below failing with EFAULT, force a crash now if the buffer is unwritable. */ explicit_bzero (buf, buflen); #ifdef HAVE_ARC4RANDOM_BUF /* arc4random_buf, if it exists, can never fail. */ arc4random_buf (buf, buflen); return true; #else /* no arc4random_buf */ #ifdef HAVE_GETENTROPY /* getentropy may exist but lack kernel support. */ static bool getentropy_doesnt_work; if (!getentropy_doesnt_work) { if (!getentropy (buf, buflen)) return true; getentropy_doesnt_work = true; } #endif #ifdef HAVE_GETRANDOM /* Likewise getrandom. */ static bool getrandom_doesnt_work; if (!getrandom_doesnt_work) { if ((size_t)getrandom (buf, buflen, 0) == buflen) return true; getrandom_doesnt_work = true; } #endif /* If we can make arbitrary syscalls, try getentropy and getrandom again that way. */ #ifdef HAVE_SYSCALL #ifdef SYS_getentropy static bool sys_getentropy_doesnt_work; if (!sys_getentropy_doesnt_work) { if (!syscall (SYS_getentropy, buf, buflen)) return true; sys_getentropy_doesnt_work = true; } #endif #ifdef SYS_getrandom static bool sys_getrandom_doesnt_work; if (!sys_getrandom_doesnt_work) { if ((size_t)syscall (SYS_getrandom, buf, buflen, 0) == buflen) return true; sys_getrandom_doesnt_work = true; } #endif #endif #if defined HAVE_SYS_STAT_H && defined HAVE_FCNTL_H && defined HAVE_UNISTD_H /* Try reading from /dev/urandom. */ static bool dev_urandom_doesnt_work; if (!dev_urandom_doesnt_work) { int fd = open ("/dev/urandom", O_RDONLY|O_CLOEXEC); if (fd == -1) dev_urandom_doesnt_work = true; else { ssize_t nread = read (fd, buf, buflen); if (nread < 0 || (size_t)nread < buflen) dev_urandom_doesnt_work = true; close(fd); return !dev_urandom_doesnt_work; } } #endif /* if we get here, we're just completely hosed */ errno = ENOSYS; return false; #endif /* no arc4random_buf */ }