Skip to content

Commit 2554c1b

Browse files
committed
Gather additional entropy from the environment
This based on code by Gregory Maxwell.
1 parent c2a262a commit 2554c1b

File tree

1 file changed

+184
-10
lines changed

1 file changed

+184
-10
lines changed

src/randomenv.cpp

+184-10
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@
33
// Distributed under the MIT software license, see the accompanying
44
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

6+
#if defined(HAVE_CONFIG_H)
7+
#include <config/bitcoin-config.h>
8+
#endif
9+
610
#include <randomenv.h>
711

12+
#include <clientversion.h>
813
#include <crypto/sha512.h>
914
#include <support/cleanse.h>
1015
#include <util/time.h> // for GetTime()
@@ -14,21 +19,34 @@
1419

1520
#include <algorithm>
1621
#include <chrono>
22+
#include <climits>
1723
#include <thread>
1824
#include <vector>
1925

2026
#include <stdint.h>
2127
#include <string.h>
2228
#ifndef WIN32
29+
#include <sys/types.h> // must go before a number of other headers
30+
#include <fcntl.h>
31+
#include <netinet/in.h>
32+
#include <sys/resource.h>
33+
#include <sys/socket.h>
34+
#include <sys/stat.h>
2335
#include <sys/time.h>
24-
#include <sys/types.h>
36+
#include <sys/utsname.h>
2537
#include <unistd.h>
2638
#endif
2739
#ifdef __MACH__
2840
#include <mach/clock.h>
2941
#include <mach/mach.h>
3042
#include <mach/mach_time.h>
3143
#endif
44+
#if HAVE_DECL_GETIFADDRS
45+
#include <ifaddrs.h>
46+
#endif
47+
48+
//! Necessary on some platforms
49+
extern char** environ;
3250

3351
namespace {
3452

@@ -85,6 +103,53 @@ CSHA512& operator<<(CSHA512& hasher, const T& data) {
85103
return hasher;
86104
}
87105

106+
#ifndef WIN32
107+
void AddSockaddr(CSHA512& hasher, const struct sockaddr *addr)
108+
{
109+
if (addr == nullptr) return;
110+
switch (addr->sa_family) {
111+
case AF_INET:
112+
hasher.Write((const unsigned char*)addr, sizeof(sockaddr_in));
113+
break;
114+
case AF_INET6:
115+
hasher.Write((const unsigned char*)addr, sizeof(sockaddr_in6));
116+
break;
117+
default:
118+
hasher.Write((const unsigned char*)&addr->sa_family, sizeof(addr->sa_family));
119+
}
120+
}
121+
122+
void AddFile(CSHA512& hasher, const char *path)
123+
{
124+
struct stat sb = {};
125+
int f = open(path, O_RDONLY);
126+
size_t total = 0;
127+
if (f != -1) {
128+
unsigned char fbuf[4096];
129+
int n;
130+
hasher.Write((const unsigned char*)&f, sizeof(f));
131+
if (fstat(f, &sb) == 0) hasher << sb;
132+
do {
133+
n = read(f, fbuf, sizeof(fbuf));
134+
if (n > 0) hasher.Write(fbuf, n);
135+
total += n;
136+
/* not bothering with EINTR handling. */
137+
} while (n == sizeof(fbuf) && total < 1048576); // Read only the first 1 Mbyte
138+
close(f);
139+
}
140+
}
141+
142+
void AddPath(CSHA512& hasher, const char *path)
143+
{
144+
struct stat sb = {};
145+
if (stat(path, &sb) == 0) {
146+
hasher.Write((const unsigned char*)path, strlen(path) + 1);
147+
hasher << sb;
148+
}
149+
}
150+
#endif
151+
152+
88153
} // namespace
89154

