Re: Question - seeding the hw pseudo random number generator

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Am Donnerstag, 23. März 2017, 10:44:06 CET schrieb Herbert Xu:

Hi Herbert,

> On Thu, Mar 23, 2017 at 09:23:07AM +0100, Corentin Labbe wrote:
> > Problem with this conversion, a huge regression for user space.
> > Using hwrng is simple as cat /dev/hwrng.
> > Using algif_rng via AF_ALG is ... unusable for the moment.
> > Perhaps creating an user space tool (prng-tool which provide a cat
> > /dev/hwrng replacement) is mandatory before any convertion.
> Stephan may have a tool to do this.  Stephan?

Here is a suggestion for such a tool that I could add to libkcapi. Naturally, 
this code is only a demonstrator which lacks some features.

Ciao
Stephan
/*
 * Copyright (C) 2017, Stephan Mueller <smueller@xxxxxxxxxx>
 *
 * License: see COPYING file in root directory
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
 * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */

#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <linux/random.h>
#ifdef HAVE_GETRANDOM
#include <sys/random.h>
#endif

#include <kcapi.h>

struct kcapi_handle *rng = NULL;

static int read_complete(int fd, uint8_t *buf, uint32_t buflen)
{
	ssize_t ret;

	do {
		ret = read(fd, buf, buflen);
		if (0 < ret) {
			buflen -= ret;
			buf += ret;
		}
	} while ((0 < ret || EINTR == errno || ERESTART == errno)
		 && buflen > 0);

	if (buflen == 0)
		return 0;
	return 1;
}

static int read_random(uint8_t *buf, uint32_t buflen)
{
	int fd;
	int ret = 0;

	fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC);
	if (0 > fd)
		return fd;

	ret = read_complete(fd, buf, buflen);
	close(fd);
	return ret;
}

static int get_random(uint8_t *buf, uint32_t buflen)
{
	if (buflen > INT_MAX)
		return 1;

#ifdef HAVE_GETRANDOM
	return getrandom(buf, buflen, 0);
#else
# ifdef __NR_getrandom
	do {
		int ret = syscall(__NR_getrandom, buf, buflen, 0);

		if (0 < ret) {
			buflen -= ret;
			buf += ret;
		}
	} while ((0 < ret || EINTR == errno || ERESTART == errno)
		 && buflen > 0);

	if (buflen == 0)
		return 0;

	return 1;
# else
	return read_random(buf, buflen);
# endif
#endif
}

static void usage(void)
{
	char version[30];
	uint32_t ver = kcapi_version();

	memset(version, 0, sizeof(version));
	kcapi_versionstring(version, sizeof(version));

	fprintf(stderr, "\nKernel Crypto API Random Number Gatherer\n");
	fprintf(stderr, "\nKernel Crypto API interface library version: %s\n", version);
	fprintf(stderr, "Reported numeric version number %u\n\n", ver);
	fprintf(stderr, "Usage:\n");
	fprintf(stderr, "\t<NUM>\tNumber of bytes to generate\n");
}

int main(int argc, char *argv[])
{
	int ret;
	uint8_t buf[64];
	unsigned long outlen;

	if (argc != 2) {
		usage();
		return -EINVAL;
	}

	outlen = strtoul(argv[1], NULL, 10);
	if (outlen == ULONG_MAX) {
		usage();
		return -EINVAL;
	}

	ret = kcapi_rng_init(&rng, "drbg_nopr_hmac_sha256", 0);
	if (ret)
		return ret;

	ret = get_random(buf, sizeof(buf));
	if (ret)
		goto out;

	ret = kcapi_rng_seed(rng, buf, sizeof(buf));
	kcapi_memset_secure(buf, 0, sizeof(buf));
	if (ret)
		goto out;

	while (outlen) {
		uint32_t todo = (outlen < sizeof(buf)) ? outlen : sizeof(buf);

		ret = kcapi_rng_generate(rng, buf, todo);
		if (ret < 0)
			goto out;

		if ((uint32_t)ret != todo) {
			ret = -EFAULT;
			goto out;
		}

		fwrite(&buf, todo, 1, stdout);

		outlen -= todo;
	}

out:
	if (rng)
		kcapi_rng_destroy(rng);
	kcapi_memset_secure(buf, 0, sizeof(buf));

	return ret;
}

[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux