1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #include "secrng.h"
6 
7 #ifdef XP_WIN
8 #include <windows.h>
9 #include <time.h>
10 
11 static BOOL
CurrentClockTickTime(LPDWORD lpdwHigh,LPDWORD lpdwLow)12 CurrentClockTickTime(LPDWORD lpdwHigh, LPDWORD lpdwLow)
13 {
14     LARGE_INTEGER liCount;
15 
16     if (!QueryPerformanceCounter(&liCount))
17         return FALSE;
18 
19     *lpdwHigh = liCount.u.HighPart;
20     *lpdwLow = liCount.u.LowPart;
21     return TRUE;
22 }
23 
24 size_t
RNG_GetNoise(void * buf,size_t maxbuf)25 RNG_GetNoise(void *buf, size_t maxbuf)
26 {
27     DWORD dwHigh, dwLow, dwVal;
28     int n = 0;
29     int nBytes;
30     time_t sTime;
31 
32     if (maxbuf <= 0)
33         return 0;
34 
35     CurrentClockTickTime(&dwHigh, &dwLow);
36 
37     // get the maximally changing bits first
38     nBytes = sizeof(dwLow) > maxbuf ? maxbuf : sizeof(dwLow);
39     memcpy((char *)buf, &dwLow, nBytes);
40     n += nBytes;
41     maxbuf -= nBytes;
42 
43     if (maxbuf <= 0)
44         return n;
45 
46     nBytes = sizeof(dwHigh) > maxbuf ? maxbuf : sizeof(dwHigh);
47     memcpy(((char *)buf) + n, &dwHigh, nBytes);
48     n += nBytes;
49     maxbuf -= nBytes;
50 
51     if (maxbuf <= 0)
52         return n;
53 
54     // get the number of milliseconds that have elapsed since Windows started
55     dwVal = GetTickCount();
56 
57     nBytes = sizeof(dwVal) > maxbuf ? maxbuf : sizeof(dwVal);
58     memcpy(((char *)buf) + n, &dwVal, nBytes);
59     n += nBytes;
60     maxbuf -= nBytes;
61 
62     if (maxbuf <= 0)
63         return n;
64 
65     // get the time in seconds since midnight Jan 1, 1970
66     time(&sTime);
67     nBytes = sizeof(sTime) > maxbuf ? maxbuf : sizeof(sTime);
68     memcpy(((char *)buf) + n, &sTime, nBytes);
69     n += nBytes;
70 
71     return n;
72 }
73 
74 void
RNG_SystemInfoForRNG(void)75 RNG_SystemInfoForRNG(void)
76 {
77     DWORD dwVal;
78     char buffer[256];
79     int nBytes;
80     MEMORYSTATUS sMem;
81     HANDLE hVal;
82     DWORD dwSerialNum;
83     DWORD dwComponentLen;
84     DWORD dwSysFlags;
85     char volName[128];
86     DWORD dwSectors, dwBytes, dwFreeClusters, dwNumClusters;
87 
88     nBytes = RNG_GetNoise(buffer, 20); // get up to 20 bytes
89     RNG_RandomUpdate(buffer, nBytes);
90 
91     sMem.dwLength = sizeof(sMem);
92     GlobalMemoryStatus(&sMem); // assorted memory stats
93     RNG_RandomUpdate(&sMem, sizeof(sMem));
94 
95     dwVal = GetLogicalDrives();
96     RNG_RandomUpdate(&dwVal, sizeof(dwVal)); // bitfields in bits 0-25
97 
98     dwVal = sizeof(buffer);
99     if (GetComputerName(buffer, &dwVal))
100         RNG_RandomUpdate(buffer, dwVal);
101 
102     hVal = GetCurrentProcess(); // 4 or 8 byte pseudo handle (a
103                                 // constant!) of current process
104     RNG_RandomUpdate(&hVal, sizeof(hVal));
105 
106     dwVal = GetCurrentProcessId(); // process ID (4 bytes)
107     RNG_RandomUpdate(&dwVal, sizeof(dwVal));
108 
109     dwVal = GetCurrentThreadId(); // thread ID (4 bytes)
110     RNG_RandomUpdate(&dwVal, sizeof(dwVal));
111 
112     volName[0] = '\0';
113     buffer[0] = '\0';
114     GetVolumeInformation(NULL,
115                          volName,
116                          sizeof(volName),
117                          &dwSerialNum,
118                          &dwComponentLen,
119                          &dwSysFlags,
120                          buffer,
121                          sizeof(buffer));
122 
123     RNG_RandomUpdate(volName, strlen(volName));
124     RNG_RandomUpdate(&dwSerialNum, sizeof(dwSerialNum));
125     RNG_RandomUpdate(&dwComponentLen, sizeof(dwComponentLen));
126     RNG_RandomUpdate(&dwSysFlags, sizeof(dwSysFlags));
127     RNG_RandomUpdate(buffer, strlen(buffer));
128 
129     if (GetDiskFreeSpace(NULL, &dwSectors, &dwBytes, &dwFreeClusters,
130                          &dwNumClusters)) {
131         RNG_RandomUpdate(&dwSectors, sizeof(dwSectors));
132         RNG_RandomUpdate(&dwBytes, sizeof(dwBytes));
133         RNG_RandomUpdate(&dwFreeClusters, sizeof(dwFreeClusters));
134         RNG_RandomUpdate(&dwNumClusters, sizeof(dwNumClusters));
135     }
136 
137     nBytes = RNG_GetNoise(buffer, 20); // get up to 20 bytes
138     RNG_RandomUpdate(buffer, nBytes);
139 }
140 
141 /*
142  * The RtlGenRandom function is declared in <ntsecapi.h>, but the
143  * declaration is missing a calling convention specifier. So we
144  * declare it manually here.
145  */
146 #define RtlGenRandom SystemFunction036
147 DECLSPEC_IMPORT BOOLEAN WINAPI RtlGenRandom(
148     PVOID RandomBuffer,
149     ULONG RandomBufferLength);
150 
151 size_t
RNG_SystemRNG(void * dest,size_t maxLen)152 RNG_SystemRNG(void *dest, size_t maxLen)
153 {
154     size_t bytes = 0;
155 
156     if (RtlGenRandom(dest, maxLen)) {
157         bytes = maxLen;
158     }
159     return bytes;
160 }
161 #endif /* is XP_WIN */
162