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.
18 #if defined ENABLE_RDRAND
22 #if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
23 #define HAS_X86_CPUID 1
25 static void do_cpuid(int regs
[], int h
)
28 #if defined __x86_64__
34 #if defined __x86_64__
39 : "=a"(regs
[0]), [ebx
] "=r"(regs
[1]), "=c"(regs
[2]), "=d"(regs
[3])
43 #elif defined _MSC_VER
45 #define HAS_X86_CPUID 1
46 #define do_cpuid __cpuid
54 static int has_rdrand()
56 // CPUID.01H:ECX.RDRAND[bit 30] == 1
59 return (regs
[2] & (1 << 30)) != 0;
64 /* get_rdrand_seed - GCC x86 and X64 */
66 #if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
70 static int get_rdrand_seed()
72 DEBUG_SEED("get_rdrand_seed");
75 __asm__
__volatile__("1: .byte 0x0F\n"
90 /* get_rdrand_seed - Visual Studio 2012 and above */
92 static int get_rdrand_seed()
94 DEBUG_SEED("get_rdrand_seed");
96 while (_rdrand32_step(&r
) == 0);
100 #elif defined _M_IX86
101 #define HAVE_RDRAND 1
103 /* get_rdrand_seed - Visual Studio 2010 and below - x86 only */
105 static int get_rdrand_seed()
107 DEBUG_SEED("get_rdrand_seed");
111 __asm _emit
0x0F __asm _emit
0xC7 __asm _emit
0xF0
120 #endif /* defined ENABLE_RDRAND */
123 /* has_dev_urandom */
125 #if defined (__APPLE__) || defined(__unix__) || defined(__linux__)
132 #include <sys/stat.h>
134 #define HAVE_DEV_RANDOM 1
136 static const char *dev_random_file
= "/dev/urandom";
138 static int has_dev_urandom()
141 if (stat(dev_random_file
, &buf
)) {
144 return ((buf
.st_mode
& S_IFCHR
) != 0);
148 /* get_dev_random_seed */
150 static int get_dev_random_seed()
152 DEBUG_SEED("get_dev_random_seed");
154 int fd
= open(dev_random_file
, O_RDONLY
);
156 fprintf(stderr
, "error opening %s: %s", dev_random_file
, strerror(errno
));
161 ssize_t nread
= read(fd
, &r
, sizeof(r
));
162 if (nread
!= sizeof(r
)) {
163 fprintf(stderr
, "error read %s: %s", dev_random_file
, strerror(errno
));
166 else if (nread
!= sizeof(r
)) {
167 fprintf(stderr
, "error short read %s", dev_random_file
);
177 /* get_cryptgenrandom_seed */
181 #define HAVE_CRYPTGENRANDOM 1
184 #pragma comment(lib, "advapi32.lib")
186 static int get_cryptgenrandom_seed()
188 DEBUG_SEED("get_cryptgenrandom_seed");
190 HCRYPTPROV hProvider
= 0;
193 if (!CryptAcquireContextW(&hProvider
, 0, 0, PROV_RSA_FULL
, CRYPT_VERIFYCONTEXT
| CRYPT_SILENT
)) {
194 fprintf(stderr
, "error CryptAcquireContextW");
198 if (!CryptGenRandom(hProvider
, sizeof(r
), (BYTE
*)&r
)) {
199 fprintf(stderr
, "error CryptGenRandom");
203 CryptReleaseContext(hProvider
, 0);
215 static int get_time_seed()
217 DEBUG_SEED("get_time_seed");
219 return (int)time(NULL
) * 433494437;
223 /* json_c_get_random_seed */
225 int json_c_get_random_seed()
228 if (has_rdrand()) return get_rdrand_seed();
231 if (has_dev_urandom()) return get_dev_random_seed();
233 #if HAVE_CRYPTGENRANDOM
234 return get_cryptgenrandom_seed();
236 return get_time_seed();