/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- connect_egd
- get_entropy
- put_entropy
- egd_seed
- get_bytes
- egd_bytes
- egd_cleanup
- egd_add
- egd_pseudorand
- egd_status
- RAND_egd_method
- RAND_egd
- RAND_egd_bytes
1 /*
2 * Copyright (c) 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 RCSID("$Id$");
39
40 #include <sys/types.h>
41 #ifdef HAVE_SYS_UN_H
42 #include <sys/un.h>
43 #endif
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50 #include <assert.h>
51
52 #include <rand.h>
53 #include <randi.h>
54
55 #include <roken.h>
56
57 static const char *egd_path = "/var/run/egd-pool";
58
59 #define MAX_EGD_DATA 255
60
61 static int
62 connect_egd(const char *path)
/* [<][>][^][v][top][bottom][index][help] */
63 {
64 struct sockaddr_un addr;
65 int fd;
66
67 memset(&addr, 0, sizeof(addr));
68
69 if (strlen(path) > sizeof(addr.sun_path))
70 return -1;
71
72 addr.sun_family = AF_UNIX;
73 strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
74
75 fd = socket(AF_UNIX, SOCK_STREAM, 0);
76 if (fd < 0)
77 return -1;
78
79 rk_cloexec(fd);
80
81 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
82 close(fd);
83 return -1;
84 }
85
86 return fd;
87 }
88
89 static int
90 get_entropy(int fd, void *data, size_t len)
/* [<][>][^][v][top][bottom][index][help] */
91 {
92 unsigned char msg[2];
93
94 assert(len <= MAX_EGD_DATA);
95
96 msg[0] = 0x02; /* read blocking data */
97 msg[1] = len; /* wanted length */
98
99 if (net_write(fd, msg, sizeof(msg)) != sizeof(msg))
100 return 0;
101
102 if (net_read(fd, data, len) != len)
103 return 0;
104
105 return 1;
106 }
107
108 static int
109 put_entropy(int fd, const void *data, size_t len)
/* [<][>][^][v][top][bottom][index][help] */
110 {
111 unsigned char msg[4];
112
113 assert (len <= MAX_EGD_DATA);
114
115 msg[0] = 0x03; /* write data */
116 msg[1] = 0; /* dummy */
117 msg[2] = 0; /* entropy */
118 msg[3] = len; /* length */
119
120 if (net_write(fd, msg, sizeof(msg)) != sizeof(msg))
121 return 0;
122 if (net_write(fd, data, len) != len)
123 return 0;
124
125 return 1;
126 }
127
128 /*
129 *
130 */
131
132 static void
133 egd_seed(const void *indata, int size)
/* [<][>][^][v][top][bottom][index][help] */
134 {
135 size_t len;
136 int fd, ret = 1;
137
138 fd = connect_egd(egd_path);
139 if (fd < 0)
140 return;
141
142 while(size) {
143 len = size;
144 if (len > MAX_EGD_DATA)
145 len = MAX_EGD_DATA;
146 ret = put_entropy(fd, indata, len);
147 if (ret != 1)
148 break;
149 indata = ((unsigned char *)indata) + len;
150 size -= len;
151 }
152 close(fd);
153 }
154
155 static int
156 get_bytes(const char *path, unsigned char *outdata, int size)
/* [<][>][^][v][top][bottom][index][help] */
157 {
158 size_t len;
159 int fd, ret = 1;
160
161 if (path == NULL)
162 path = egd_path;
163
164 fd = connect_egd(path);
165 if (fd < 0)
166 return 0;
167
168 while(size) {
169 len = size;
170 if (len > MAX_EGD_DATA)
171 len = MAX_EGD_DATA;
172 ret = get_entropy(fd, outdata, len);
173 if (ret != 1)
174 break;
175 outdata += len;
176 size -= len;
177 }
178 close(fd);
179
180 return ret;
181 }
182
183 static int
184 egd_bytes(unsigned char *outdata, int size)
/* [<][>][^][v][top][bottom][index][help] */
185 {
186 return get_bytes(NULL, outdata, size);
187 }
188
189 static void
190 egd_cleanup(void)
/* [<][>][^][v][top][bottom][index][help] */
191 {
192 }
193
194 static void
195 egd_add(const void *indata, int size, double entropi)
/* [<][>][^][v][top][bottom][index][help] */
196 {
197 egd_seed(indata, size);
198 }
199
200 static int
201 egd_pseudorand(unsigned char *outdata, int size)
/* [<][>][^][v][top][bottom][index][help] */
202 {
203 return get_bytes(NULL, outdata, size);
204 }
205
206 static int
207 egd_status(void)
/* [<][>][^][v][top][bottom][index][help] */
208 {
209 int fd;
210 fd = connect_egd(egd_path);
211 if (fd < 0)
212 return 0;
213 close(fd);
214 return 1;
215 }
216
217 const RAND_METHOD hc_rand_egd_method = {
218 egd_seed,
219 egd_bytes,
220 egd_cleanup,
221 egd_add,
222 egd_pseudorand,
223 egd_status
224 };
225
226 const RAND_METHOD *
227 RAND_egd_method(void)
/* [<][>][^][v][top][bottom][index][help] */
228 {
229 return &hc_rand_egd_method;
230 }
231
232
233 int
234 RAND_egd(const char *filename)
/* [<][>][^][v][top][bottom][index][help] */
235 {
236 return RAND_egd_bytes(filename, 128);
237 }
238
239 int
240 RAND_egd_bytes(const char *filename, int size)
/* [<][>][^][v][top][bottom][index][help] */
241 {
242 void *data;
243 int ret;
244
245 if (size <= 0)
246 return 0;
247
248 data = malloc(size);
249 if (data == NULL)
250 return 0;
251
252 ret = get_bytes(filename, data, size);
253 if (ret != 1) {
254 free(data);
255 return ret;
256 }
257
258 RAND_seed(data, size);
259
260 memset(data, 0, size);
261 free(data);
262
263 return 1;
264 }