1 | /* |
2 | * Copyright 2008-2018 Aerospike, Inc. |
3 | * |
4 | * Portions may be licensed to Aerospike, Inc. under one or more contributor |
5 | * license agreements. |
6 | * |
7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
8 | * use this file except in compliance with the License. You may obtain a copy of |
9 | * the License at http://www.apache.org/licenses/LICENSE-2.0 |
10 | * |
11 | * Unless required by applicable law or agreed to in writing, software |
12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
14 | * License for the specific language governing permissions and limitations under |
15 | * the License. |
16 | */ |
17 | #include <citrusleaf/cf_random.h> |
18 | #include <fcntl.h> |
19 | #include <openssl/rand.h> |
20 | #include <pthread.h> |
21 | #include <stdio.h> |
22 | #include <string.h> |
23 | |
24 | #if !defined ENHANCED_ALLOC |
25 | #include <aerospike/as_log_macros.h> |
26 | #endif |
27 | |
28 | #define SEED_SZ 64 |
29 | static uint8_t rand_buf[1024 * 8]; |
30 | static uint32_t rand_buf_off = 0; |
31 | static int seeded = 0; |
32 | static pthread_mutex_t rand_buf_lock = PTHREAD_MUTEX_INITIALIZER; |
33 | |
34 | #if defined(__linux__) || defined(__FreeBSD__) |
35 | #include <unistd.h> |
36 | |
37 | int |
38 | cf_rand_reload() |
39 | { |
40 | if (seeded == 0) { |
41 | int rfd = open("/dev/urandom" , O_RDONLY); |
42 | int rsz = (int)read(rfd, rand_buf, SEED_SZ); |
43 | if (rsz < SEED_SZ) { |
44 | #if !defined ENHANCED_ALLOC |
45 | as_log_error("Failed to seed random number generator" ); |
46 | #endif |
47 | return(-1); |
48 | } |
49 | close(rfd); |
50 | RAND_seed(rand_buf, rsz); |
51 | seeded = 1; |
52 | } |
53 | |
54 | if (1 != RAND_bytes(rand_buf, sizeof(rand_buf))) { |
55 | #if !defined ENHANCED_ALLOC |
56 | as_log_error("Failed to reload random buffer" ); |
57 | #endif |
58 | return(-1); |
59 | } |
60 | |
61 | rand_buf_off = sizeof(rand_buf); |
62 | return 0; |
63 | } |
64 | |
65 | #elif defined (__APPLE__) |
66 | |
67 | int |
68 | cf_rand_reload() |
69 | { |
70 | if (seeded == 0) { |
71 | arc4random_stir(); |
72 | seeded = 1; |
73 | } |
74 | |
75 | arc4random_buf(rand_buf, sizeof(rand_buf)); |
76 | rand_buf_off = sizeof(rand_buf); |
77 | return 0; |
78 | } |
79 | |
80 | #elif defined (_MSC_VER) |
81 | |
82 | #define WIN32_LEAN_AND_MEAN |
83 | #include <windows.h> |
84 | |
85 | int |
86 | cf_rand_reload() |
87 | { |
88 | // Acquire/Release context every buffer reload. |
89 | HCRYPTPROV hProvider; |
90 | |
91 | if (!CryptAcquireContext(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { |
92 | #if !defined ENHANCED_ALLOC |
93 | as_log_error("Failed to seed random number generator" ); |
94 | #endif |
95 | return -1; |
96 | } |
97 | |
98 | if (!CryptGenRandom(hProvider, sizeof(rand_buf), rand_buf)) { |
99 | #if !defined ENHANCED_ALLOC |
100 | as_log_error("Failed to reload random buffer" ); |
101 | #endif |
102 | CryptReleaseContext(hProvider, 0); |
103 | return -1; |
104 | } |
105 | |
106 | CryptReleaseContext(hProvider, 0); |
107 | rand_buf_off = sizeof(rand_buf); |
108 | return 0; |
109 | } |
110 | #endif |
111 | |
112 | int |
113 | cf_get_rand_buf(uint8_t *buf, int len) |
114 | { |
115 | if ((uint32_t)len >= sizeof(rand_buf)) return(-1); |
116 | |
117 | pthread_mutex_lock(&rand_buf_lock); |
118 | |
119 | if (rand_buf_off < (uint32_t)len ) { |
120 | if (-1 == cf_rand_reload()) { |
121 | pthread_mutex_unlock(&rand_buf_lock); |
122 | return(-1); |
123 | } |
124 | } |
125 | |
126 | rand_buf_off -= len; |
127 | memcpy(buf, &rand_buf[rand_buf_off] ,len); |
128 | |
129 | pthread_mutex_unlock(&rand_buf_lock); |
130 | |
131 | return(0); |
132 | } |
133 | |
134 | uint64_t |
135 | cf_get_rand64() |
136 | { |
137 | pthread_mutex_lock(&rand_buf_lock); |
138 | if (rand_buf_off < sizeof(uint64_t) ) { |
139 | if (-1 == cf_rand_reload()) { |
140 | pthread_mutex_unlock(&rand_buf_lock); |
141 | return(0); |
142 | } |
143 | } |
144 | rand_buf_off -= sizeof(uint64_t); |
145 | uint64_t r = *(uint64_t *) (&rand_buf[rand_buf_off]); |
146 | pthread_mutex_unlock(&rand_buf_lock); |
147 | return(r); |
148 | } |
149 | |
150 | uint32_t |
151 | cf_get_rand32() |
152 | { |
153 | pthread_mutex_lock(&rand_buf_lock); |
154 | if (rand_buf_off < sizeof(uint64_t) ) { |
155 | if (-1 == cf_rand_reload()) { |
156 | pthread_mutex_unlock(&rand_buf_lock); |
157 | return(0); |
158 | } |
159 | } |
160 | |
161 | rand_buf_off -= sizeof(uint64_t); |
162 | uint64_t r = *(uint64_t *) (&rand_buf[rand_buf_off]); |
163 | pthread_mutex_unlock(&rand_buf_lock); |
164 | return((uint32_t)r); |
165 | } |
166 | |