90155
void RandAddDynamicEnv(CSHA512& hasher)
@@ -99,48 +164,157 @@ void RandAddDynamicEnv(CSHA512& hasher)
99164
#else
100165
# ifndef __MACH__
101166
// On non-MacOS systems, use various clock_gettime() calls.
102-
struct timespec ts;
167+
struct timespec ts = {};
103168
# ifdef CLOCK_MONOTONIC
104169
clock_gettime(CLOCK_MONOTONIC, &ts);
105-
hasher << ts.tv_sec << ts.tv_nsec;
170+
hasher << ts;
106171
# endif
107172
# ifdef CLOCK_REALTIME
108173
clock_gettime(CLOCK_REALTIME, &ts);
109-
hasher << ts.tv_sec << ts.tv_nsec;
174+
hasher << ts;
110175
# endif
111176
# ifdef CLOCK_BOOTTIME
112177
clock_gettime(CLOCK_BOOTTIME, &ts);
113-
hasher << ts.tv_sec << ts.tv_nsec;
178+
hasher << ts;
114179
# endif
115180
# else
116181
// On MacOS use mach_absolute_time (number of CPU ticks since boot) as a replacement for CLOCK_MONOTONIC,
117182
// and clock_get_time for CALENDAR_CLOCK as a replacement for CLOCK_REALTIME.
118183
hasher << mach_absolute_time();
119184
// From https://gist.github.com/jbenet/1087739
120185
clock_serv_t cclock;
121-
mach_timespec_t mts;
186+
mach_timespec_t mts = {};
122187
if (host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock) == KERN_SUCCESS && clock_get_time(cclock, &mts) == KERN_SUCCESS) {
123-
hasher << mts.tv_sec << mts.tv_nsec;
188+
hasher << mts;
124189
mach_port_deallocate(mach_task_self(), cclock);
125190
}
126191
# endif
127192
// gettimeofday is available on all UNIX systems, but only has microsecond precision.
128-
struct timeval tv;
193+
struct timeval tv = {};
129194
gettimeofday(&tv, nullptr);
130-
hasher << tv.tv_sec << tv.tv_usec;
195+
hasher << tv;
131196
#endif
132197
// Probably redundant, but also use all the clocks C++11 provides:
133198
hasher << std::chrono::system_clock::now().time_since_epoch().count();
134199
hasher << std::chrono::steady_clock::now().time_since_epoch().count();
135200
hasher << std::chrono::high_resolution_clock::now().time_since_epoch().count();
201+
202+
#ifndef WIN32
203+
// Current resource usage.
204+
struct rusage usage = {};
205+
if (getrusage(RUSAGE_SELF, &usage) == 0) hasher << usage;
206+
#endif
207+
208+
#ifdef __linux__
209+
AddFile(hasher, "/proc/diskstats");
210+
AddFile(hasher, "/proc/vmstat");
211+
AddFile(hasher, "/proc/schedstat");
212+
AddFile(hasher, "/proc/zoneinfo");
213+
AddFile(hasher, "/proc/meminfo");
214+
AddFile(hasher, "/proc/softirqs");
215+
AddFile(hasher, "/proc/stat");
216+
AddFile(hasher, "/proc/self/schedstat");
217+
AddFile(hasher, "/proc/self/status");
218+
#endif
219+
220+
// Stack and heap location
221+
void* addr = malloc(4097);
222+
hasher << &addr << addr;
223+
free(addr);
136224
}
137225

