Source code of Windows XP (NT5)
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.

305 lines
7.4 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(
  62. (PVOID) ContextHandle,
  63. &SessionKey
  64. );
  65. if (! NT_SUCCESS(ntstatus)) {
  66. SCC_LOG1(ERROR,
  67. "ScEncryptPassword: RtlGetUserSessionKeyClient returned "
  68. FORMAT_NTSTATUS "\n", ntstatus);
  69. return ERROR_GEN_FAILURE;
  70. }
  71. //
  72. // Encryption includes the NULL terminator.
  73. //
  74. ClearTextPW.Length = ((DWORD) wcslen(Password) + 1) * sizeof(WCHAR);
  75. ClearTextPW.MaximumLength = ClearTextPW.Length;
  76. ClearTextPW.Buffer = (PVOID) Password;
  77. DataKey.Length = USER_SESSION_KEY_LENGTH;
  78. DataKey.MaximumLength = USER_SESSION_KEY_LENGTH;
  79. DataKey.Buffer = (PVOID) &SessionKey;
  80. EncryptPW.Length = 0;
  81. EncryptPW.MaximumLength = 0;
  82. EncryptPW.Buffer = NULL;
  83. //
  84. // Call RtlEncryptData with 0 length so that it will return the
  85. // required length.
  86. //
  87. ntstatus = RtlEncryptData(
  88. &ClearTextPW,
  89. &DataKey,
  90. &EncryptPW
  91. );
  92. if (ntstatus != STATUS_BUFFER_TOO_SMALL) {
  93. SCC_LOG1(ERROR,
  94. "ScEncryptPassword: RtlEncryptData returned "
  95. FORMAT_NTSTATUS "\n", ntstatus);
  96. return ERROR_GEN_FAILURE;
  97. }
  98. if ((EncryptPW.Buffer = (PVOID) LocalAlloc(
  99. 0,
  100. EncryptPW.Length
  101. )) == NULL) {
  102. SCC_LOG1(ERROR,
  103. "ScEncryptPassword: LocalAlloc failed "
  104. FORMAT_DWORD "\n", GetLastError());
  105. return ERROR_NOT_ENOUGH_MEMORY;
  106. }
  107. EncryptPW.MaximumLength = EncryptPW.Length;
  108. ntstatus = RtlEncryptData(
  109. &ClearTextPW,
  110. &DataKey,
  111. &EncryptPW
  112. );
  113. if (! NT_SUCCESS(ntstatus)) {
  114. SCC_LOG1(ERROR,
  115. "ScEncryptPassword: RtlEncryptData returned "
  116. FORMAT_NTSTATUS "\n", ntstatus);
  117. LocalFree(EncryptPW.Buffer);
  118. return ERROR_GEN_FAILURE;
  119. }
  120. *EncryptedPassword = (LPBYTE) EncryptPW.Buffer;
  121. *EncryptedPasswordSize = EncryptPW.Length;
  122. return NO_ERROR;
  123. }
  124. DWORD
  125. ScDecryptPassword(
  126. IN SC_RPC_HANDLE ContextHandle,
  127. IN LPBYTE EncryptedPassword,
  128. IN DWORD EncryptedPasswordSize,
  129. OUT LPWSTR *Password
  130. )
  131. /*++
  132. Routine Description:
  133. This function decrypts a given encrypted password back to clear
  134. text with the user session key gotten from the RPC context handle.
  135. This is called by the RPC server.
  136. Arguments:
  137. ContextHandle - Supplies the RPC context handle.
  138. EncryptedPassword - Supplies a buffer which contains the encrypted
  139. password.
  140. EncryptedPasswordSize - Supplies the number of bytes in
  141. EncryptedPassword.
  142. Password - Receives a pointer to the memory which contains the
  143. clear text password. This memory must be freed with LocalFree
  144. when done.
  145. Return Value:
  146. NO_ERROR - Successful encryption.
  147. ERROR_NOT_ENOUGH_MEMORY - Failed to allocate the Password buffer.
  148. ERROR_GEN_FAILURE - Any other failures encountered by this function.
  149. --*/
  150. {
  151. NTSTATUS ntstatus;
  152. USER_SESSION_KEY SessionKey;
  153. CYPHER_DATA EncryptPW;
  154. DATA_KEY DataKey;
  155. CLEAR_DATA ClearTextPW;
  156. ntstatus = RtlGetUserSessionKeyServer(
  157. (PVOID) ContextHandle,
  158. &SessionKey
  159. );
  160. if (! NT_SUCCESS(ntstatus)) {
  161. SC_LOG1(ERROR,
  162. "ScDecryptPassword: RtlGetUserSessionKeyClient returned "
  163. FORMAT_NTSTATUS "\n", ntstatus);
  164. return ERROR_GEN_FAILURE;
  165. }
  166. EncryptPW.Length = EncryptedPasswordSize;
  167. EncryptPW.MaximumLength = EncryptedPasswordSize;
  168. EncryptPW.Buffer = (PVOID) EncryptedPassword;
  169. DataKey.Length = USER_SESSION_KEY_LENGTH;
  170. DataKey.MaximumLength = USER_SESSION_KEY_LENGTH;
  171. DataKey.Buffer = (PVOID) &SessionKey;
  172. ClearTextPW.Length = 0;
  173. ClearTextPW.MaximumLength = 0;
  174. ClearTextPW.Buffer = NULL;
  175. //
  176. // Call RtlDecryptData with 0 length so that it will return the
  177. // required length.
  178. //
  179. ntstatus = RtlDecryptData(
  180. &EncryptPW,
  181. &DataKey,
  182. &ClearTextPW
  183. );
  184. if (ntstatus != STATUS_BUFFER_TOO_SMALL) {
  185. if (ntstatus == STATUS_SUCCESS && ClearTextPW.Length == 0) {
  186. //
  187. // Assume empty password
  188. //
  189. *Password = NULL;
  190. return NO_ERROR;
  191. }
  192. SC_LOG1(ERROR,
  193. "ScDecryptPassword: RtlDecryptData returned "
  194. FORMAT_NTSTATUS "\n", ntstatus);
  195. return ERROR_GEN_FAILURE;
  196. }
  197. //
  198. // Allocate exact size needed because NULL terminator is included in
  199. // the encrypted string.
  200. //
  201. if ((ClearTextPW.Buffer = (PVOID) LocalAlloc(
  202. LMEM_ZEROINIT,
  203. ClearTextPW.Length
  204. )) == NULL) {
  205. SC_LOG1(ERROR,
  206. "ScDecryptPassword: LocalAlloc failed "
  207. FORMAT_DWORD "\n", GetLastError());
  208. return ERROR_NOT_ENOUGH_MEMORY;
  209. }
  210. ClearTextPW.MaximumLength = ClearTextPW.Length;
  211. ntstatus = RtlDecryptData(
  212. &EncryptPW,
  213. &DataKey,
  214. &ClearTextPW
  215. );
  216. if (! NT_SUCCESS(ntstatus)) {
  217. SC_LOG1(ERROR,
  218. "ScDecryptPassword: RtlDecryptData returned "
  219. FORMAT_NTSTATUS "\n", ntstatus);
  220. return ERROR_GEN_FAILURE;
  221. }
  222. *Password = (LPWSTR) ClearTextPW.Buffer;
  223. return NO_ERROR;
  224. }