4 * Copyright (c) 2013 Metaparadigm Pte. Ltd.
5 * Michael Clark <michael@metaparadigm.com>
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the MIT license. See COPYING for details.
12 #include "strerror_override.h"
15 #include "random_seed.h"
20 #if defined ENABLE_RDRAND
24 #if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
25 #define HAS_X86_CPUID 1
27 static void do_cpuid(int regs[], int h)
30 #if defined __x86_64__
36 #if defined __x86_64__
41 : "=a"(regs[0]), [ebx] "=r"(regs[1]), "=c"(regs[2]), "=d"(regs[3])
45 #elif defined _MSC_VER
47 #define HAS_X86_CPUID 1
48 #define do_cpuid __cpuid
56 static int has_rdrand()
58 // CPUID.01H:ECX.RDRAND[bit 30] == 1
61 return (regs[2] & (1 << 30)) != 0;
66 /* get_rdrand_seed - GCC x86 and X64 */
68 #if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
72 static int get_rdrand_seed()
74 DEBUG_SEED("get_rdrand_seed");
77 __asm__ __volatile__("1: .byte 0x0F\n"
92 /* get_rdrand_seed - Visual Studio 2012 and above */
94 static int get_rdrand_seed()
96 DEBUG_SEED("get_rdrand_seed");
98 while (_rdrand32_step(&r) == 0);
102 #elif defined _M_IX86
103 #define HAVE_RDRAND 1
105 /* get_rdrand_seed - Visual Studio 2010 and below - x86 only */
107 static int get_rdrand_seed()
109 DEBUG_SEED("get_rdrand_seed");
113 __asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0
122 #endif /* defined ENABLE_RDRAND */
125 /* has_dev_urandom */
127 #if defined (__APPLE__) || defined(__unix__) || defined(__linux__)
133 #include <sys/stat.h>
135 #define HAVE_DEV_RANDOM 1
137 static const char *dev_random_file = "/dev/urandom";
139 static int has_dev_urandom()
142 if (stat(dev_random_file, &buf)) {
145 return ((buf.st_mode & S_IFCHR) != 0);
149 /* get_dev_random_seed */
151 static int get_dev_random_seed()
153 DEBUG_SEED("get_dev_random_seed");
155 int fd = open(dev_random_file, O_RDONLY);
157 fprintf(stderr, "error opening %s: %s", dev_random_file, strerror(errno));
162 ssize_t nread = read(fd, &r, sizeof(r));
163 if (nread != sizeof(r)) {
164 fprintf(stderr, "error short read %s: %s", dev_random_file, strerror(errno));
175 /* get_cryptgenrandom_seed */
179 #define HAVE_CRYPTGENRANDOM 1
182 #include <wincrypt.h>
184 #pragma comment(lib, "advapi32.lib")
187 static int get_cryptgenrandom_seed()
189 HCRYPTPROV hProvider = 0;
192 DEBUG_SEED("get_cryptgenrandom_seed");
194 if (!CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
195 fprintf(stderr, "error CryptAcquireContextW");
199 if (!CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r)) {
200 fprintf(stderr, "error CryptGenRandom");
204 CryptReleaseContext(hProvider, 0);
216 static int get_time_seed()
218 DEBUG_SEED("get_time_seed");
220 return (int)time(NULL) * 433494437;
224 /* json_c_get_random_seed */
226 int json_c_get_random_seed()
229 if (has_rdrand()) return get_rdrand_seed();
232 if (has_dev_urandom()) return get_dev_random_seed();
234 #if HAVE_CRYPTGENRANDOM
235 return get_cryptgenrandom_seed();
237 return get_time_seed();