Skip to content

Commit c2a262a

Browse files
committed
Seed randomness with process id / thread id / various clocks
This sort of data is also used by OpenSSL.
1 parent 723c796 commit c2a262a

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

src/randomenv.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,22 @@
1313
#endif
1414

1515
#include <algorithm>
16+
#include <chrono>
17+
#include <thread>
1618
#include <vector>
1719

1820
#include <stdint.h>
21+
#include <string.h>
22+
#ifndef WIN32
23+
#include <sys/time.h>
24+
#include <sys/types.h>
25+
#include <unistd.h>
26+
#endif
27+
#ifdef __MACH__
28+
#include <mach/clock.h>
29+
#include <mach/mach.h>
30+
#include <mach/mach_time.h>
31+
#endif
1932

2033
namespace {
2134

@@ -57,13 +70,77 @@ void RandAddSeedPerfmon(CSHA512& hasher)
5770
#endif
5871
}
5972

73+
/** Helper to easily feed data into a CSHA512.
74+
*
75+
* Note that this does not serialize the passed object (like stream.h's << operators do).
76+
* Its raw memory representation is used directly.
77+
*/
78+
template<typename T>
79+
CSHA512& operator<<(CSHA512& hasher, const T& data) {
80+
static_assert(!std::is_same<typename std::decay<T>::type, char*>::value, "Calling operator<<(CSHA512, char*) is probably not what you want");
81+
static_assert(!std::is_same<typename std::decay<T>::type, unsigned char*>::value, "Calling operator<<(CSHA512, unsigned char*) is probably not what you want");
82+
static_assert(!std::is_same<typename std::decay<T>::type, const char*>::value, "Calling operator<<(CSHA512, const char*) is probably not what you want");
83+
static_assert(!std::is_same<typename std::decay<T>::type, const unsigned char*>::value, "Calling operator<<(CSHA512, const unsigned char*) is probably not what you want");
84+
hasher.Write((const unsigned char*)&data, sizeof(data));
85+
return hasher;
86+
}
87+
6088
} // namespace
6189

6290
void RandAddDynamicEnv(CSHA512& hasher)
6391
{
6492
RandAddSeedPerfmon(hasher);
93+
94+
// Various clocks
95+
#ifdef WIN32
96+
FILETIME ftime;
97+
GetSystemTimeAsFileTime(&ftime);
98+
hasher << ftime;
99+
#else
100+
# ifndef __MACH__
101+
// On non-MacOS systems, use various clock_gettime() calls.
102+
struct timespec ts;
103+
# ifdef CLOCK_MONOTONIC
104+
clock_gettime(CLOCK_MONOTONIC, &ts);
105+
hasher << ts.tv_sec << ts.tv_nsec;
106+
# endif
107+
# ifdef CLOCK_REALTIME
108+
clock_gettime(CLOCK_REALTIME, &ts);
109+
hasher << ts.tv_sec << ts.tv_nsec;
110+
# endif
111+
# ifdef CLOCK_BOOTTIME
112+
clock_gettime(CLOCK_BOOTTIME, &ts);
113+
hasher << ts.tv_sec << ts.tv_nsec;
114+
# endif
115+
# else
116+
// On MacOS use mach_absolute_time (number of CPU ticks since boot) as a replacement for CLOCK_MONOTONIC,
117+
// and clock_get_time for CALENDAR_CLOCK as a replacement for CLOCK_REALTIME.
118+
hasher << mach_absolute_time();
119+
// From https://gist.github.com/jbenet/1087739
120+
clock_serv_t cclock;
121+
mach_timespec_t mts;
122+
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;
124+
mach_port_deallocate(mach_task_self(), cclock);
125+
}
126+
# endif
127+
// gettimeofday is available on all UNIX systems, but only has microsecond precision.
128+
struct timeval tv;
129+
gettimeofday(&tv, nullptr);
130+
hasher << tv.tv_sec << tv.tv_usec;
131+
#endif
132+
// Probably redundant, but also use all the clocks C++11 provides:
133+
hasher << std::chrono::system_clock::now().time_since_epoch().count();
134+
hasher << std::chrono::steady_clock::now().time_since_epoch().count();
135+
hasher << std::chrono::high_resolution_clock::now().time_since_epoch().count();
65136
}
66137

67138
void RandAddStaticEnv(CSHA512& hasher)
68139
{
140+
#ifdef WIN32
141+
hasher << GetCurrentProcessId() << GetCurrentThreadId();
142+
#else
143+
hasher << getpid();
144+
#endif
145+
hasher << std::this_thread::get_id();
69146
}

0 commit comments

Comments
 (0)