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