summaryrefslogtreecommitdiffstats
path: root/sysrand.c
blob: bdda374c129d30181becd970535f798a20894e44 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <time.h>
#include "grv.h"

#ifdef __unix__
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

static int xread(int fd, void *buf, size_t count)
{
  char *b = (char *)buf;
  int n = 0;
  int rv;

  while ( count ) {
    rv = read(fd, b, count);
    if ( rv == -1 ) {
      if ( errno == EINTR || errno == EAGAIN )
	continue;
      else
	return n ? n : -1;
    } else if ( rv == 0 ) {
      return n;
    }

    count -= rv;
    n += rv;
    b += rv;
  }
  return n;
}

static int randfd = -1;

int get_random_bytes(void *ptr, int len)
{
  /* We might have /dev/urandom */
  if (randfd < 0) {
    randfd = open("/dev/urandom", O_RDONLY);

    if (randfd < 0)
      return -1;

    /*
     * File descriptors are closed automatically on process exit, so
     * we don't bother setting up atexit() here.
     */
  }

  return xread(randfd, ptr, len) == len ? 0 : -1;
}

#elif defined(__WIN32__)
#include <windows.h>
#include <wincrypt.h>

static HCRYPTPROV hProv;
static int provider_open = 0;

static void close_provider(void)
{
  CryptReleaseContext(hProv, 0);
  provider_open = 0;
}

int get_random_bytes(void *ptr, int len)
{
  BOOL ok;
  static const DWORD providers[] = {
    PROV_RNG, PROV_INTEL_SEC, PROV_RSA_SIG, PROV_RSA_FULL,
    PROV_DSS, PROV_SSL, 0
  };

  if (!provider_open) {
    const DWORD *pp = providers;

    while (*pp) {
      if (CryptAcquireContext(&hProv, NULL, NULL, *pp,
			      CRYPT_SILENT | CRYPT_VERIFYCONTEXT))
	goto found;
      pp++;
    }
    return -1;			/* No provider available */

  found:
    provider_open = 1;
    atexit(close_provider);
  }

  ok = CryptGenRandom(hProv, len, ptr);

  return ok ? 0 : -1;
}

#else

/* Need system-specific code here */

int get_random_bytes(void *ptr, int len)
{
  return -1;
}

#endif

void randomize(void)
{
  unsigned long key_array[32/sizeof(unsigned long)];

  key_array[0] = time(0);	/* Better than nothing on failure*/

  get_random_bytes(key_array, sizeof key_array);

  init_by_array(key_array, sizeof key_array/(sizeof key_array[0]));
}