xref: /reactos/drivers/crypto/ksecdd/crypt.c (revision 40462c92)
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
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
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
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
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
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
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
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
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
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
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