MPHELL  4.0.0
mphell-entropy.c
Go to the documentation of this file.
1 /*
2  MPHELL-4.0
3  Author(s): The MPHELL team
4 
5  (C) Copyright 2015-2018 - Institut Fourier / Univ. Grenoble Alpes (France)
6 
7  This file is part of the MPHELL Library.
8  MPHELL is free software: you can redistribute it and/or modify
9  it under the terms of the GNU Lesser General Public License as published by
10  the Free Software Foundation, version 3 of the License.
11 
12  MPHELL is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public License
18  along with MPHELL. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
26 #include "mphell-entropy.h"
27 
32 typedef struct cpuid_struct {
33  unsigned int eax;
34  unsigned int ebx;
35  unsigned int ecx;
36  unsigned int edx;
37 } cpuid_t;
38 
46 void cpuid (cpuid_t *info, unsigned int leaf, unsigned int subleaf)
47 {
48 #if __x86_64__
49  asm volatile("cpuid"
50  : "=a" (info->eax), "=b" (info->ebx), "=c" (info->ecx), "=d" (info->edx)
51  : "a" (leaf), "c" (subleaf)
52  );
53 #endif
54 }
55 
63 {
64  static int intel_cpu= -1;
65 #if __x86_64__
66  cpuid_t info;
67 
68  if ( intel_cpu == -1 ) {
69  cpuid(&info, 0, 0);
70 
71  if (
72  memcmp((char *) &info.ebx, "Genu", 4) ||
73  memcmp((char *) &info.edx, "ineI", 4) ||
74  memcmp((char *) &info.ecx, "ntel", 4)
75  ) {
76  intel_cpu= 0;
77  } else {
78  intel_cpu= 1;
79  }
80  }
81 #endif
82  return intel_cpu;
83 }
84 
85 /* These are bits that are OR’d together */
86 
87 #define DRNG_NO_SUPPORT 0x0 /* For clarity */
88 #define DRNG_HAS_RDRAND 0x1
89 #define DRNG_HAS_RDSEED 0x2
90 
99 {
100  static int drng_features= -1;
101 #if __x86_64__
102  /* So we don't call cpuid multiple times for
103  * the same information */
104 
105  if ( drng_features == -1 ) {
106  drng_features= DRNG_NO_SUPPORT;
107 
108  if ( _is_intel_cpu() ) {
109  cpuid_t info;
110 
111  cpuid(&info, 1, 0);
112 
113  if ( (info.ecx & 0x40000000) == 0x40000000 ) {
114  drng_features|= DRNG_HAS_RDRAND;
115  }
116 
117  cpuid(&info, 7, 0);
118 
119  if ( (info.ebx & 0x40000) == 0x40000 ) {
120  drng_features|= DRNG_HAS_RDSEED;
121  }
122  }
123  }
124 #endif
125  return drng_features;
126 }
127 
128 #if MPHELL_USE_RDSEED == 1
129 
137 int rdseed16_step (uint16_t *seed)
138 {
139  unsigned char ok;
140 
141  asm volatile ("rdseed %0; setc %1"
142  : "=r" (*seed), "=qm" (ok));
143 
144  return (int) ok;
145 }
146 
156 int rdseed16_with_retry (uint16_t *seed, uint8_t nb_retry)
157 {
158  int success = 0;
159  uint8_t c = 0;
160  while(c < nb_retry)
161  {
162  success=rdseed16_step(seed);
163  c++;
164  if(success)
165  {
166  return success;
167  }
168  }
169  return success;
170 }
171 
172 #elif MPHELL_USE_RDSEED == 0
173 
182 int rdseed16_with_retry (uint16_t *seed, uint8_t nb_retry)
183 {
184  /* Intel instruction RDSEED is not available, nb: gcc >= 4.8 is required */
185  return 0;
186 }
187 
188 #endif
189 
197 void intel_rdseed(mphell_status ret, uint8_t *data, const uint16_t length)
198 {
199  if(get_drng_support() < 2)
200  {
202  char *text = "intel_rdrand : intel rdseed not available";
203  ret->info = malloc(strlen(text));
204  memcpy(ret->info, text, strlen(text));
205  memset(data, 0, length);
206  return;
207  }
208 
209  uint16_t nb = ceil((float)length / 2);
210  uint16_t tmp[nb];
211  uint16_t i = 0;
212 
213  for(i = 0; i < nb; i++)
214  {
215  if(rdseed16_with_retry(tmp + i, 10) != 1)
216  {
217  ret->flag = MPHELL_ERROR_RANDOM;
218  char *text = "intel_rdseed : unable to generate bytes";
219  mphell_error("RDSEED pb step\n");
220  ret->info = malloc(strlen(text));
221  memcpy(ret->info, text, strlen(text));
222  memset(data, 0, length);
223  return;
224  }
225  }
226  memcpy(data, tmp, length);
227 
228  ret->flag = MPHELL_SUCCESS;
229 }
230 
238 void dev_urandom(mphell_status ret, uint8_t *data, const uint16_t length)
239 {
240  FILE *fd = NULL;
241 
242  fd = fopen("/dev/urandom", "rb");
243 
244  if(fd == NULL)
245  {
247  char *text = "dev_urandom : file /dev/urandom not available";
248  ret->info = malloc(strlen(text));
249  memcpy(ret->info, text, strlen(text));
250  memset(data, 0, length);
251  return;
252  }
253 
254  if(fread(data, 1, length, fd) != length)
255  {
256  ret->flag = MPHELL_ERROR_RANDOM;
257  char *text = "dev_urandom : unable to generate bytes";
258  ret->info = malloc(strlen(text));
259  memcpy(ret->info, text, strlen(text));
260  memset(data, 0, length);
261  fclose(fd);
262  return;
263  }
264  fclose(fd);
265  ret->flag = MPHELL_SUCCESS;
266 }
267 
275 void dev_random(mphell_status ret, uint8_t *data, const uint16_t length)
276 {
277  FILE *fd = NULL;
278 
279  fd = fopen("/dev/random", "rb");
280 
281  if(fd == NULL)
282  {
284  char *text = "dev_random : file /dev/random not available";
285  ret->info = malloc(strlen(text));
286  memcpy(ret->info, text, strlen(text));
287  memset(data, 0, length);
288  return;
289  }
290 
291  if(fread(data, 1, length, fd) != length)
292  {
293  ret->flag = MPHELL_ERROR_RANDOM;
294  char *text = "dev_random : unable to generate bytes";
295  ret->info = malloc(strlen(text));
296  memcpy(ret->info, text, strlen(text));
297  memset(data, 0, length);
298  fclose(fd);
299  return;
300  }
301  fclose(fd);
302  ret->flag = MPHELL_SUCCESS;
303 }
304 
305 void
306 get_entropy_input(mphell_status ret, uint8_t *data,
307  const entropy_type entropy_src, const uint16_t length)
308 {
309  switch(entropy_src)
310  {
311  case INTEL :
312  intel_rdseed(ret, data, length);
313  break;
314 
315  case DEVURANDOM :
316  dev_urandom(ret, data, length);
317  break;
318 
319  case DEVRANDOM :
320  dev_random(ret, data, length);
321  break;
322 
323  default :
324  ret->flag = MPHELL_ERROR_RANDOM;
325  char *text = "get_entropy_input : Invalid entropy src";
326  ret->info = malloc(strlen(text));
327  memcpy(ret->info, text, strlen(text));
328  }
329 }
void mphell_error(char *expr)
Write in stderr, filename, line and expr, free mphell.
Definition: mphell-errors.c:45
void get_entropy_input(mphell_status ret, uint8_t *data, const entropy_type entropy_src, const uint16_t length)
Get length bit of entropy from the entropy source selected.
void cpuid(cpuid_t *info, unsigned int leaf, unsigned int subleaf)
Get cpuid informations, code comes from the "Intel® Digital Random Number Generator (DRNG) Software I...
void dev_random(mphell_status ret, uint8_t *data, const uint16_t length)
Get length bit of entropy from dev/random.
void dev_urandom(mphell_status ret, uint8_t *data, const uint16_t length)
Get length bit of entropy from /dev/urandom.
mphell_status_t mphell_status[1]
The status is a couple (flag, information)
Definition: mphell-errors.h:94
void intel_rdseed(mphell_status ret, uint8_t *data, const uint16_t length)
Get length bit of entropy from intel RDSEED instruction.
int _is_intel_cpu()
Define if the cpu is an intel cpu or not, code comes from the "Intel® Digital Random Number Generator...
enum entropy_source entropy_type
Define the entropy source.
Declaration of entropy functions.
To store registers, code comes from the "Intel® Digital Random Number Generator (DRNG) Software Imple...
int get_drng_support()
Test if the cpu support RDRAND and / or RDSEED, code comes from the "Intel® Digital Random Number Gen...