Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

310 lines
7.5 KiB

  1. /*++
  2. Copyright (c) 1991-92 Microsoft Corporation
  3. Module Name:
  4. sccrypt.c
  5. Abstract:
  6. This module provides support routines to encrypt and decrypt
  7. a password.
  8. Author:
  9. Rita Wong (ritaw) 27-Apr-1992
  10. Environment:
  11. Contains NT specific code.
  12. Revision History:
  13. --*/
  14. #include <scpragma.h>
  15. extern "C"
  16. {
  17. #include <nt.h>
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. }
  21. #include <crypt.h>
  22. #include <windef.h> // DWORD (needed by scdebug.h).
  23. #include <winerror.h> // NO_ERROR
  24. #include <winbase.h> // LocalAlloc
  25. #include <stdlib.h>
  26. #include <scdebug.h> // STATIC.
  27. #include <svcctl.h> // SC_RPC_HANDLE
  28. #include <sccrypt.h> // Exported function prototypes
  29. DWORD
  30. ScEncryptPassword(
  31. IN SC_RPC_HANDLE ContextHandle,
  32. IN LPWSTR Password,
  33. OUT LPBYTE *EncryptedPassword,
  34. OUT LPDWORD EncryptedPasswordSize
  35. )
  36. /*++
  37. Routine Description:
  38. This function encrypts a user specified clear text password with
  39. the user session key gotten from the RPC context handle.
  40. This is called by the RPC client.
  41. Arguments:
  42. ContextHandle - Supplies the RPC context handle.
  43. Password - Supplies the user specified password.
  44. EncryptedPassword - Receives a pointer to memory which contains
  45. the encrypted password. This memory must be freed with LocalFree
  46. when done.
  47. EncryptedPasswordSize - Receives the number of bytes of encrypted
  48. password returned.
  49. Return Value:
  50. NO_ERROR - Successful encryption.
  51. ERROR_NOT_ENOUGH_MEMORY - Failed to allocate the EncryptedPassword
  52. buffer.
  53. ERROR_GEN_FAILURE - Any other failures encountered by this function.
  54. --*/
  55. {
  56. NTSTATUS ntstatus;
  57. USER_SESSION_KEY SessionKey;
  58. CLEAR_DATA ClearTextPW;
  59. DATA_KEY DataKey;
  60. CYPHER_DATA EncryptPW;
  61. ntstatus = RtlGetUserSessionKeyClient((PVOID) ContextHandle, &SessionKey);
  62. if (!NT_SUCCESS(ntstatus))
  63. {
  64. SCC_LOG1(ERROR,
  65. "ScEncryptPassword: RtlGetUserSessionKeyClient returned "
  66. FORMAT_NTSTATUS "\n", ntstatus);
  67. return RtlNtStatusToDosErrorNoTeb(ntstatus);
  68. }
  69. //
  70. // Encryption includes the NULL terminator.
  71. //
  72. ClearTextPW.Length = ((DWORD) wcslen(Password) + 1) * sizeof(WCHAR);
  73. ClearTextPW.MaximumLength = ClearTextPW.Length;
  74. ClearTextPW.Buffer = (PVOID) Password;
  75. DataKey.Length = USER_SESSION_KEY_LENGTH;
  76. DataKey.MaximumLength = USER_SESSION_KEY_LENGTH;
  77. DataKey.Buffer = (PVOID) &SessionKey;
  78. EncryptPW.Length = 0;
  79. EncryptPW.MaximumLength = 0;
  80. EncryptPW.Buffer = NULL;
  81. //
  82. // Call RtlEncryptData with 0 length so that it will return the
  83. // required length.
  84. //
  85. ntstatus = RtlEncryptData(
  86. &ClearTextPW,
  87. &DataKey,
  88. &EncryptPW
  89. );
  90. if (ntstatus != STATUS_BUFFER_TOO_SMALL)
  91. {
  92. SCC_LOG1(ERROR,
  93. "ScEncryptPassword: RtlEncryptData returned "
  94. FORMAT_NTSTATUS "\n", ntstatus);
  95. return RtlNtStatusToDosErrorNoTeb(ntstatus);
  96. }
  97. if ((EncryptPW.Buffer = (PVOID) LocalAlloc(0, EncryptPW.Length)) == NULL)
  98. {
  99. SCC_LOG1(ERROR,
  100. "ScEncryptPassword: LocalAlloc failed "
  101. FORMAT_DWORD "\n", GetLastError());
  102. return ERROR_NOT_ENOUGH_MEMORY;
  103. }
  104. EncryptPW.MaximumLength = EncryptPW.Length;
  105. ntstatus = RtlEncryptData(
  106. &ClearTextPW,
  107. &DataKey,
  108. &EncryptPW
  109. );
  110. if (!NT_SUCCESS(ntstatus))
  111. {
  112. SCC_LOG1(ERROR,
  113. "ScEncryptPassword: RtlEncryptData returned "
  114. FORMAT_NTSTATUS "\n", ntstatus);
  115. LocalFree(EncryptPW.Buffer);
  116. return RtlNtStatusToDosErrorNoTeb(ntstatus);
  117. }
  118. *EncryptedPassword = (LPBYTE) EncryptPW.Buffer;
  119. *EncryptedPasswordSize = EncryptPW.Length;
  120. return NO_ERROR;
  121. }
  122. DWORD
  123. ScDecryptPassword(
  124. IN SC_RPC_HANDLE ContextHandle,
  125. IN LPBYTE EncryptedPassword,
  126. IN DWORD EncryptedPasswordSize,
  127. OUT LPWSTR *Password
  128. )
  129. /*++
  130. Routine Description:
  131. This function decrypts a given encrypted password back to clear
  132. text with the user session key gotten from the RPC context handle.
  133. This is called by the RPC server.
  134. Arguments:
  135. ContextHandle - Supplies the RPC context handle.
  136. EncryptedPassword - Supplies a buffer which contains the encrypted
  137. password.
  138. EncryptedPasswordSize - Supplies the number of bytes in
  139. EncryptedPassword.
  140. Password - Receives a pointer to the memory which contains the
  141. clear text password. This memory must be freed with LocalFree
  142. when done.
  143. Return Value:
  144. NO_ERROR - Successful encryption.
  145. ERROR_NOT_ENOUGH_MEMORY - Failed to allocate the Password buffer.
  146. ERROR_GEN_FAILURE - Any other failures encountered by this function.
  147. --*/
  148. {
  149. NTSTATUS ntstatus;
  150. USER_SESSION_KEY SessionKey;
  151. CYPHER_DATA EncryptPW;
  152. DATA_KEY DataKey;
  153. CLEAR_DATA ClearTextPW;
  154. ntstatus = RtlGetUserSessionKeyServer((PVOID) ContextHandle, &SessionKey);
  155. if (!NT_SUCCESS(ntstatus))
  156. {
  157. SC_LOG1(ERROR,
  158. "ScDecryptPassword: RtlGetUserSessionKeyClient returned "
  159. FORMAT_NTSTATUS "\n", ntstatus);
  160. return RtlNtStatusToDosErrorNoTeb(ntstatus);
  161. }
  162. EncryptPW.Length = EncryptedPasswordSize;
  163. EncryptPW.MaximumLength = EncryptedPasswordSize;
  164. EncryptPW.Buffer = (PVOID) EncryptedPassword;
  165. DataKey.Length = USER_SESSION_KEY_LENGTH;
  166. DataKey.MaximumLength = USER_SESSION_KEY_LENGTH;
  167. DataKey.Buffer = (PVOID) &SessionKey;
  168. ClearTextPW.Length = 0;
  169. ClearTextPW.MaximumLength = 0;
  170. ClearTextPW.Buffer = NULL;
  171. //
  172. // Call RtlDecryptData with 0 length so that it will return the
  173. // required length.
  174. //
  175. ntstatus = RtlDecryptData(
  176. &EncryptPW,
  177. &DataKey,
  178. &ClearTextPW
  179. );
  180. if (ntstatus != STATUS_BUFFER_TOO_SMALL)
  181. {
  182. if (ntstatus == STATUS_SUCCESS && ClearTextPW.Length == 0)
  183. {
  184. //
  185. // Assume empty password
  186. //
  187. *Password = NULL;
  188. return NO_ERROR;
  189. }
  190. SC_LOG1(ERROR,
  191. "ScDecryptPassword: RtlDecryptData returned "
  192. FORMAT_NTSTATUS "\n", ntstatus);
  193. return RtlNtStatusToDosErrorNoTeb(ntstatus);
  194. }
  195. //
  196. // Allocate exact size needed because NULL terminator is included in
  197. // the encrypted string.
  198. //
  199. if ((ClearTextPW.Buffer = (PVOID) LocalAlloc(LMEM_ZEROINIT, ClearTextPW.Length)) == NULL)
  200. {
  201. SC_LOG1(ERROR,
  202. "ScDecryptPassword: LocalAlloc failed "
  203. FORMAT_DWORD "\n", GetLastError());
  204. return ERROR_NOT_ENOUGH_MEMORY;
  205. }
  206. ClearTextPW.MaximumLength = ClearTextPW.Length;
  207. ntstatus = RtlDecryptData(
  208. &EncryptPW,
  209. &DataKey,
  210. &ClearTextPW
  211. );
  212. if (!NT_SUCCESS(ntstatus))
  213. {
  214. SC_LOG1(ERROR,
  215. "ScDecryptPassword: RtlDecryptData returned "
  216. FORMAT_NTSTATUS "\n", ntstatus);
  217. return RtlNtStatusToDosErrorNoTeb(ntstatus);
  218. }
  219. *Password = (LPWSTR) ClearTextPW.Buffer;
  220. return NO_ERROR;
  221. }