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