Example #1
0
/* {{{ */
static int php_random_bytes(void *bytes, size_t size)
{
#if PHP_WIN32
	/* Defer to CryptGenRandom on Windows */
	if (php_win32_get_random_bytes(bytes, size) == FAILURE) {
		zend_throw_exception(zend_ce_exception, "Could not gather sufficient random data", 0);
		return FAILURE;
	}
#elif HAVE_DECL_ARC4RANDOM_BUF
	arc4random_buf(bytes, size);
#else
	int    fd = RANDOM_G(fd);
	size_t read_bytes = 0;

	if (fd < 0) {
#if HAVE_DEV_ARANDOM
		fd = open("/dev/arandom", O_RDONLY);
#elif HAVE_DEV_URANDOM
		fd = open("/dev/urandom", O_RDONLY);
#endif
		if (fd < 0) {
			zend_throw_exception(zend_ce_exception, "Cannot open source device", 0);
			return FAILURE;
		}

		RANDOM_G(fd) = fd;
	}

	while (read_bytes < size) {
		ssize_t n = read(fd, bytes + read_bytes, size - read_bytes);
		if (n <= 0) {
			break;
		}
		read_bytes += n;
	}

	if (read_bytes < size) {
		zend_throw_exception(zend_ce_exception, "Could not gather sufficient random data", 0);
		return FAILURE;
	}
#endif

	return SUCCESS;
}
Example #2
0
static int php_password_make_salt(size_t length, char *ret) /* {{{ */
{
	int buffer_valid = 0;
	size_t i, raw_length;
	char *buffer;
	char *result;

	if (length > (INT_MAX / 3)) {
		php_error_docref(NULL, E_WARNING, "Length is too large to safely generate");
		return FAILURE;
	}

	raw_length = length * 3 / 4 + 1;

	buffer = (char *) safe_emalloc(raw_length, 1, 1);

#if PHP_WIN32
	{
		BYTE *iv_b = (BYTE *) buffer;
		if (php_win32_get_random_bytes(iv_b, raw_length) == SUCCESS) {
			buffer_valid = 1;
		}
	}
#else
	{
		int fd, n;
		size_t read_bytes = 0;
		fd = open("/dev/urandom", O_RDONLY);
		if (fd >= 0) {
			while (read_bytes < raw_length) {
				n = read(fd, buffer + read_bytes, raw_length - read_bytes);
				if (n < 0) {
					break;
				}
				read_bytes += (size_t) n;
			}
			close(fd);
		}
		if (read_bytes >= raw_length) {
			buffer_valid = 1;
		}
	}
#endif
	if (!buffer_valid) {
		for (i = 0; i < raw_length; i++) {
			buffer[i] ^= (char) (255.0 * php_rand() / RAND_MAX);
		}
	}

	result = safe_emalloc(length, 1, 1);
	if (php_password_salt_to64(buffer, raw_length, length, result) == FAILURE) {
		php_error_docref(NULL, E_WARNING, "Generated salt too short");
		efree(buffer);
		efree(result);
		return FAILURE;
	}
	memcpy(ret, result, length);
	efree(result);
	efree(buffer);
	ret[length] = 0;
	return SUCCESS;
}
Example #3
0
static int php_random_bytes(void *bytes, size_t size)
{
#if PHP_WIN32
	/* Defer to CryptGenRandom on Windows */
	if (php_win32_get_random_bytes(bytes, size) == FAILURE) {
		zend_throw_exception(zend_ce_exception, "Could not gather sufficient random data", 0);
		return FAILURE;
	}
#elif HAVE_DECL_ARC4RANDOM_BUF && ((defined(__OpenBSD__) && OpenBSD >= 201405) || (defined(__NetBSD__) && __NetBSD_Version__ >= 700000001))
	arc4random_buf(bytes, size);
#elif HAVE_DECL_GETRANDOM
	/* Linux getrandom(2) syscall */
	size_t read_bytes = 0;
	size_t amount_to_read = 0;
	ssize_t n;

	/* Keep reading until we get enough entropy */
	do {
		amount_to_read = size - read_bytes;
		/* Below, (bytes + read_bytes)  is pointer arithmetic.

		   bytes   read_bytes  size
		     |      |           |
		    [#######=============] (we're going to write over the = region)
		             \\\\\\\\\\\\\
		              amount_to_read

		*/
		n = syscall(SYS_getrandom, bytes + read_bytes, amount_to_read, 0);

		if (n == -1) {
			if (errno == EINTR || errno == EAGAIN) {
				/* Try again */
				continue;
			}
			/*
				If the syscall fails, we are doomed. The loop that calls
				php_random_bytes should be terminated by the exception instead
				of proceeding to demand more entropy.
			*/
			zend_throw_exception(zend_ce_exception, "Could not gather sufficient random data", errno);
			return FAILURE;
		}

		read_bytes += (size_t) n;
	} while (read_bytes < size);
#else
	int    fd = RANDOM_G(fd);
	struct stat st;
	size_t read_bytes = 0;
	ssize_t n;

	if (fd < 0) {
#if HAVE_DEV_URANDOM
		fd = open("/dev/urandom", O_RDONLY);
#endif
		if (fd < 0) {
			zend_throw_exception(zend_ce_exception, "Cannot open source device", 0);
			return FAILURE;
		}
		/* Does the file exist and is it a character device? */
		if (fstat(fd, &st) != 0 || 
# ifdef S_ISNAM
                !(S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode))
# else
                !S_ISCHR(st.st_mode)
# endif
		) {
			close(fd);
			zend_throw_exception(zend_ce_exception, "Error reading from source device", 0);
			return FAILURE;
		}
		RANDOM_G(fd) = fd;
	}

	while (read_bytes < size) {
		n = read(fd, bytes + read_bytes, size - read_bytes);
		if (n <= 0) {
			break;
		}
		read_bytes += n;
	}

	if (read_bytes < size) {
		zend_throw_exception(zend_ce_exception, "Could not gather sufficient random data", 0);
		return FAILURE;
	}
