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