138226
void RandAddStaticEnv(CSHA512& hasher)
139227
{
228+
// Some compile-time static properties
229+
hasher << (CHAR_MIN < 0) << sizeof(void*) << sizeof(long) << sizeof(int);
230+
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
231+
hasher << __GNUC__ << __GNUC_MINOR__ << __GNUC_PATCHLEVEL__;
232+
#endif
233+
#ifdef _MSC_VER
234+
hasher << _MSC_VER;
235+
#endif
236+
hasher << __cplusplus;
237+
#ifdef _XOPEN_VERSION
238+
hasher << _XOPEN_VERSION;
239+
#endif
240+
#ifdef __VERSION__
241+
const char* COMPILER_VERSION = __VERSION__;
242+
hasher.Write((const unsigned char*)COMPILER_VERSION, strlen(COMPILER_VERSION) + 1);
243+
#endif
244+
245+
// Bitcoin client version
246+
hasher << CLIENT_VERSION;
247+
248+
// Memory locations
249+
hasher << &hasher << &RandAddStaticEnv << &malloc << &errno << &environ;
250+
251+
// Hostname
252+
char hname[256];
253+
if (gethostname(hname, 256) == 0) {
254+
hasher.Write((const unsigned char*)hname, strnlen(hname, 256));
255+
}
256+
257+
#if HAVE_DECL_GETIFADDRS
258+
// Network interfaces
259+
struct ifaddrs *ifad = NULL;
260+
getifaddrs(&ifad);
261+
struct ifaddrs *ifit = ifad;
262+
while (ifit != NULL) {
263+
hasher.Write((const unsigned char*)&ifit, sizeof(ifit));
264+
hasher.Write((const unsigned char*)ifit->ifa_name, strlen(ifit->ifa_name) + 1);
265+
hasher.Write((const unsigned char*)&ifit->ifa_flags, sizeof(ifit->ifa_flags));
266+
AddSockaddr(hasher, ifit->ifa_addr);
267+
AddSockaddr(hasher, ifit->ifa_netmask);
268+
AddSockaddr(hasher, ifit->ifa_dstaddr);
269+
ifit = ifit->ifa_next;
270+
}
271+
freeifaddrs(ifad);
272+
#endif
273+
274+
#ifndef WIN32
275+
// UNIX kernel information
276+
struct utsname name;
277+
if (uname(&name) != -1) {
278+
hasher.Write((const unsigned char*)&name.sysname, strlen(name.sysname) + 1);
279+
hasher.Write((const unsigned char*)&name.nodename, strlen(name.nodename) + 1);
280+
hasher.Write((const unsigned char*)&name.release, strlen(name.release) + 1);
281+
hasher.Write((const unsigned char*)&name.version, strlen(name.version) + 1);
282+
hasher.Write((const unsigned char*)&name.machine, strlen(name.machine) + 1);
283+
}
284+
285+
/* Path and filesystem provided data */
286+
AddPath(hasher, "/");
287+
AddPath(hasher, ".");
288+
AddPath(hasher, "/tmp");
289+
AddPath(hasher, "/home");
290+
AddPath(hasher, "/proc");
291+
#ifdef __linux__
292+
AddFile(hasher, "/proc/cmdline");
293+
AddFile(hasher, "/proc/cpuinfo");
294+
AddFile(hasher, "/proc/version");
295+
#endif
296+
AddFile(hasher, "/etc/passwd");
297+
AddFile(hasher, "/etc/group");
298+
AddFile(hasher, "/etc/hosts");
299+
AddFile(hasher, "/etc/resolv.conf");
300+
AddFile(hasher, "/etc/timezone");
301+
AddFile(hasher, "/etc/localtime");
302+
303+
/* TODO: sysctl's for OSX to fetch information not available from /proc */
304+
#endif
305+
306+
// Env variables
307+
if (environ) {
308+
for (size_t i = 0; environ[i]; ++i) {
309+
hasher.Write((const unsigned char*)environ[i], strlen(environ[i]));
310+
}
311+
}
312+
313+
// Process, thread, user, session, group, ... ids.
140314
#ifdef WIN32
141315
hasher << GetCurrentProcessId() << GetCurrentThreadId();
142316
#else
143-
hasher << getpid();
317+
hasher << getpid() << getppid() << getsid(0) << getpgid(0) << getuid() << geteuid() << getgid() << getegid();
144318
#endif
145319
hasher << std::this_thread::get_id();
146320
}

0 commit comments

Comments
 (0)