f15507a21d5dd23a303f082be90a8a252c98a67f
[strongswan.git] / Source / charon / utils / randomizer.c
1 /**
2 * @file randomizer.c
3 *
4 * @brief Class used to get random and pseudo random values
5 *
6 */
7
8 /*
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28
29 #include "randomizer.h"
30
31 #include <utils/allocator.h>
32
33 /**
34 * Default random device used when no device is given.
35 */
36 #define DEFAULT_RANDOM_DEVICE "/dev/random"
37
38 /**
39 * Pseudo random device used when no device is given.
40 */
41 #define DEFAULT_PSEUDO_RANDOM_DEVICE "/dev/urandom"
42
43 typedef struct private_randomizer_t private_randomizer_t;
44
45 struct private_randomizer_t {
46 /**
47 * public interface
48 */
49 randomizer_t public;
50
51 /**
52 * @brief Reads a specific number of bytes from random or pseudo random device
53 *
54 * @param pseudo_random TRUE, if pseudo random bytes should be read,
55 * FALSE for true random bytes
56 * @param bytes Number of bytes to read
57 * @param[out] buffer Pointer to buffer where to write the data in.
58 * Size of buffer has to be at least bytes.
59 * @return
60 * - SUCCESS
61 * - FAILED
62 */
63 status_t (*get_bytes_from_device) (private_randomizer_t *this,bool pseudo_random, size_t bytes, u_int8_t *buffer);
64
65 /**
66 * Random device name
67 */
68 char *random_dev_name;
69
70 /**
71 * Pseudo random device name
72 */
73 char *pseudo_random_dev_name;
74 };
75
76
77 /**
78 * Implements private_randomizer_t's get_bytes_from_device function.
79 * See #private_randomizer_t.get_bytes_from_device for description.
80 */
81 static status_t get_bytes_from_device(private_randomizer_t *this,bool pseudo_random, size_t bytes, u_int8_t *buffer)
82 {
83 /* number of bytes already done */
84 size_t ndone;
85 /* device file descriptor */
86 int device;
87 size_t got;
88 char * device_name;
89
90 device_name = (pseudo_random) ? this->pseudo_random_dev_name : this->random_dev_name;
91
92 // open device
93 device = open(device_name, 0);
94 if (device < 0) {
95 return FAILED;
96 }
97 ndone = 0;
98
99 // read until nbytes are read
100 while (ndone < bytes)
101 {
102 got = read(device, buffer + ndone, bytes - ndone);
103 if (got < 0) {
104 return FAILED;
105 }
106 if (got == 0) {
107 return FAILED;
108 }
109 ndone += got;
110 }
111 // close device
112 close(device);
113 return SUCCESS;
114 }
115
116 /**
117 * Implements randomizer_t's get_random_bytes function.
118 * See #randomizer_t.get_random_bytes for description.
119 */
120 static status_t get_random_bytes(private_randomizer_t *this,size_t bytes, u_int8_t *buffer)
121 {
122 return (this->get_bytes_from_device(this, FALSE, bytes, buffer));
123 }
124 /**
125 * Implements randomizer_t's allocate_random_bytes function.
126 * See #randomizer_t.allocate_random_bytes for description.
127 */
128 static status_t allocate_random_bytes(private_randomizer_t *this, size_t bytes, chunk_t *chunk)
129 {
130 chunk->len = bytes;
131 chunk->ptr = allocator_alloc(bytes);
132 if (chunk->ptr == NULL)
133 {
134 return OUT_OF_RES;
135 }
136 return (this->get_bytes_from_device(this, FALSE, bytes, chunk->ptr));
137 }
138
139 /**
140 * Implements randomizer_t's get_pseudo_random_bytes function.
141 * See #randomizer_t.get_pseudo_random_bytes for description.
142 */
143 static status_t get_pseudo_random_bytes(private_randomizer_t *this,size_t bytes, u_int8_t *buffer)
144 {
145 return (this->get_bytes_from_device(this, TRUE, bytes, buffer));
146 }
147
148
149 /**
150 * Implements randomizer_t's allocate_random_bytes function.
151 * See #randomizer_t.allocate_random_bytes for description.
152 */
153 static status_t allocate_pseudo_random_bytes(private_randomizer_t *this, size_t bytes, chunk_t *chunk)
154 {
155 chunk->len = bytes;
156 chunk->ptr = allocator_alloc(bytes);
157 if (chunk->ptr == NULL)
158 {
159 return OUT_OF_RES;
160 }
161 return (this->get_bytes_from_device(this, TRUE, bytes, chunk->ptr));
162 }
163
164
165 /**
166 * Implements randomizer_t's destroy function.
167 * See #randomizer_t.destroy for description.
168 */
169 static status_t destroy(private_randomizer_t *this)
170 {
171 allocator_free(this->random_dev_name);
172 allocator_free(this->pseudo_random_dev_name);
173 allocator_free(this);
174
175 return SUCCESS;
176 }
177
178 /*
179 * Described in header.
180 */
181 randomizer_t *randomizer_create(void)
182 {
183 return randomizer_create_on_devices(DEFAULT_RANDOM_DEVICE,DEFAULT_PSEUDO_RANDOM_DEVICE);
184 }
185
186 /*
187 * Described in header.
188 */
189 randomizer_t *randomizer_create_on_devices(char * random_dev_name,char * prandom_dev_name)
190 {
191 private_randomizer_t *this = allocator_alloc_thing(private_randomizer_t);
192 if (this == NULL)
193 {
194 return NULL;
195 }
196 if ((random_dev_name == NULL) || (prandom_dev_name == NULL))
197 {
198 return NULL;
199 }
200
201 /* public functions */
202 this->public.get_random_bytes = (status_t (*) (randomizer_t *,size_t, u_int8_t *)) get_random_bytes;
203 this->public.allocate_random_bytes = (status_t (*) (randomizer_t *,size_t, chunk_t *)) allocate_random_bytes;
204 this->public.get_pseudo_random_bytes = (status_t (*) (randomizer_t *,size_t, u_int8_t *)) get_pseudo_random_bytes;
205 this->public.allocate_pseudo_random_bytes = (status_t (*) (randomizer_t *,size_t, chunk_t *)) allocate_pseudo_random_bytes;
206 this->public.destroy = (status_t (*) (randomizer_t *))destroy;
207
208 /* private functions */
209 this->get_bytes_from_device = get_bytes_from_device;
210
211 /* private fields */
212 this->random_dev_name = allocator_alloc(strlen(random_dev_name) + 1);
213 if (this->random_dev_name == NULL)
214 {
215 allocator_free(this);
216 return NULL;
217 }
218 strcpy(this->random_dev_name,random_dev_name);
219
220 this->pseudo_random_dev_name = allocator_alloc(strlen(prandom_dev_name) + 1);
221 if (this->pseudo_random_dev_name == NULL)
222 {
223 allocator_free(this->random_dev_name);
224 allocator_free(this);
225 return NULL;
226 }
227 strcpy(this->pseudo_random_dev_name,prandom_dev_name);
228
229 return &(this->public);
230 }