1d1168a877660b1d345470e7000c360e3f767050
[reactos.git] / reactos / drivers / crypto / ksecdd / random.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Drivers
4 * PURPOSE: Kernel Security Support Provider Interface Driver
5 *
6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "ksecdd.h"
12 #include <ndk/exfuncs.h>
13 #include <ndk/kefuncs.h>
14 #include <pseh/pseh2.h>
15 #include <md4.h>
16
17 #define NDEBUG
18 #include <debug.h>
19
20
21 /* GLOBALS ********************************************************************/
22
23 static ULONG KsecRandomSeed = 0x62b409a1;
24
25
26 /* FUNCTIONS ******************************************************************/
27
28 NTSTATUS
29 NTAPI
30 KsecGenRandom(
31 PVOID Buffer,
32 SIZE_T Length)
33 {
34 LARGE_INTEGER TickCount;
35 ULONG i, RandomValue;
36 PULONG P;
37
38 /* Try to generate a more random seed */
39 KeQueryTickCount(&TickCount);
40 KsecRandomSeed ^= _rotl(TickCount.LowPart, (KsecRandomSeed % 23));
41
42 P = Buffer;
43 for (i = 0; i < Length / sizeof(ULONG); i++)
44 {
45 P[i] = RtlRandomEx(&KsecRandomSeed);
46 }
47
48 Length &= (sizeof(ULONG) - 1);
49 if (Length > 0)
50 {
51 RandomValue = RtlRandomEx(&KsecRandomSeed);
52 RtlCopyMemory(&P[i], &RandomValue, Length);
53 }
54
55 return STATUS_SUCCESS;
56 }
57
58 VOID
59 NTAPI
60 KsecReadMachineSpecificCounters(
61 _Out_ PKSEC_MACHINE_SPECIFIC_COUNTERS MachineSpecificCounters)
62 {
63 #if defined(_M_IX86) || defined(_M_AMD64)
64 /* Check if RDTSC is available */
65 if (ExIsProcessorFeaturePresent(PF_RDTSC_INSTRUCTION_AVAILABLE))
66 {
67 /* Read the TSC value */
68 MachineSpecificCounters->Tsc = __rdtsc();
69 }
70
71 /* Read the CPU event counter MSRs */
72 MachineSpecificCounters->Ctr0 = __readmsr(0x12);
73 MachineSpecificCounters->Ctr1 = __readmsr(0x13);
74
75 /* Check if this is an MMX capable CPU */
76 if (ExIsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE))
77 {
78 /* Read the CPU performance counters 0 and 1 */
79 MachineSpecificCounters->Pmc0 = __readpmc(0);
80 MachineSpecificCounters->Pmc1 = __readpmc(1);
81 }
82 #else
83 #error Implement me!
84 #endif
85 }
86
87 /*!
88 * \see http://blogs.msdn.com/b/michael_howard/archive/2005/01/14/353379.aspx
89 */
90 NTSTATUS
91 NTAPI
92 KsecGatherEntropyData(
93 PKSEC_ENTROPY_DATA EntropyData)
94 {
95 MD4_CTX Md4Context;
96 PTEB Teb;
97 PPEB Peb;
98 PWSTR String;
99 SIZE_T ReturnLength;
100 NTSTATUS Status;
101
102 /* Query some generic values */
103 EntropyData->CurrentProcessId = PsGetCurrentProcessId();
104 EntropyData->CurrentThreadId = PsGetCurrentThreadId();
105 KeQueryTickCount(&EntropyData->TickCount);
106 KeQuerySystemTime(&EntropyData->SystemTime);
107 EntropyData->PerformanceCounter = KeQueryPerformanceCounter(
108 &EntropyData->PerformanceFrequency);
109
110 /* Check if we have a TEB/PEB for the process environment */
111 Teb = PsGetCurrentThread()->Tcb.Teb;
112 if (Teb != NULL)
113 {
114 Peb = Teb->ProcessEnvironmentBlock;
115
116 /* Initialize the MD4 context */
117 MD4Init(&Md4Context);
118 _SEH2_TRY
119 {
120 /* Get the end of the environment */
121 String = Peb->ProcessParameters->Environment;
122 while (*String)
123 {
124 String += wcslen(String) + 1;
125 }
126
127 /* Update the MD4 context from the environment data */
128 MD4Update(&Md4Context,
129 (PUCHAR)Peb->ProcessParameters->Environment,
130 (ULONG)((PUCHAR)String - (PUCHAR)Peb->ProcessParameters->Environment));
131 }
132 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
133 {
134 /* Simply ignore the exception */
135 }
136 _SEH2_END;
137
138 /* Finalize and copy the MD4 hash */
139 MD4Final(&Md4Context);
140 RtlCopyMemory(&EntropyData->EnvironmentHash, Md4Context.digest, 16);
141 }
142
143 /* Read some machine specific hardware counters */
144 KsecReadMachineSpecificCounters(&EntropyData->MachineSpecificCounters);
145
146 /* Query processor performance information */
147 Status = ZwQuerySystemInformation(SystemProcessorPerformanceInformation,
148 &EntropyData->SystemProcessorPerformanceInformation,
149 sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION),
150 &ReturnLength);
151 if (!NT_SUCCESS(Status))
152 {
153 return Status;
154 }
155
156 /* Query system performance information */
157 Status = ZwQuerySystemInformation(SystemPerformanceInformation,
158 &EntropyData->SystemPerformanceInformation,
159 sizeof(SYSTEM_PERFORMANCE_INFORMATION),
160 &ReturnLength);
161 if (!NT_SUCCESS(Status))
162 {
163 return Status;
164 }
165
166 /* Query exception information */
167 Status = ZwQuerySystemInformation(SystemExceptionInformation,
168 &EntropyData->SystemExceptionInformation,
169 sizeof(SYSTEM_EXCEPTION_INFORMATION),
170 &ReturnLength);
171 if (!NT_SUCCESS(Status))
172 {
173 return Status;
174 }
175
176 /* Query lookaside information */
177 Status = ZwQuerySystemInformation(SystemLookasideInformation,
178 &EntropyData->SystemLookasideInformation,
179 sizeof(SYSTEM_LOOKASIDE_INFORMATION),
180 &ReturnLength);
181 if (!NT_SUCCESS(Status))
182 {
183 return Status;
184 }
185
186 /* Query interrupt information */
187 Status = ZwQuerySystemInformation(SystemInterruptInformation,
188 &EntropyData->SystemInterruptInformation,
189 sizeof(SYSTEM_INTERRUPT_INFORMATION),
190 &ReturnLength);
191 if (!NT_SUCCESS(Status))
192 {
193 return Status;
194 }
195
196 /* Query process information */
197 Status = ZwQuerySystemInformation(SystemProcessInformation,
198 &EntropyData->SystemProcessInformation,
199 sizeof(SYSTEM_PROCESS_INFORMATION),
200 &ReturnLength);
201 if (!NT_SUCCESS(Status))
202 {
203 return Status;
204 }
205
206 return STATUS_SUCCESS;
207 }