xref: /reactos/drivers/crypto/ksecdd/random.c (revision fe11f7a2)
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 
13 #define NDEBUG
14 #include <debug.h>
15 
16 
17 /* GLOBALS ********************************************************************/
18 
19 static ULONG KsecRandomSeed = 0x62b409a1;
20 
21 
22 /* FUNCTIONS ******************************************************************/
23 
24 NTSTATUS
25 NTAPI
KsecGenRandom(PVOID Buffer,SIZE_T Length)26 KsecGenRandom(
27     PVOID Buffer,
28     SIZE_T Length)
29 {
30     LARGE_INTEGER TickCount;
31     ULONG i, RandomValue;
32     PULONG P;
33 
34     /* Try to generate a more random seed */
35     KeQueryTickCount(&TickCount);
36     KsecRandomSeed ^= _rotl(TickCount.LowPart, (KsecRandomSeed % 23));
37 
38     P = Buffer;
39     for (i = 0; i < Length / sizeof(ULONG); i++)
40     {
41         P[i] = RtlRandomEx(&KsecRandomSeed);
42     }
43 
44     Length &= (sizeof(ULONG) - 1);
45     if (Length > 0)
46     {
47         RandomValue = RtlRandomEx(&KsecRandomSeed);
48         RtlCopyMemory(&P[i], &RandomValue, Length);
49     }
50 
51     return STATUS_SUCCESS;
52 }
53 
54 VOID
55 NTAPI
KsecReadMachineSpecificCounters(_Out_ PKSEC_MACHINE_SPECIFIC_COUNTERS MachineSpecificCounters)56 KsecReadMachineSpecificCounters(
57     _Out_ PKSEC_MACHINE_SPECIFIC_COUNTERS MachineSpecificCounters)
58 {
59 #if defined(_M_IX86) || defined(_M_AMD64)
60     /* Check if RDTSC is available */
61     if (ExIsProcessorFeaturePresent(PF_RDTSC_INSTRUCTION_AVAILABLE))
62     {
63         /* Read the TSC value */
64         MachineSpecificCounters->Tsc = __rdtsc();
65     }
66 #if 0 // FIXME: investigate what the requirements are for these
67     /* Read the CPU event counter MSRs */
68     //MachineSpecificCounters->Ctr0 = __readmsr(0x12);
69     //MachineSpecificCounters->Ctr1 = __readmsr(0x13);
70 
71     /* Check if this is an MMX capable CPU */
72     if (ExIsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE))
73     {
74         /* Read the CPU performance counters 0 and 1 */
75         MachineSpecificCounters->Pmc0 = __readpmc(0);
76         MachineSpecificCounters->Pmc1 = __readpmc(1);
77     }
78 #endif
79 #elif defined(_M_ARM)
80     /* Read the Cycle Counter Register */
81     MachineSpecificCounters->Ccr = _MoveFromCoprocessor(CP15_PMCCNTR);
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 (DEAD_LINK)
89  */
90 NTSTATUS
91 NTAPI
KsecGatherEntropyData(PKSEC_ENTROPY_DATA EntropyData)92 KsecGatherEntropyData(
93     PKSEC_ENTROPY_DATA EntropyData)
94 {
95     MD4_CTX Md4Context;
96     PTEB Teb;
97     PPEB Peb;
98     PWSTR String;
99     ULONG 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 }
208