xref: /reactos/dll/win32/advapi32/misc/sysfunc.c (revision 845faec4)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            dll/win32/advapi32/misc/sysfun.c
5  * PURPOSE:         advapi32.dll system functions (undocumented)
6  * PROGRAMMER:      Emanuele Aliberti
7  * UPDATE HISTORY:
8  *  19990413 EA created
9  *  19990415 EA
10  *  20080424 Ported from WINE
11  */
12 
13 #include <advapi32.h>
14 #include <ntsecapi.h>
15 #include <ksecioctl.h>
16 #include <md4.h>
17 #include <md5.h>
18 #include <rc4.h>
19 
20 static const unsigned char CRYPT_LMhash_Magic[8] =
21     { 'K', 'G', 'S', '!', '@', '#', '$', '%' };
22 
23 /******************************************************************************
24  * SystemFunction001  [ADVAPI32.@]
25  *
26  * Encrypts a single block of data using DES
27  *
28  * PARAMS
29  *   data    [I] data to encrypt    (8 bytes)
30  *   key     [I] key data           (7 bytes)
31  *   output  [O] the encrypted data (8 bytes)
32  *
33  * RETURNS
34  *  Success: STATUS_SUCCESS
35  *  Failure: STATUS_UNSUCCESSFUL
36  *
37  */
38 NTSTATUS
39 WINAPI SystemFunction001(const BYTE *data, const BYTE *key, LPBYTE output)
40 {
41     if (!data || !output)
42         return STATUS_UNSUCCESSFUL;
43     CRYPT_DEShash(output, key, data);
44     return STATUS_SUCCESS;
45 }
46 
47 
48 /******************************************************************************
49  * SystemFunction002  [ADVAPI32.@]
50  *
51  * Decrypts a single block of data using DES
52  *
53  * PARAMS
54  *   data    [I] data to decrypt    (8 bytes)
55  *   key     [I] key data           (7 bytes)
56  *   output  [O] the decrypted data (8 bytes)
57  *
58  * RETURNS
59  *  Success: STATUS_SUCCESS
60  *  Failure: STATUS_UNSUCCESSFUL
61  *
62  */
63 NTSTATUS
64 WINAPI SystemFunction002(const BYTE *data, const BYTE *key, LPBYTE output)
65 {
66     if (!data || !output)
67         return STATUS_UNSUCCESSFUL;
68     CRYPT_DESunhash(output, key, data);
69     return STATUS_SUCCESS;
70 }
71 
72 
73 /******************************************************************************
74  * SystemFunction003  [ADVAPI32.@]
75  *
76  * Hashes a key using DES and a fixed datablock
77  *
78  * PARAMS
79  *   key     [I] key data    (7 bytes)
80  *   output  [O] hashed key  (8 bytes)
81  *
82  * RETURNS
83  *  Success: STATUS_SUCCESS
84  *  Failure: STATUS_UNSUCCESSFUL
85  *
86  */
87 NTSTATUS
88 WINAPI SystemFunction003(const BYTE *key, LPBYTE output)
89 {
90     if (!output)
91         return STATUS_UNSUCCESSFUL;
92     CRYPT_DEShash(output, key, CRYPT_LMhash_Magic);
93     return STATUS_SUCCESS;
94 }
95 
96 
97 /******************************************************************************
98  * SystemFunction004  [ADVAPI32.@]
99  *
100  * Encrypts a block of data with DES in ECB mode, preserving the length
101  *
102  * PARAMS
103  *   data    [I] data to encrypt
104  *   key     [I] key data (up to 7 bytes)
105  *   output  [O] buffer to receive encrypted data
106  *
107  * RETURNS
108  *  Success: STATUS_SUCCESS
109  *  Failure: STATUS_BUFFER_TOO_SMALL     if the output buffer is too small
110  *  Failure: STATUS_INVALID_PARAMETER_2  if the key is zero length
111  *
112  * NOTES
113  *  Encrypt buffer size should be input size rounded up to 8 bytes
114  *   plus an extra 8 bytes.
115  */
116 NTSTATUS
117 WINAPI SystemFunction004(const struct ustring *in,
118                                   const struct ustring *key,
119                                   struct ustring *out)
120 {
121     union {
122         unsigned char uc[8];
123           unsigned int  ui[2];
124     } data;
125     unsigned char deskey[7];
126     unsigned int crypt_len, ofs;
127 
128     if (key->Length<=0)
129         return STATUS_INVALID_PARAMETER_2;
130 
131     crypt_len = ((in->Length+7)&~7);
132     if (out->MaximumLength < (crypt_len+8))
133         return STATUS_BUFFER_TOO_SMALL;
134 
135     data.ui[0] = in->Length;
136     data.ui[1] = 1;
137 
138     if (key->Length<sizeof deskey)
139     {
140         memset(deskey, 0, sizeof deskey);
141         memcpy(deskey, key->Buffer, key->Length);
142     }
143     else
144         memcpy(deskey, key->Buffer, sizeof deskey);
145 
146     CRYPT_DEShash(out->Buffer, deskey, data.uc);
147 
148     for(ofs=0; ofs<(crypt_len-8); ofs+=8)
149         CRYPT_DEShash(out->Buffer+8+ofs, deskey, in->Buffer+ofs);
150 
151     memset(data.uc, 0, sizeof data.uc);
152     memcpy(data.uc, in->Buffer+ofs, in->Length +8-crypt_len);
153     CRYPT_DEShash(out->Buffer+8+ofs, deskey, data.uc);
154 
155     out->Length = crypt_len+8;
156 
157     return STATUS_SUCCESS;
158 }
159 
160 /******************************************************************************
161  * SystemFunction005  [ADVAPI32.@]
162  *
163  * Decrypts a block of data with DES in ECB mode
164  *
165  * PARAMS
166  *   data    [I] data to decrypt
167  *   key     [I] key data (up to 7 bytes)
168  *   output  [O] buffer to receive decrypted data
169  *
170  * RETURNS
171  *  Success: STATUS_SUCCESS
172  *  Failure: STATUS_BUFFER_TOO_SMALL     if the output buffer is too small
173  *  Failure: STATUS_INVALID_PARAMETER_2  if the key is zero length
174  *
175  */
176 NTSTATUS
177 WINAPI SystemFunction005(const struct ustring *in,
178                          const struct ustring *key,
179                          struct ustring *out)
180 {
181     union {
182         unsigned char uc[8];
183         unsigned int  ui[2];
184     } data;
185     unsigned char deskey[7];
186     unsigned int ofs, crypt_len;
187 
188     if (key->Length<=0)
189         return STATUS_INVALID_PARAMETER_2;
190 
191     if (key->Length<sizeof deskey)
192     {
193         memset(deskey, 0, sizeof deskey);
194         memcpy(deskey, key->Buffer, key->Length);
195     }
196     else
197         memcpy(deskey, key->Buffer, sizeof deskey);
198 
199     CRYPT_DESunhash(data.uc, deskey, in->Buffer);
200 
201     if (data.ui[1] != 1)
202         return STATUS_UNKNOWN_REVISION;
203 
204     crypt_len = data.ui[0];
205     if (crypt_len > out->MaximumLength)
206         return STATUS_BUFFER_TOO_SMALL;
207 
208     for (ofs=0; (ofs+8)<crypt_len; ofs+=8)
209         CRYPT_DESunhash(out->Buffer+ofs, deskey, in->Buffer+ofs+8);
210 
211     if (ofs<crypt_len)
212     {
213         CRYPT_DESunhash(data.uc, deskey, in->Buffer+ofs+8);
214         memcpy(out->Buffer+ofs, data.uc, crypt_len-ofs);
215     }
216 
217     out->Length = crypt_len;
218 
219     return STATUS_SUCCESS;
220 }
221 
222 /******************************************************************************
223  * SystemFunction007  [ADVAPI32.@]
224  *
225  * MD4 hash a unicode string
226  *
227  * PARAMS
228  *   string  [I] the string to hash
229  *   output  [O] the md4 hash of the string (16 bytes)
230  *
231  * RETURNS
232  *  Success: STATUS_SUCCESS
233  *  Failure: STATUS_UNSUCCESSFUL
234  *
235  */
236 NTSTATUS
237 WINAPI SystemFunction007(const UNICODE_STRING *string, LPBYTE hash)
238 {
239     MD4_CTX ctx;
240 
241     MD4Init( &ctx );
242     MD4Update( &ctx, (const BYTE *)string->Buffer, string->Length );
243     MD4Final( &ctx );
244     memcpy( hash, ctx.digest, 0x10 );
245 
246     return STATUS_SUCCESS;
247 }
248 
249 /******************************************************************************
250  * SystemFunction008  [ADVAPI32.@]
251  *
252  * Creates a LM response from a challenge and a password hash
253  *
254  * PARAMS
255  *   challenge  [I] Challenge from authentication server
256  *   hash       [I] NTLM hash (from SystemFunction006)
257  *   response   [O] response to send back to the server
258  *
259  * RETURNS
260  *  Success: STATUS_SUCCESS
261  *  Failure: STATUS_UNSUCCESSFUL
262  *
263  * NOTES
264  *  see http://davenport.sourceforge.net/ntlm.html#theLmResponse
265  *
266  */
267 NTSTATUS
268 WINAPI SystemFunction008(const BYTE *challenge, const BYTE *hash, LPBYTE response)
269 {
270     BYTE key[7*3];
271 
272     if (!challenge || !response)
273         return STATUS_UNSUCCESSFUL;
274 
275     memset(key, 0, sizeof key);
276     memcpy(key, hash, 0x10);
277 
278     CRYPT_DEShash(response, key, challenge);
279     CRYPT_DEShash(response+8, key+7, challenge);
280     CRYPT_DEShash(response+16, key+14, challenge);
281 
282     return STATUS_SUCCESS;
283 }
284 
285 /******************************************************************************
286  * SystemFunction009  [ADVAPI32.@]
287  *
288  * Seems to do the same as SystemFunction008...
289  */
290 NTSTATUS
291 WINAPI SystemFunction009(const BYTE *challenge, const BYTE *hash, LPBYTE response)
292 {
293     return SystemFunction008(challenge, hash, response);
294 }
295 
296 /******************************************************************************
297  * SystemFunction010  [ADVAPI32.@]
298  * SystemFunction011  [ADVAPI32.@]
299  *
300  * MD4 hashes 16 bytes of data
301  *
302  * PARAMS
303  *   unknown []  seems to have no effect on the output
304  *   data    [I] pointer to data to hash (16 bytes)
305  *   output  [O] the md4 hash of the data (16 bytes)
306  *
307  * RETURNS
308  *  Success: STATUS_SUCCESS
309  *  Failure: STATUS_UNSUCCESSFUL
310  *
311  */
312 NTSTATUS
313 WINAPI SystemFunction010(LPVOID unknown, const BYTE *data, LPBYTE hash)
314 {
315     MD4_CTX ctx;
316 
317     MD4Init( &ctx );
318     MD4Update( &ctx, data, 0x10 );
319     MD4Final( &ctx );
320     memcpy( hash, ctx.digest, 0x10 );
321 
322     return STATUS_SUCCESS;
323 }
324 
325 /******************************************************************************
326  * SystemFunction012  [ADVAPI32.@]
327  * SystemFunction014  [ADVAPI32.@]
328  * SystemFunction016  [ADVAPI32.@]
329  * SystemFunction018  [ADVAPI32.@]
330  * SystemFunction020  [ADVAPI32.@]
331  * SystemFunction022  [ADVAPI32.@]
332  *
333  * Encrypts two DES blocks with two keys
334  *
335  * PARAMS
336  *   data    [I] data to encrypt (16 bytes)
337  *   key     [I] key data (two lots of 7 bytes)
338  *   output  [O] buffer to receive encrypted data (16 bytes)
339  *
340  * RETURNS
341  *  Success: STATUS_SUCCESS
342  *  Failure: STATUS_UNSUCCESSFUL  if the input or output buffer is NULL
343  */
344 NTSTATUS
345 WINAPI SystemFunction012(const BYTE *in, const BYTE *key, LPBYTE out)
346 {
347     if (!in || !out)
348         return STATUS_UNSUCCESSFUL;
349 
350     CRYPT_DEShash(out, key, in);
351     CRYPT_DEShash(out+8, key+7, in+8);
352     return STATUS_SUCCESS;
353 }
354 
355 /******************************************************************************
356  * SystemFunction013  [ADVAPI32.@]
357  * SystemFunction015  [ADVAPI32.@]
358  * SystemFunction017  [ADVAPI32.@]
359  * SystemFunction019  [ADVAPI32.@]
360  * SystemFunction021  [ADVAPI32.@]
361  * SystemFunction023  [ADVAPI32.@]
362  *
363  * Decrypts two DES blocks with two keys
364  *
365  * PARAMS
366  *   data    [I] data to decrypt (16 bytes)
367  *   key     [I] key data (two lots of 7 bytes)
368  *   output  [O] buffer to receive decrypted data (16 bytes)
369  *
370  * RETURNS
371  *  Success: STATUS_SUCCESS
372  *  Failure: STATUS_UNSUCCESSFUL  if the input or output buffer is NULL
373  */
374 NTSTATUS
375 WINAPI SystemFunction013(const BYTE *in, const BYTE *key, LPBYTE out)
376 {
377     if (!in || !out)
378         return STATUS_UNSUCCESSFUL;
379     CRYPT_DESunhash(out, key, in);
380     CRYPT_DESunhash(out+8, key+7, in+8);
381     return STATUS_SUCCESS;
382 }
383 
384 /******************************************************************************
385  * SystemFunction024  [ADVAPI32.@]
386  *
387  * Encrypts two DES blocks with a 32 bit key...
388  *
389  * PARAMS
390  *   data    [I] data to encrypt (16 bytes)
391  *   key     [I] key data (4 bytes)
392  *   output  [O] buffer to receive encrypted data (16 bytes)
393  *
394  * RETURNS
395  *  Success: STATUS_SUCCESS
396  */
397 NTSTATUS
398 WINAPI SystemFunction024(const BYTE *in, const BYTE *key, LPBYTE out)
399 {
400     BYTE deskey[0x10];
401 
402     memcpy(deskey, key, 4);
403     memcpy(deskey+4, key, 4);
404     memcpy(deskey+8, key, 4);
405     memcpy(deskey+12, key, 4);
406 
407     CRYPT_DEShash(out, deskey, in);
408     CRYPT_DEShash(out+8, deskey+7, in+8);
409 
410     return STATUS_SUCCESS;
411 }
412 
413 /******************************************************************************
414  * SystemFunction025  [ADVAPI32.@]
415  *
416  * Decrypts two DES blocks with a 32 bit key...
417  *
418  * PARAMS
419  *   data    [I] data to encrypt (16 bytes)
420  *   key     [I] key data (4 bytes)
421  *   output  [O] buffer to receive encrypted data (16 bytes)
422  *
423  * RETURNS
424  *  Success: STATUS_SUCCESS
425  */
426 NTSTATUS
427 WINAPI SystemFunction025(const BYTE *in, const BYTE *key, LPBYTE out)
428 {
429     BYTE deskey[0x10];
430 
431     memcpy(deskey, key, 4);
432     memcpy(deskey+4, key, 4);
433     memcpy(deskey+8, key, 4);
434     memcpy(deskey+12, key, 4);
435 
436     CRYPT_DESunhash(out, deskey, in);
437     CRYPT_DESunhash(out+8, deskey+7, in+8);
438 
439     return STATUS_SUCCESS;
440 }
441 
442 /**********************************************************************
443  *
444  * @unimplemented
445  */
446 INT
447 WINAPI
448 SystemFunction028(INT a, INT b)
449 {
450     //NDRCContextBinding()
451     //SystemFunction034()
452     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
453     return 28;
454 }
455 
456 
457 /**********************************************************************
458  *
459  * @unimplemented
460  */
461 INT
462 WINAPI
463 SystemFunction029(INT a, INT b)
464 {
465     //I_RpcBindingIsClientLocal()
466     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
467     return 29;
468 }
469 
470 
471 /******************************************************************************
472  * SystemFunction030   (ADVAPI32.@)
473  *
474  * Tests if two blocks of 16 bytes are equal
475  *
476  * PARAMS
477  *  b1,b2   [I] block of 16 bytes
478  *
479  * RETURNS
480  *  TRUE  if blocks are the same
481  *  FALSE if blocks are different
482  */
483 BOOL
484 WINAPI SystemFunction030(LPCVOID b1, LPCVOID b2)
485 {
486     return !memcmp(b1, b2, 0x10);
487 }
488 
489 
490 /******************************************************************************
491  * SystemFunction032  [ADVAPI32.@]
492  *
493  * Encrypts a string data using ARC4
494  *
495  * PARAMS
496  *   data    [I/O] data to encrypt
497  *   key     [I] key data
498  *
499  * RETURNS
500  *  Success: STATUS_SUCCESS
501  *  Failure: STATUS_UNSUCCESSFUL
502  *
503  * NOTES
504  *  see http://web.it.kth.se/~rom/ntsec.html#crypto-strongavail
505  */
506 NTSTATUS
507 WINAPI SystemFunction032(struct ustring *data, const struct ustring *key)
508 {
509     RC4_CONTEXT a4i;
510 
511     rc4_init(&a4i, key->Buffer, key->Length);
512     rc4_crypt(&a4i, data->Buffer, data->Length);
513 
514     return STATUS_SUCCESS;
515 }
516 
517 
518 /**********************************************************************
519  *
520  * @unimplemented
521  */
522 INT
523 WINAPI
524 SystemFunction033(INT a, INT b)
525 {
526     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
527     return 33;
528 }
529 
530 /**********************************************************************
531  *
532  * @unimplemented
533  */
534 INT
535 WINAPI
536 SystemFunction034(INT a, INT b)
537 {
538     //RpcBindingToStringBindingW
539     //I_RpcMapWin32Status
540     //RpcStringBindingParseW
541     //RpcStringFreeW
542     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
543     return 34;
544 }
545 
546 
547 /******************************************************************************
548  * SystemFunction035   (ADVAPI32.@)
549  *
550  * Described here:
551 http://disc.server.com/discussion.cgi?disc=148775;article=942;title=Coding%2FASM%2FSystem
552  *
553  * NOTES
554  *  Stub, always return TRUE.
555  */
556 BOOL WINAPI SystemFunction035(LPCSTR lpszDllFilePath)
557 {
558     //FIXME("%s: stub\n", debugstr_a(lpszDllFilePath));
559     return TRUE;
560 }
561 
562 /******************************************************************************
563  * SystemFunction036   (ADVAPI32.@)
564  *
565  * MSDN documents this function as RtlGenRandom and declares it in ntsecapi.h
566  *
567  * PARAMS
568  *  pbBuffer [O] Pointer to memory to receive random bytes.
569  *  dwLen    [I] Number of random bytes to fetch.
570  *
571  * RETURNS
572  *  Always TRUE in my tests
573  */
574 BOOLEAN
575 WINAPI
576 SystemFunction036(PVOID pbBuffer, ULONG dwLen)
577 {
578     ////////////////////////////////////////////////////////////////
579     //////////////////// B I G   W A R N I N G  !!! ////////////////
580     // This function will output numbers based on the tick count. //
581     // It will NOT OUTPUT CRYPTOGRAPHIC-SAFE RANDOM NUMBERS !!!    //
582     ////////////////////////////////////////////////////////////////
583 
584     DWORD dwSeed;
585     PBYTE pBuffer;
586     ULONG uPseudoRandom;
587     LARGE_INTEGER time;
588     static ULONG uCounter = 17;
589 
590     if(!pbBuffer || !dwLen)
591     {
592         /* This function always returns TRUE, even if invalid parameters were passed. (verified under WinXP SP2) */
593         return TRUE;
594     }
595 
596     /* Get the first seed from the performance counter */
597     QueryPerformanceCounter(&time);
598     dwSeed = time.LowPart ^ time.HighPart ^ RtlUlongByteSwap(uCounter++);
599 
600     /* We will access the buffer bytewise */
601     pBuffer = (PBYTE)pbBuffer;
602 
603     do
604     {
605         /* Use the pseudo random number generator RtlRandom, which outputs a 4-byte value and a new seed */
606         uPseudoRandom = RtlRandom(&dwSeed);
607 
608         do
609         {
610             /* Get each byte from the pseudo random number and store it in the buffer */
611             *pBuffer = (BYTE)(uPseudoRandom >> 8 * (dwLen % 3) & 0xFF);
612             ++pBuffer;
613         } while(--dwLen % 3);
614     } while(dwLen);
615 
616     return TRUE;
617 }
618 
619 HANDLE KsecDeviceHandle;
620 
621 static
622 NTSTATUS
623 KsecOpenDevice()
624 {
625     UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\KsecDD");
626     OBJECT_ATTRIBUTES ObjectAttributes;
627     IO_STATUS_BLOCK IoStatusBlock;
628     HANDLE DeviceHandle;
629     NTSTATUS Status;
630 
631     InitializeObjectAttributes(&ObjectAttributes,
632                                &DeviceName,
633                                OBJ_CASE_INSENSITIVE,
634                                NULL,
635                                NULL);
636     Status = NtOpenFile(&DeviceHandle,
637                         FILE_READ_DATA | SYNCHRONIZE,
638                         &ObjectAttributes,
639                         &IoStatusBlock,
640                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
641                         FILE_SYNCHRONOUS_IO_NONALERT);
642     if (!NT_SUCCESS(Status))
643     {
644         return Status;
645     }
646 
647     if (InterlockedCompareExchangePointer(&KsecDeviceHandle, DeviceHandle, NULL) != NULL)
648     {
649         NtClose(DeviceHandle);
650     }
651 
652     return STATUS_SUCCESS;
653 }
654 
655 VOID
656 CloseKsecDdHandle(VOID)
657 {
658     /* Check if we already opened a handle to ksecdd */
659     if (KsecDeviceHandle != NULL)
660     {
661         /* Close it */
662         CloseHandle(KsecDeviceHandle);
663         KsecDeviceHandle = NULL;
664     }
665 }
666 
667 static
668 NTSTATUS
669 KsecDeviceIoControl(
670     ULONG IoControlCode,
671     PVOID InputBuffer,
672     SIZE_T InputBufferLength,
673     PVOID OutputBuffer,
674     SIZE_T OutputBufferLength)
675 {
676     IO_STATUS_BLOCK IoStatusBlock;
677     NTSTATUS Status;
678 
679     /* Check if we already have a handle */
680     if (KsecDeviceHandle == NULL)
681     {
682         /* Try to open the device */
683         Status = KsecOpenDevice();
684         if (!NT_SUCCESS(Status))
685         {
686             //ERR("Failed to open handle to KsecDd driver!\n");
687             return Status;
688         }
689     }
690 
691     /* Call the driver */
692     Status = NtDeviceIoControlFile(KsecDeviceHandle,
693                                    NULL,
694                                    NULL,
695                                    NULL,
696                                    &IoStatusBlock,
697                                    IoControlCode,
698                                    InputBuffer,
699                                    InputBufferLength,
700                                    OutputBuffer,
701                                    OutputBufferLength);
702 
703     return Status;
704 }
705 
706 /*
707    These functions have nearly identical prototypes to CryptProtectMemory and CryptUnprotectMemory,
708    in crypt32.dll.
709  */
710 
711 /******************************************************************************
712  * SystemFunction040   (ADVAPI32.@)
713  *
714  * MSDN documents this function as RtlEncryptMemory and declares it in ntsecapi.h.
715  *
716  * PARAMS
717  *  memory [I/O] Pointer to memory to encrypt.
718  *  length [I] Length of region to encrypt in bytes.
719  *  flags  [I] Control whether other processes are able to decrypt the memory.
720  *    RTL_ENCRYPT_OPTION_SAME_PROCESS
721  *    RTL_ENCRYPT_OPTION_CROSS_PROCESS
722  *    RTL_ENCRYPT_OPTION_SAME_LOGON
723  *
724  * RETURNS
725  *  Success: STATUS_SUCCESS
726  *  Failure: NTSTATUS error code
727  *
728  * NOTES
729  *  length must be a multiple of RTL_ENCRYPT_MEMORY_SIZE.
730  *  If flags are specified when encrypting, the same flag value must be given
731  *  when decrypting the memory.
732  */
733 NTSTATUS
734 WINAPI
735 SystemFunction040(
736     _Inout_ PVOID Memory,
737     _In_ ULONG MemoryLength,
738     _In_ ULONG OptionFlags)
739 {
740     ULONG IoControlCode;
741 
742     if (OptionFlags == RTL_ENCRYPT_OPTION_SAME_PROCESS)
743     {
744         IoControlCode = IOCTL_KSEC_ENCRYPT_SAME_PROCESS;
745     }
746     else if (OptionFlags == RTL_ENCRYPT_OPTION_CROSS_PROCESS)
747     {
748         IoControlCode = IOCTL_KSEC_ENCRYPT_CROSS_PROCESS;
749     }
750     else if (OptionFlags == RTL_ENCRYPT_OPTION_SAME_LOGON)
751     {
752         IoControlCode = IOCTL_KSEC_ENCRYPT_SAME_LOGON;
753     }
754     else
755     {
756         return STATUS_INVALID_PARAMETER;
757     }
758 
759     return KsecDeviceIoControl(IoControlCode, Memory, MemoryLength, Memory, MemoryLength);
760 }
761 
762 /******************************************************************************
763  * SystemFunction041  (ADVAPI32.@)
764  *
765  * MSDN documents this function as RtlDecryptMemory and declares it in ntsecapi.h.
766  *
767  * PARAMS
768  *  memory [I/O] Pointer to memory to decrypt.
769  *  length [I] Length of region to decrypt in bytes.
770  *  flags  [I] Control whether other processes are able to decrypt the memory.
771  *    RTL_ENCRYPT_OPTION_SAME_PROCESS
772  *    RTL_ENCRYPT_OPTION_CROSS_PROCESS
773  *    RTL_ENCRYPT_OPTION_SAME_LOGON
774  *
775  * RETURNS
776  *  Success: STATUS_SUCCESS
777  *  Failure: NTSTATUS error code
778  *
779  * NOTES
780  *  length must be a multiple of RTL_ENCRYPT_MEMORY_SIZE.
781  *  If flags are specified when encrypting, the same flag value must be given
782  *  when decrypting the memory.
783  */
784 NTSTATUS
785 WINAPI
786 SystemFunction041(
787     _Inout_ PVOID Memory,
788     _In_ ULONG MemoryLength,
789     _In_ ULONG OptionFlags)
790 {
791     ULONG IoControlCode;
792 
793     if (OptionFlags == RTL_ENCRYPT_OPTION_SAME_PROCESS)
794     {
795         IoControlCode = IOCTL_KSEC_DECRYPT_SAME_PROCESS;
796     }
797     else if (OptionFlags == RTL_ENCRYPT_OPTION_CROSS_PROCESS)
798     {
799         IoControlCode = IOCTL_KSEC_DECRYPT_CROSS_PROCESS;
800     }
801     else if (OptionFlags == RTL_ENCRYPT_OPTION_SAME_LOGON)
802     {
803         IoControlCode = IOCTL_KSEC_DECRYPT_SAME_LOGON;
804     }
805     else
806     {
807         return STATUS_INVALID_PARAMETER;
808     }
809 
810     return KsecDeviceIoControl(IoControlCode, Memory, MemoryLength, Memory, MemoryLength);
811 }
812 
813 /* EOF */
814