1 /**
2 * @file rand.c Random generator
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6 #include <stdlib.h>
7 #ifdef USE_OPENSSL
8 #include <openssl/rand.h>
9 #include <openssl/err.h>
10 #endif
11 #include <re_types.h>
12 #include <re_mbuf.h>
13 #include <re_list.h>
14 #include <re_tmr.h>
15 #include <re_sys.h>
16
17
18 #define DEBUG_MODULE "rand"
19 #define DEBUG_LEVEL 5
20 #include <re_dbg.h>
21
22
23 #ifndef RELEASE
24 #define RAND_DEBUG 1 /**< Enable random debugging */
25 #endif
26
27 static const char alphanum[] =
28 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
29 "abcdefghijklmnopqrstuvwxyz"
30 "0123456789";
31
32 #if RAND_DEBUG
33 static bool inited = false;
34 /** Check random state */
35 #define RAND_CHECK \
36 if (!inited) { \
37 DEBUG_WARNING("%s: random not inited\n", __REFUNC__); \
38 }
39 #else
40 #define RAND_CHECK if (0) {}
41 #endif
42
43
44 /**
45 * Initialise random number generator
46 */
rand_init(void)47 void rand_init(void)
48 {
49 #ifndef USE_OPENSSL
50 srand((uint32_t) tmr_jiffies());
51 #endif
52
53 #if RAND_DEBUG
54 inited = true;
55 #endif
56 }
57
58
59 /**
60 * Generate an unsigned 16-bit random value
61 *
62 * @return 16-bit random value
63 */
rand_u16(void)64 uint16_t rand_u16(void)
65 {
66 RAND_CHECK;
67
68 /* Use higher-order bits (see man 3 rand) */
69 return rand_u32() >> 16;
70 }
71
72
73 /**
74 * Generate an unsigned 32-bit random value
75 *
76 * @return 32-bit random value
77 */
rand_u32(void)78 uint32_t rand_u32(void)
79 {
80 uint32_t v;
81
82 RAND_CHECK;
83
84 #ifdef USE_OPENSSL
85 v = 0;
86 if (RAND_bytes((unsigned char *)&v, sizeof(v)) <= 0) {
87 DEBUG_WARNING("RAND_bytes() error: %i\n",
88 ERR_GET_REASON(ERR_get_error()));
89 ERR_clear_error();
90 }
91 #elif defined(HAVE_ARC4RANDOM)
92 v = arc4random();
93 #elif defined(WIN32)
94 v = (rand() << 16) + rand(); /* note: 16-bit rand */
95 #else
96 v = rand();
97 #endif
98
99 return v;
100 }
101
102
103 /**
104 * Generate an unsigned 64-bit random value
105 *
106 * @return 64-bit random value
107 */
rand_u64(void)108 uint64_t rand_u64(void)
109 {
110 RAND_CHECK;
111
112 return (uint64_t)rand_u32()<<32 | rand_u32();
113 }
114
115
116 /**
117 * Generate a random printable character
118 *
119 * @return Random printable character
120 */
rand_char(void)121 char rand_char(void)
122 {
123 char s[2];
124
125 RAND_CHECK;
126
127 rand_str(s, sizeof(s));
128
129 return s[0];
130 }
131
132
133 /**
134 * Generate a string of random characters
135 *
136 * @param str Pointer to string
137 * @param size Size of string
138 */
rand_str(char * str,size_t size)139 void rand_str(char *str, size_t size)
140 {
141 size_t i;
142
143 if (!str || !size)
144 return;
145
146 RAND_CHECK;
147
148 --size;
149
150 rand_bytes((uint8_t *)str, size);
151
152 for (i=0; i<size; i++)
153 str[i] = alphanum[((uint8_t)str[i]) % (sizeof(alphanum)-1)];
154
155 str[size] = '\0';
156 }
157
158
159 /**
160 * Generate a set of random bytes
161 *
162 * @param p Pointer to buffer
163 * @param size Size of buffer
164 */
rand_bytes(uint8_t * p,size_t size)165 void rand_bytes(uint8_t *p, size_t size)
166 {
167 #ifdef USE_OPENSSL
168 if (RAND_bytes(p, (int)size) <= 0) {
169 DEBUG_WARNING("RAND_bytes() error: %i\n",
170 ERR_GET_REASON(ERR_get_error()));
171 ERR_clear_error();
172 }
173 #elif defined (HAVE_ARC4RANDOM)
174 arc4random_buf(p, size);
175 #else
176 while (size--) {
177 p[size] = rand_u32();
178 }
179 #endif
180 }
181