|
|
1.1 misha 1: /** @file
2: Parser: random related functions.
3:
1.3 moko 4: Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com)
1.1 misha 5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
6: */
7:
8: // includes
9:
10: #include "pa_random.h"
11: #include "pa_exception.h"
12: #include "pa_threads.h"
13:
1.5 ! moko 14: volatile const char * IDENT_PA_RANDOM_C="$Id: pa_random.C,v 1.4 2012/06/20 20:54:26 moko Exp $" IDENT_PA_RANDOM_H;
1.3 moko 15:
1.5 ! moko 16: #ifdef _MSC_VER
1.4 moko 17: #include <windows.h>
1.1 misha 18:
19: class Random_provider {
20: HCRYPTPROV fhProv;
21:
22: void acquire() {
23: SYNCHRONIZED;
24:
25: if(fhProv)
26: return;
27:
28: if(!CryptAcquireContext(&fhProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
29: throw Exception(0,
30: 0,
31: "CryptAcquireContext failed");
32: }
33: void release() {
34: if(fhProv)
35: CryptReleaseContext(fhProv, 0);
36: }
37:
38: public:
39: Random_provider(): fhProv(0) {}
40: ~Random_provider() { release(); }
41: void generate(void *buffer, size_t size) {
42: acquire();
43:
44: if(!CryptGenRandom(fhProv, size, (BYTE*)buffer))
45: throw Exception(0,
46: 0,
47: "CryptGenRandom failed");
48: }
49: }
50: random_provider;
51:
52: #else
53:
54: /// from gen_uuid.c
55: static int get_random_fd(void)
56: {
57: struct timeval tv;
58: static int fd = -2;
59: int i;
60:
61: if (fd == -2) {
62: gettimeofday(&tv, 0);
63: fd = open("/dev/urandom", O_RDONLY);
64: if (fd == -1)
65: fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
66: srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
67: }
68: /* Crank the random number generator a few times */
69: gettimeofday(&tv, 0);
70: for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
71: rand();
72: return fd;
73: }
74:
75:
76: /*
77: * Generate a series of random bytes. Use /dev/urandom if possible,
78: * and if not, use srandom/random.
79: */
80: static void get_random_bytes(void *buf, int nbytes)
81: {
82: int i, fd = get_random_fd();
83: int lose_counter = 0;
84: char *cp = (char *) buf;
85:
86: if (fd >= 0) {
87: while (nbytes > 0) {
88: i = read(fd, cp, nbytes);
89: if (i <= 0) {
90: if (lose_counter++ > 16)
91: break;
92: continue;
93: }
94: nbytes -= i;
95: cp += i;
96: lose_counter = 0;
97: }
98: }
99:
100: /* XXX put something better here if no /dev/random! */
101: for (i = 0; i < nbytes; i++)
102: *cp++ = rand() & 0xFF;
103: return;
104: }
105:
106:
107: #endif
108:
109: void random(void *buffer, size_t size) {
1.5 ! moko 110: #ifdef _MSC_VER
1.1 misha 111: random_provider.generate(buffer, size);
112: #else
113: get_random_bytes(buffer, size);
114: #endif
115: }
116:
117: uuid get_uuid() {
118: // random
119: uuid uuid;
120: random(&uuid, sizeof(uuid));
121:
122: // http://www.opengroup.org/onlinepubs/9629399/apdxa.htm#tagtcjh_35
123: // ~
124: // version = DCE Security version, with embedded POSIX UIDs.
125: // variant = DCE
126: //
127: // DCE=Distributed Computing Environment
128: // http://www.opengroup.org/dce/
129: //
130: // they say this influences comparison&such,
131: // but could not figure out how, hence structure layout specified strictly
132: // anyhow, uuidgen on Win32 yield those values
133: //
134: // xxxxxxxx-xxxx-4xxx-{8,9,A,B}xxx-xxxxxxxxxxxx
135: uuid.clock_seq = (uuid.clock_seq & 0x3FFF) | 0x8000;
136: uuid.time_hi_and_version = (uuid.time_hi_and_version & 0x0FFF) | 0x4000;
137:
138: return uuid;
139: }
140: