1 /*
2 * PROJECT: ReactOS Drivers
3 * COPYRIGHT: See COPYING in the top level directory
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 MD5_CTX KsecLoadTimeStartMd5s[2];
14 DES3_KEY KsecGlobalDes3Key;
15 AES_KEY KsecGlobalAesKey;
16
17 typedef struct _KSEC_PROCESS_DATA
18 {
19 PEPROCESS Process;
20 HANDLE ProcessId;
21 LONGLONG CreateTime;
22 ULONG_PTR DirectoryTableBase;
23 } KSEC_PROCESS_DATA, *PKSEC_PROCESS_DATA;
24
25 typedef struct _KSEC_LOGON_DATA
26 {
27 LUID LogonId;
28 } KSEC_LOGON_DATA, *PKSEC_LOGON_DATA;
29
30 #if 0
31 void PrintKeyData(PUCHAR KeyData)
32 {
33 ULONG i;
34 for (i = 0; i < 32; i++)
35 {
36 DbgPrint("%02X", KeyData[i]);
37 }
38 DbgPrint("\n");
39 }
40 #endif
41
42 VOID
43 NTAPI
KsecInitializeEncryptionSupport(VOID)44 KsecInitializeEncryptionSupport (
45 VOID)
46 {
47 KSEC_ENTROPY_DATA EntropyData;
48 MD5_CTX Md5Context;
49 UCHAR KeyDataBuffer[32];
50
51 KsecGatherEntropyData(&EntropyData);
52 MD5Init(&Md5Context);
53 MD5Update(&Md5Context, (PVOID)&EntropyData, sizeof(EntropyData));
54 KsecLoadTimeStartMd5s[0] = Md5Context;
55 MD5Final(&Md5Context);
56 RtlCopyMemory(KeyDataBuffer, &Md5Context.digest, 16);
57
58 KsecGatherEntropyData(&EntropyData);
59 Md5Context = KsecLoadTimeStartMd5s[0];
60 MD5Update(&Md5Context, (PVOID)&EntropyData, sizeof(EntropyData));
61 KsecLoadTimeStartMd5s[1] = Md5Context;
62 MD5Final(&Md5Context);
63 RtlCopyMemory(&KeyDataBuffer[16], &Md5Context.digest, 16);
64
65 /* Create the global keys */
66 aes_setup(KeyDataBuffer, 32, 0, &KsecGlobalAesKey);
67 des3_setup(KeyDataBuffer, 24, 0, &KsecGlobalDes3Key);
68
69 /* Erase the temp data */
70 RtlSecureZeroMemory(KeyDataBuffer, sizeof(KeyDataBuffer));
71 RtlSecureZeroMemory(&Md5Context, sizeof(Md5Context));
72 }
73
74 static
75 VOID
KsecGetKeyData(_Out_ UCHAR KeyData[32],_In_ ULONG OptionFlags)76 KsecGetKeyData (
77 _Out_ UCHAR KeyData[32],
78 _In_ ULONG OptionFlags)
79 {
80 MD5_CTX Md5Contexts[2];
81 KSEC_PROCESS_DATA ProcessData;
82 KSEC_LOGON_DATA LogonData;
83 PEPROCESS CurrentProcess;
84 PACCESS_TOKEN Token;
85
86 /* We need to generate the key, start with our load MD5s */
87 Md5Contexts[0] = KsecLoadTimeStartMd5s[0];
88 Md5Contexts[1] = KsecLoadTimeStartMd5s[1];
89
90 /* Get the current process */
91 CurrentProcess = PsGetCurrentProcess();
92
93 if (OptionFlags == RTL_ENCRYPT_OPTION_SAME_PROCESS)
94 {
95 /* Hash some process specific data to generate the key */
96 RtlZeroMemory(&ProcessData, sizeof(ProcessData));
97 ProcessData.Process = CurrentProcess;
98 ProcessData.ProcessId = CurrentProcess->UniqueProcessId;
99 ProcessData.CreateTime = PsGetProcessCreateTimeQuadPart(CurrentProcess);
100 ProcessData.DirectoryTableBase = CurrentProcess->Pcb.DirectoryTableBase[0];
101 MD5Update(&Md5Contexts[0], (PVOID)&ProcessData, sizeof(ProcessData));
102 MD5Update(&Md5Contexts[1], (PVOID)&ProcessData, sizeof(ProcessData));
103 }
104 else if (OptionFlags == RTL_ENCRYPT_OPTION_SAME_LOGON)
105 {
106 /* Hash the logon id to generate the key */
107 RtlZeroMemory(&LogonData, sizeof(LogonData));
108 Token = PsReferencePrimaryToken(CurrentProcess);
109 SeQueryAuthenticationIdToken(Token, &LogonData.LogonId);
110 PsDereferencePrimaryToken(Token);
111 MD5Update(&Md5Contexts[0], (PVOID)&LogonData, sizeof(LogonData));
112 MD5Update(&Md5Contexts[1], (PVOID)&LogonData, sizeof(LogonData));
113 }
114 else if (OptionFlags == RTL_ENCRYPT_OPTION_CROSS_PROCESS)
115 {
116 /* Use the original MD5s to generate the global key */
117 NOTHING;
118 }
119 else
120 {
121 /* Must not pass anything else */
122 ASSERT(FALSE);
123 }
124
125 /* Finalize the MD5s */
126 MD5Final(&Md5Contexts[0]);
127 MD5Final(&Md5Contexts[1]);
128
129 /* Copy the md5 data */
130 RtlCopyMemory(KeyData, &Md5Contexts[0].digest, 16);
131 RtlCopyMemory((PUCHAR)KeyData + 16, &Md5Contexts[1].digest, 16);
132
133 /* Erase the temp data */
134 RtlSecureZeroMemory(&Md5Contexts, sizeof(Md5Contexts));
135 }
136
137 static
138 VOID
KsecGetDes3Key(_Out_ PDES3_KEY Des3Key,_In_ ULONG OptionFlags)139 KsecGetDes3Key (
140 _Out_ PDES3_KEY Des3Key,
141 _In_ ULONG OptionFlags)
142 {
143 UCHAR KeyDataBuffer[32];
144
145 /* Check if the caller allows cross process encryption */
146 if (OptionFlags == RTL_ENCRYPT_OPTION_CROSS_PROCESS)
147 {
148 /* Return our global cached DES3 key */
149 *Des3Key = KsecGlobalDes3Key;
150 }
151 else
152 {
153 /* Setup the key */
154 KsecGetKeyData(KeyDataBuffer, OptionFlags);
155 des3_setup(KeyDataBuffer, 24, 0, Des3Key);
156
157 /* Erase the temp data */
158 RtlSecureZeroMemory(KeyDataBuffer, sizeof(KeyDataBuffer));
159 }
160 }
161
162 static
163 VOID
KsecGetAesKey(_Out_ PAES_KEY AesKey,_In_ ULONG OptionFlags)164 KsecGetAesKey (
165 _Out_ PAES_KEY AesKey,
166 _In_ ULONG OptionFlags)
167 {
168 UCHAR KeyDataBuffer[32];
169
170 /* Check if the caller allows cross process encryption */
171 if (OptionFlags == RTL_ENCRYPT_OPTION_CROSS_PROCESS)
172 {
173 /* Return our global cached AES key */
174 *AesKey = KsecGlobalAesKey;
175 }
176 else
177 {
178 /* Setup the key */
179 KsecGetKeyData(KeyDataBuffer, OptionFlags);
180 aes_setup(KeyDataBuffer, 32, 0, AesKey);
181
182 /* Erase the temp data */
183 RtlSecureZeroMemory(KeyDataBuffer, sizeof(KeyDataBuffer));
184 }
185 }
186
187 static
188 VOID
KsecEncryptMemoryDes3(_Inout_ PVOID Buffer,_In_ ULONG Length,_In_ ULONG OptionFlags)189 KsecEncryptMemoryDes3 (
190 _Inout_ PVOID Buffer,
191 _In_ ULONG Length,
192 _In_ ULONG OptionFlags)
193 {
194 UCHAR EncryptedBlockData[8];
195 DES3_KEY Des3Key;
196
197 /* Get they triple DES key */
198 KsecGetDes3Key(&Des3Key, OptionFlags);
199
200 /* Do the triple DES encryption */
201 while (Length >= sizeof(EncryptedBlockData))
202 {
203 des3_ecb_encrypt(Buffer, EncryptedBlockData, &Des3Key);
204 RtlCopyMemory(Buffer, EncryptedBlockData, sizeof(EncryptedBlockData));
205 Buffer = (PUCHAR)Buffer + sizeof(EncryptedBlockData);
206 Length -= sizeof(EncryptedBlockData);
207 }
208
209 /* Erase the key data */
210 RtlSecureZeroMemory(&Des3Key, sizeof(Des3Key));
211 }
212
213 static
214 VOID
KsecDecryptMemoryDes3(_Inout_ PVOID Buffer,_In_ ULONG Length,_In_ ULONG OptionFlags)215 KsecDecryptMemoryDes3 (
216 _Inout_ PVOID Buffer,
217 _In_ ULONG Length,
218 _In_ ULONG OptionFlags)
219 {
220 UCHAR BlockData[8];
221 DES3_KEY Des3Key;
222
223 /* Get they triple DES key */
224 KsecGetDes3Key(&Des3Key, OptionFlags);
225
226 /* Do the triple DES decryption */
227 while (Length >= sizeof(BlockData))
228 {
229 des3_ecb_decrypt(Buffer, BlockData, &Des3Key);
230 RtlCopyMemory(Buffer, BlockData, sizeof(BlockData));
231 Buffer = (PUCHAR)Buffer + sizeof(BlockData);
232 Length -= sizeof(BlockData);
233 }
234
235 /* Erase the key data */
236 RtlSecureZeroMemory(&Des3Key, sizeof(Des3Key));
237 }
238
239 static
240 VOID
KsecEncryptMemoryAes(_Inout_ PVOID Buffer,_In_ ULONG Length,_In_ ULONG OptionFlags)241 KsecEncryptMemoryAes (
242 _Inout_ PVOID Buffer,
243 _In_ ULONG Length,
244 _In_ ULONG OptionFlags)
245 {
246 UCHAR EncryptedBlockData[16];
247 AES_KEY AesKey;
248
249 /* Get they AES key */
250 KsecGetAesKey(&AesKey, OptionFlags);
251
252 /* Do the AES encryption */
253 while (Length >= sizeof(EncryptedBlockData))
254 {
255 aes_ecb_encrypt(Buffer, EncryptedBlockData, &AesKey);
256 RtlCopyMemory(Buffer, EncryptedBlockData, sizeof(EncryptedBlockData));
257 Buffer = (PUCHAR)Buffer + sizeof(EncryptedBlockData);
258 Length -= sizeof(EncryptedBlockData);
259 }
260
261 /* Erase the key data */
262 RtlSecureZeroMemory(&AesKey, sizeof(AesKey));
263 }
264
265 static
266 VOID
KsecDecryptMemoryAes(_Inout_ PVOID Buffer,_In_ ULONG Length,_In_ ULONG OptionFlags)267 KsecDecryptMemoryAes (
268 _Inout_ PVOID Buffer,
269 _In_ ULONG Length,
270 _In_ ULONG OptionFlags)
271 {
272 UCHAR BlockData[16];
273 AES_KEY AesKey;
274
275 /* Get they AES key */
276 KsecGetAesKey(&AesKey, OptionFlags);
277
278 /* Do the AES decryption */
279 while (Length >= sizeof(BlockData))
280 {
281 aes_ecb_decrypt(Buffer, BlockData, &AesKey);
282 RtlCopyMemory(Buffer, BlockData, sizeof(BlockData));
283 Buffer = (PUCHAR)Buffer + sizeof(BlockData);
284 Length -= sizeof(BlockData);
285 }
286
287 /* Erase the key data */
288 RtlSecureZeroMemory(&AesKey, sizeof(AesKey));
289 }
290
291 NTSTATUS
292 NTAPI
KsecEncryptMemory(_Inout_ PVOID Buffer,_In_ ULONG Length,_In_ ULONG OptionFlags)293 KsecEncryptMemory (
294 _Inout_ PVOID Buffer,
295 _In_ ULONG Length,
296 _In_ ULONG OptionFlags)
297 {
298 /* Validate parameter */
299 if (OptionFlags > RTL_ENCRYPT_OPTION_SAME_LOGON)
300 {
301 return STATUS_INVALID_PARAMETER;
302 }
303
304 /* Check if the length is not 16 bytes aligned */
305 if (Length & 15)
306 {
307 /* Is it at least 8 bytes aligned? */
308 if (Length & 7)
309 {
310 /* No, we can't deal with it! */
311 return STATUS_INVALID_PARAMETER;
312 }
313
314 /* Use triple DES encryption */
315 KsecEncryptMemoryDes3(Buffer, Length, OptionFlags);
316 }
317 else
318 {
319 /* Use AES encryption */
320 KsecEncryptMemoryAes(Buffer, Length, OptionFlags);
321 }
322
323 return STATUS_SUCCESS;
324 }
325
326 NTSTATUS
327 NTAPI
KsecDecryptMemory(_Inout_ PVOID Buffer,_In_ ULONG Length,_In_ ULONG OptionFlags)328 KsecDecryptMemory (
329 _Inout_ PVOID Buffer,
330 _In_ ULONG Length,
331 _In_ ULONG OptionFlags)
332 {
333 /* Validate parameter */
334 if (OptionFlags > RTL_ENCRYPT_OPTION_SAME_LOGON)
335 {
336 return STATUS_INVALID_PARAMETER;
337 }
338
339 /* Check if the length is not 16 bytes aligned */
340 if (Length & 15)
341 {
342 /* Is it at least 8 bytes aligned? */
343 if (Length & 7)
344 {
345 /* No, we can't deal with it! */
346 return STATUS_INVALID_PARAMETER;
347 }
348
349 /* Use triple DES encryption */
350 KsecDecryptMemoryDes3(Buffer, Length, OptionFlags);
351 }
352 else
353 {
354 /* Use AES encryption */
355 KsecDecryptMemoryAes(Buffer, Length, OptionFlags);
356 }
357
358 return STATUS_SUCCESS;
359 }
360