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.

372 lines
8.1 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // File: passwd.c
  4. //
  5. // Contents: Password hashing routine
  6. //
  7. //
  8. // History: 12-20-91, RichardW, created
  9. //
  10. //------------------------------------------------------------------------
  11. #ifndef WIN32_CHICAGO
  12. #include "krbprgma.h"
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <kerbcomm.h>
  17. #include <kerbcon.h>
  18. #include <kerberr.h>
  19. #else // WIN32_CHICAGO
  20. #include <kerb.hxx>
  21. #include <kerbp.h>
  22. #endif // WIN32_CHICAGO
  23. #include "wincrypt.h"
  24. //
  25. // Globals used for allowing the replacement of the StringToKey functions
  26. //
  27. HCRYPTPROV KerbGlobalStrToKeyProvider = 0;
  28. //+-------------------------------------------------------------------------
  29. //
  30. // Function: CheckForOutsideStringToKey
  31. //
  32. // Synopsis: Call CryptoAPI to query to see if a CSP is registered
  33. // of the type PROV_REPLACE_OWF.
  34. //
  35. // Effects:
  36. //
  37. // Arguments:
  38. //
  39. // Requires:
  40. //
  41. // Returns: STATUS_SUCCESS if it succeeds, otherwise STATUS_UNSUCCESSFUL
  42. //
  43. // Notes:
  44. //
  45. //
  46. //--------------------------------------------------------------------------
  47. VOID
  48. CheckForOutsideStringToKey()
  49. {
  50. HCRYPTPROV hProv = 0;
  51. KerbGlobalStrToKeyProvider = 0;
  52. //
  53. // Try to acquire a context to a CSP which is used for OWF replacement
  54. //
  55. if (!CryptAcquireContext(&hProv,
  56. NULL,
  57. NULL,
  58. PROV_REPLACE_OWF,
  59. CRYPT_VERIFYCONTEXT))
  60. {
  61. return;
  62. }
  63. KerbGlobalStrToKeyProvider = hProv;
  64. return;
  65. }
  66. //+-------------------------------------------------------------------------
  67. //
  68. // Function: UseOutsideStringToKey
  69. //
  70. // Synopsis: Calls the CSP to do an outside StringToKey function
  71. // using the hashing entry points of CryptoAPI.
  72. //
  73. // Effects:
  74. //
  75. // Arguments:
  76. //
  77. // Requires:
  78. //
  79. // Returns:
  80. //
  81. // Notes:
  82. //
  83. //
  84. //--------------------------------------------------------------------------
  85. NTSTATUS
  86. UseOutsideStringToKey(
  87. IN PUNICODE_STRING pPassword,
  88. IN ULONG cbKey,
  89. OUT PUCHAR pbKey
  90. )
  91. {
  92. HCRYPTHASH hHash = 0;
  93. ULONG cb;
  94. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  95. //
  96. // create the hash
  97. //
  98. if (!CryptCreateHash(KerbGlobalStrToKeyProvider,
  99. CALG_HASH_REPLACE_OWF,
  100. 0,
  101. 0,
  102. &hHash))
  103. {
  104. goto Cleanup;
  105. }
  106. //
  107. // hash the password
  108. //
  109. if (!CryptHashData(hHash,
  110. (PUCHAR)pPassword->Buffer,
  111. pPassword->Length,
  112. 0))
  113. {
  114. if (NTE_BAD_DATA == GetLastError())
  115. {
  116. Status = NTE_BAD_DATA;
  117. }
  118. goto Cleanup;
  119. }
  120. //
  121. // Get the HP_HASHVAL, this is the key
  122. //
  123. cb = cbKey;
  124. if (!CryptGetHashParam(hHash,
  125. HP_HASHVAL,
  126. pbKey,
  127. &cb,
  128. 0))
  129. {
  130. if (NTE_BAD_LEN == GetLastError())
  131. {
  132. Status = NTE_BAD_DATA;
  133. }
  134. goto Cleanup;
  135. }
  136. Status = STATUS_SUCCESS;
  137. Cleanup:
  138. if (0 != hHash)
  139. {
  140. CryptDestroyHash(hHash);
  141. }
  142. return Status;
  143. }
  144. //+-------------------------------------------------------------------------
  145. //
  146. // Function: KerbHashPasswordEx
  147. //
  148. // Synopsis: Hashes a password into a kerberos encryption key
  149. //
  150. // Effects:
  151. //
  152. // Arguments:
  153. //
  154. // Requires:
  155. //
  156. // Returns:
  157. //
  158. // Notes:
  159. //
  160. //
  161. //--------------------------------------------------------------------------
  162. KERBERR NTAPI
  163. KerbHashPasswordEx(
  164. IN PUNICODE_STRING Password,
  165. IN PUNICODE_STRING PrincipalName,
  166. IN ULONG EncryptionType,
  167. OUT PKERB_ENCRYPTION_KEY Key
  168. )
  169. {
  170. PCRYPTO_SYSTEM CryptoSystem;
  171. NTSTATUS Status;
  172. KERBERR KerbErr;
  173. UNICODE_STRING CombinedName;
  174. ULONG Temp = 0;
  175. BOOLEAN fUseDefaultStringToKey = TRUE;
  176. RtlInitUnicodeString(
  177. &CombinedName,
  178. NULL
  179. );
  180. Key->keyvalue.value = NULL;
  181. //
  182. // Locate the crypto system
  183. //
  184. Status = CDLocateCSystem(
  185. EncryptionType,
  186. &CryptoSystem
  187. );
  188. if (!NT_SUCCESS(Status))
  189. {
  190. return(KDC_ERR_ETYPE_NOTSUPP);
  191. }
  192. //
  193. // Check to see if the principal name must be appended to the password
  194. //
  195. if ((CryptoSystem->Attributes & CSYSTEM_USE_PRINCIPAL_NAME) != 0)
  196. {
  197. Temp = (ULONG) Password->Length + (ULONG) PrincipalName->Length;
  198. if (Temp > (USHORT) -1)
  199. {
  200. KerbErr = KRB_ERR_GENERIC;
  201. goto Cleanup;
  202. }
  203. CombinedName.Length = (USHORT) Temp;
  204. CombinedName.MaximumLength = CombinedName.Length;
  205. CombinedName.Buffer = (LPWSTR) MIDL_user_allocate(CombinedName.Length);
  206. if (CombinedName.Buffer == NULL)
  207. {
  208. KerbErr = KRB_ERR_GENERIC;
  209. goto Cleanup;
  210. }
  211. RtlCopyMemory(
  212. CombinedName.Buffer,
  213. Password->Buffer,
  214. Password->Length
  215. );
  216. RtlCopyMemory(
  217. CombinedName.Buffer + Password->Length/sizeof(WCHAR),
  218. PrincipalName->Buffer,
  219. PrincipalName->Length
  220. );
  221. }
  222. else
  223. {
  224. CombinedName = *Password;
  225. }
  226. //
  227. // Get the preferred checksum
  228. //
  229. Key->keyvalue.value = (PUCHAR) MIDL_user_allocate(CryptoSystem->KeySize);
  230. if (Key->keyvalue.value == NULL)
  231. {
  232. KerbErr = KRB_ERR_GENERIC;
  233. goto Cleanup;
  234. }
  235. //
  236. // Check if we need to use an outside supplied string to key
  237. // calculation
  238. //
  239. if (0 != KerbGlobalStrToKeyProvider)
  240. {
  241. Status = UseOutsideStringToKey(
  242. &CombinedName,
  243. CryptoSystem->KeySize,
  244. Key->keyvalue.value
  245. );
  246. if (NT_SUCCESS(Status))
  247. {
  248. fUseDefaultStringToKey = FALSE;
  249. }
  250. //
  251. // the function will return STATUS_UNSUCCESSFUL indicates not to fall
  252. // back to the typical string to key function.
  253. //
  254. else if (STATUS_UNSUCCESSFUL == Status)
  255. {
  256. KerbErr = KRB_ERR_GENERIC;
  257. goto Cleanup;
  258. }
  259. }
  260. if (fUseDefaultStringToKey)
  261. {
  262. Status = CryptoSystem->HashString(
  263. &CombinedName,
  264. Key->keyvalue.value
  265. );
  266. if (!NT_SUCCESS(Status))
  267. {
  268. KerbErr = KRB_ERR_GENERIC;
  269. goto Cleanup;
  270. }
  271. }
  272. Key->keyvalue.length = CryptoSystem->KeySize;
  273. Key->keytype = EncryptionType;
  274. KerbErr = KDC_ERR_NONE;
  275. Cleanup:
  276. if ((CombinedName.Buffer != Password->Buffer) &&
  277. (CombinedName.Buffer != NULL))
  278. {
  279. MIDL_user_free(CombinedName.Buffer);
  280. }
  281. if (!KERB_SUCCESS(KerbErr) && Key->keyvalue.value != NULL)
  282. {
  283. MIDL_user_free(Key->keyvalue.value);
  284. Key->keyvalue.value = NULL;
  285. }
  286. return(KerbErr);
  287. }
  288. //+-------------------------------------------------------------------------
  289. //
  290. // Function: KerbHashPassword
  291. //
  292. // Synopsis: Hashes a password into a kerberos encryption key
  293. //
  294. // Effects:
  295. //
  296. // Arguments:
  297. //
  298. // Requires:
  299. //
  300. // Returns:
  301. //
  302. // Notes:
  303. //
  304. //
  305. //--------------------------------------------------------------------------
  306. KERBERR NTAPI
  307. KerbHashPassword(
  308. IN PUNICODE_STRING Password,
  309. IN ULONG EncryptionType,
  310. OUT PKERB_ENCRYPTION_KEY Key
  311. )
  312. {
  313. UNICODE_STRING TempString;
  314. RtlInitUnicodeString(
  315. &TempString,
  316. NULL
  317. );
  318. return( KerbHashPasswordEx(
  319. Password,
  320. &TempString, // no principal name
  321. EncryptionType,
  322. Key
  323. ) );
  324. }