#endif

	return SUCCESS;
}
Example #4
0
/* {{{ */
PHPAPI int php_random_bytes(void *bytes, size_t size, zend_bool should_throw)
{
#ifdef PHP_WIN32
	/* Defer to CryptGenRandom on Windows */
	if (php_win32_get_random_bytes(bytes, size) == FAILURE) {
		if (should_throw) {
			zend_throw_exception(zend_ce_exception, "Could not gather sufficient random data", 0);
		}
		return FAILURE;
	}
#elif HAVE_DECL_ARC4RANDOM_BUF && ((defined(__OpenBSD__) && OpenBSD >= 201405) || (defined(__NetBSD__) && __NetBSD_Version__ >= 700000001))
	arc4random_buf(bytes, size);
#else
	size_t read_bytes = 0;
	ssize_t n;
#if defined(__linux__) && defined(SYS_getrandom)
	/* Linux getrandom(2) syscall */
	/* Keep reading until we get enough entropy */
	while (read_bytes < size) {
		/* Below, (bytes + read_bytes)  is pointer arithmetic.

		   bytes   read_bytes  size
		     |      |           |
		    [#######=============] (we're going to write over the = region)
		             \\\\\\\\\\\\\
		              amount_to_read

		*/
		size_t amount_to_read = size - read_bytes;
		n = syscall(SYS_getrandom, bytes + read_bytes, amount_to_read, 0);

		if (n == -1) {
			if (errno == ENOSYS) {
				/* This can happen if PHP was compiled against a newer kernel where getrandom()
				 * is available, but then runs on an older kernel without getrandom(). If this
				 * happens we simply fall back to reading from /dev/urandom. */
				ZEND_ASSERT(read_bytes == 0);
				break;
			} else if (errno == EINTR || errno == EAGAIN) {
				/* Try again */
				continue;
			} else {
			    /* If the syscall fails, fall back to reading from /dev/urandom */
				break;
			}
		}

		read_bytes += (size_t) n;
	}
#endif
	if (read_bytes < size) {
		int    fd = RANDOM_G(fd);
		struct stat st;

		if (fd < 0) {
#if HAVE_DEV_URANDOM
			fd = open("/dev/urandom", O_RDONLY);
#endif
			if (fd < 0) {
				if (should_throw) {
					zend_throw_exception(zend_ce_exception, "Cannot open source device", 0);
				}
				return FAILURE;
			}
			/* Does the file exist and is it a character device? */
			if (fstat(fd, &st) != 0 ||
# ifdef S_ISNAM
					!(S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode))
# else
					!S_ISCHR(st.st_mode)
# endif
			) {
				close(fd);
				if (should_throw) {
					zend_throw_exception(zend_ce_exception, "Error reading from source device", 0);
				}
				return FAILURE;
			}
			RANDOM_G(fd) = fd;
		}

		for (read_bytes = 0; read_bytes < size; read_bytes += (size_t) n) {
			n = read(fd, bytes + read_bytes, size - read_bytes);
			if (n <= 0) {
				break;
			}
		}

		if (read_bytes < size) {
			if (should_throw) {
				zend_throw_exception(zend_ce_exception, "Could not gather sufficient random data", 0);
			}
			return FAILURE;
		}
	}
#endif

	return SUCCESS;
}