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.

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