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