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.

867 lines
18 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. encrypt.c
  5. Abstract:
  6. Provides a set of functions dealing with OWF hash values of passwords.
  7. Author:
  8. Ovidiu Temereanca (ovidiut) 14-Mar-2000
  9. Revision History:
  10. <alias> <date> <comments>
  11. --*/
  12. //
  13. // Includes
  14. //
  15. #include <windows.h>
  16. #include "encrypt.h"
  17. //
  18. // Strings
  19. //
  20. // None
  21. //
  22. // Constants
  23. //
  24. // None
  25. //
  26. // Macros
  27. //
  28. // None
  29. //
  30. // Types
  31. //
  32. // None
  33. //
  34. // Globals
  35. //
  36. // None
  37. //
  38. // Macro expansion list
  39. //
  40. // None
  41. //
  42. // Private function prototypes
  43. //
  44. // None
  45. //
  46. // Macro expansion definition
  47. //
  48. // None
  49. //
  50. // Code
  51. //
  52. PSTR
  53. ConvertW2A (
  54. IN PCWSTR Unicode,
  55. IN UINT CodePage
  56. )
  57. /*++
  58. Routine Description:
  59. Converts an UNICODE string to it's ANSI equivalent, using the given codepage.
  60. Arguments:
  61. Unicode - Specifies the string to be converted
  62. CodePage - Specifies the code page used for conversion
  63. Return value:
  64. A pointer to the ANSI string if successful, or NULL on error. Call GetLastError()
  65. to determine the cause of failure.
  66. --*/
  67. {
  68. PSTR ansi = NULL;
  69. DWORD rc;
  70. rc = WideCharToMultiByte (
  71. CodePage,
  72. WC_NO_BEST_FIT_CHARS,
  73. Unicode,
  74. -1,
  75. NULL,
  76. 0,
  77. NULL,
  78. NULL
  79. );
  80. if (rc || *Unicode == L'\0') {
  81. ansi = (PSTR)HeapAlloc (GetProcessHeap (), 0, (rc + 1) * sizeof (CHAR));
  82. if (ansi) {
  83. rc = WideCharToMultiByte (
  84. CodePage,
  85. WC_NO_BEST_FIT_CHARS,
  86. Unicode,
  87. -1,
  88. ansi,
  89. rc + 1,
  90. NULL,
  91. NULL
  92. );
  93. if (!(rc || *Unicode == L'\0')) {
  94. rc = GetLastError ();
  95. HeapFree (GetProcessHeap (), 0, (PVOID)ansi);
  96. ansi = NULL;
  97. SetLastError (rc);
  98. }
  99. }
  100. }
  101. return ansi;
  102. }
  103. PWSTR
  104. ConvertA2W (
  105. IN PCSTR Ansi,
  106. IN UINT CodePage
  107. )
  108. /*++
  109. Routine Description:
  110. Converts an ANSI string to it's UNICODE equivalent, using the given codepage.
  111. Arguments:
  112. Ansi - Specifies the string to be converted
  113. CodePage - Specifies the code page used for conversion
  114. Return value:
  115. A pointer to the UNICODE string if successful, or NULL on error. Call GetLastError()
  116. to determine the cause of failure.
  117. --*/
  118. {
  119. PWSTR unicode = NULL;
  120. DWORD rc;
  121. rc = MultiByteToWideChar (
  122. CodePage,
  123. MB_ERR_INVALID_CHARS,
  124. Ansi,
  125. -1,
  126. NULL,
  127. 0
  128. );
  129. if (rc || *Ansi == '\0') {
  130. unicode = (PWSTR) HeapAlloc (GetProcessHeap (), 0, (rc + 1) * sizeof (WCHAR));
  131. if (unicode) {
  132. rc = MultiByteToWideChar (
  133. CodePage,
  134. MB_ERR_INVALID_CHARS,
  135. Ansi,
  136. -1,
  137. unicode,
  138. rc + 1
  139. );
  140. if (!(rc || *Ansi == '\0')) {
  141. rc = GetLastError ();
  142. HeapFree (GetProcessHeap (), 0, (PVOID)unicode);
  143. unicode = NULL;
  144. SetLastError (rc);
  145. }
  146. }
  147. }
  148. return unicode;
  149. }
  150. /*++
  151. Routine Description:
  152. EncodeLmOwfPassword converts a password to the LM OWF format.
  153. Arguments:
  154. Password - Specifies the password to be hashed
  155. OwfPassword - Receives the hash form
  156. ComplexNtPassword - Receives TRUE if the password is complex (longer than 14 chars);
  157. optional
  158. Return value:
  159. TRUE on successful hashing
  160. --*/
  161. BOOL
  162. EncodeLmOwfPasswordA (
  163. IN PCSTR AnsiPassword,
  164. OUT PLM_OWF_PASSWORD OwfPassword,
  165. OUT PBOOL ComplexNtPassword OPTIONAL
  166. )
  167. {
  168. CHAR oemPassword[LM_PASSWORD_SIZE_MAX];
  169. CHAR password[LM_PASSWORD_SIZE_MAX];
  170. BOOL complex;
  171. if (!AnsiPassword) {
  172. AnsiPassword = "";
  173. }
  174. complex = lstrlenA (AnsiPassword) > LM20_PWLEN;
  175. if (ComplexNtPassword) {
  176. *ComplexNtPassword = complex;
  177. }
  178. if (complex) {
  179. password[0] = 0;
  180. } else {
  181. lstrcpyA (oemPassword, AnsiPassword);
  182. CharUpperA (oemPassword);
  183. CharToOemA (oemPassword, password);
  184. }
  185. return CalculateLmOwfPassword (password, OwfPassword);
  186. }
  187. BOOL
  188. EncodeLmOwfPasswordW (
  189. IN PCWSTR Password,
  190. OUT PLM_OWF_PASSWORD OwfPassword,
  191. OUT PBOOL ComplexNtPassword OPTIONAL
  192. )
  193. {
  194. PSTR ansi;
  195. BOOL b = FALSE;
  196. if (!Password) {
  197. Password = L"";
  198. }
  199. ansi = ConvertW2A (Password, CP_ACP);
  200. if (ansi) {
  201. b = EncodeLmOwfPasswordA (ansi, OwfPassword, ComplexNtPassword);
  202. HeapFree (GetProcessHeap (), 0, (PVOID)ansi);
  203. }
  204. return b;
  205. }
  206. /*++
  207. Routine Description:
  208. StringEncodeLmOwfPassword converts a password to the LM OWF format, expressed as
  209. a string of characters (each byte converted to 2 hex digits).
  210. Arguments:
  211. Password - Specifies the password to be hashed
  212. EncodedPassword - Receives the hash form, as a string of hex digits
  213. ComplexNtPassword - Receives TRUE if the password is complex (longer than 14 chars);
  214. optional
  215. Return value:
  216. TRUE on successful hashing
  217. --*/
  218. BOOL
  219. StringEncodeLmOwfPasswordA (
  220. IN PCSTR Password,
  221. OUT PSTR EncodedPassword,
  222. OUT PBOOL ComplexNtPassword OPTIONAL
  223. )
  224. {
  225. LM_OWF_PASSWORD owfPassword;
  226. PBYTE start;
  227. PBYTE end;
  228. PSTR dest;
  229. if (!EncodeLmOwfPasswordA (Password, &owfPassword, ComplexNtPassword)) {
  230. return FALSE;
  231. }
  232. //
  233. // each byte will be represented as 2 chars, so it will be twice as long
  234. //
  235. start = (PBYTE)&owfPassword;
  236. end = start + sizeof (LM_OWF_PASSWORD);
  237. dest = EncodedPassword;
  238. while (start < end) {
  239. dest += wsprintfA (dest, "%02x", (UINT)(*start));
  240. start++;
  241. }
  242. return TRUE;
  243. }
  244. BOOL
  245. StringEncodeLmOwfPasswordW (
  246. IN PCWSTR Password,
  247. OUT PWSTR EncodedPassword,
  248. OUT PBOOL ComplexNtPassword OPTIONAL
  249. )
  250. {
  251. LM_OWF_PASSWORD owfPassword;
  252. PBYTE start;
  253. PBYTE end;
  254. PWSTR dest;
  255. if (!EncodeLmOwfPasswordW (Password, &owfPassword, ComplexNtPassword)) {
  256. return FALSE;
  257. }
  258. //
  259. // each byte will be represented as 2 chars, so it will be twice as long
  260. //
  261. start = (PBYTE)&owfPassword;
  262. end = start + sizeof (LM_OWF_PASSWORD);
  263. dest = EncodedPassword;
  264. while (start < end) {
  265. dest += wsprintfW (dest, L"%02x", (UINT)(*start));
  266. start++;
  267. }
  268. return TRUE;
  269. }
  270. /*++
  271. Routine Description:
  272. EncodeNtOwfPassword converts a password to the NT OWF format.
  273. Arguments:
  274. Password - Specifies the password to be hashed
  275. OwfPassword - Receives the hash form
  276. Return value:
  277. TRUE on successful hashing
  278. --*/
  279. BOOL
  280. EncodeNtOwfPasswordA (
  281. IN PCSTR Password,
  282. OUT PNT_OWF_PASSWORD OwfPassword
  283. )
  284. {
  285. PWSTR unicode;
  286. BOOL b = FALSE;
  287. unicode = ConvertA2W (Password, CP_ACP);
  288. if (unicode) {
  289. b = EncodeNtOwfPasswordW (unicode, OwfPassword);
  290. HeapFree (GetProcessHeap (), 0, unicode);
  291. }
  292. return b;
  293. }
  294. BOOL
  295. EncodeNtOwfPasswordW (
  296. IN PCWSTR Password,
  297. OUT PNT_OWF_PASSWORD OwfPassword
  298. )
  299. {
  300. NT_PASSWORD pwd;
  301. if (Password) {
  302. pwd.Buffer = (PWSTR)Password;
  303. pwd.Length = (USHORT)lstrlenW (Password) * (USHORT)sizeof (WCHAR);
  304. pwd.MaximumLength = pwd.Length + (USHORT) sizeof (WCHAR);
  305. } else {
  306. ZeroMemory (&pwd, sizeof (pwd));
  307. }
  308. return CalculateNtOwfPassword (&pwd, OwfPassword);
  309. }
  310. /*++
  311. Routine Description:
  312. StringEncodeNtOwfPassword converts a password to the NT OWF format, expressed as
  313. a string of characters (each byte converted to 2 hex digits).
  314. Arguments:
  315. Password - Specifies the password to be hashed
  316. EncodedPassword - Receives the hash form, as a string of hex digits
  317. Return value:
  318. TRUE on successful hashing
  319. --*/
  320. BOOL
  321. StringEncodeNtOwfPasswordA (
  322. IN PCSTR Password,
  323. OUT PSTR EncodedPassword
  324. )
  325. {
  326. NT_OWF_PASSWORD owfPassword;
  327. PBYTE start;
  328. PBYTE end;
  329. PSTR dest;
  330. if (!EncodeNtOwfPasswordA (Password, &owfPassword)) {
  331. return FALSE;
  332. }
  333. //
  334. // each byte will be represented as 2 chars, so it will be twice as long
  335. //
  336. start = (PBYTE)&owfPassword;
  337. end = start + sizeof (NT_OWF_PASSWORD);
  338. dest = EncodedPassword;
  339. while (start < end) {
  340. dest += wsprintfA (dest, "%02x", (UINT)(*start));
  341. start++;
  342. }
  343. return TRUE;
  344. }
  345. BOOL
  346. StringEncodeNtOwfPasswordW (
  347. IN PCWSTR Password,
  348. OUT PWSTR EncodedPassword
  349. )
  350. {
  351. NT_OWF_PASSWORD owfPassword;
  352. PBYTE start;
  353. PBYTE end;
  354. PWSTR dest;
  355. if (!EncodeNtOwfPasswordW (Password, &owfPassword)) {
  356. return FALSE;
  357. }
  358. //
  359. // each byte will be represented as 2 chars, so it will be twice as long
  360. //
  361. start = (PBYTE)&owfPassword;
  362. end = start + sizeof (NT_OWF_PASSWORD);
  363. dest = EncodedPassword;
  364. while (start < end) {
  365. dest += wsprintfW (dest, L"%02x", (UINT)(*start));
  366. start++;
  367. }
  368. return TRUE;
  369. }
  370. /*++
  371. Routine Description:
  372. StringDecodeLmOwfPassword converts a hashed password to the LM OWF format
  373. Arguments:
  374. EncodedOwfPassword - Specifies the password to be hashed
  375. OwfPassword - Receives the hash form
  376. Return value:
  377. TRUE on successful decoding of the string
  378. --*/
  379. BOOL
  380. StringDecodeLmOwfPasswordA (
  381. IN PCSTR EncodedOwfPassword,
  382. OUT PLM_OWF_PASSWORD OwfPassword
  383. )
  384. {
  385. DWORD nible;
  386. PCSTR p;
  387. PBYTE dest;
  388. CHAR ch;
  389. if (lstrlenA (EncodedOwfPassword) != sizeof (LM_OWF_PASSWORD) * 2) {
  390. return FALSE;
  391. }
  392. nible = 0;
  393. p = EncodedOwfPassword;
  394. dest = (PBYTE)OwfPassword;
  395. ch = 0;
  396. while (*p) {
  397. if (!((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F'))) {
  398. return FALSE;
  399. }
  400. if (*p <= '9') {
  401. ch |= *p - '0';
  402. } else if (*p <= 'F') {
  403. ch |= *p - 'A' + 10;
  404. } else {
  405. ch |= *p - 'a' + 10;
  406. }
  407. p++;
  408. nible++;
  409. if ((nible & 1) == 0) {
  410. *dest++ = ch;
  411. ch = 0;
  412. } else {
  413. ch <<= 4;
  414. }
  415. }
  416. return TRUE;
  417. }
  418. BOOL
  419. StringDecodeLmOwfPasswordW (
  420. IN PCWSTR EncodedOwfPassword,
  421. OUT PLM_OWF_PASSWORD OwfPassword
  422. )
  423. {
  424. DWORD nible;
  425. PCWSTR p;
  426. PBYTE dest;
  427. WCHAR ch;
  428. if (lstrlenW (EncodedOwfPassword) != sizeof (LM_OWF_PASSWORD) * 2) {
  429. return FALSE;
  430. }
  431. nible = 0;
  432. p = EncodedOwfPassword;
  433. dest = (PBYTE)OwfPassword;
  434. ch = 0;
  435. while (*p) {
  436. if (!((*p >= L'0' && *p <= L'9') || (*p >= L'a' && *p <= L'f') || (*p >= L'A' && *p <= L'F'))) {
  437. return FALSE;
  438. }
  439. if (*p <= L'9') {
  440. ch |= *p - L'0';
  441. } else if (*p <= L'F') {
  442. ch |= *p - L'A' + 10;
  443. } else {
  444. ch |= *p - L'a' + 10;
  445. }
  446. p++;
  447. nible++;
  448. if ((nible & 1) == 0) {
  449. *dest++ = (BYTE)ch;
  450. ch = 0;
  451. } else {
  452. ch <<= 4;
  453. }
  454. }
  455. return TRUE;
  456. }
  457. /*++
  458. Routine Description:
  459. StringDecodeNtOwfPassword converts a hashed password to the NT OWF format
  460. Arguments:
  461. EncodedOwfPassword - Specifies the password to be hashed
  462. OwfPassword - Receives the hash form
  463. Return value:
  464. TRUE on successful decoding of the string
  465. --*/
  466. BOOL
  467. StringDecodeNtOwfPasswordA (
  468. IN PCSTR EncodedOwfPassword,
  469. OUT PNT_OWF_PASSWORD OwfPassword
  470. )
  471. {
  472. DWORD nible;
  473. PCSTR p;
  474. PBYTE dest;
  475. CHAR ch;
  476. if (lstrlenA (EncodedOwfPassword) != sizeof (NT_OWF_PASSWORD) * 2) {
  477. return FALSE;
  478. }
  479. nible = 0;
  480. p = EncodedOwfPassword;
  481. dest = (PBYTE)OwfPassword;
  482. ch = 0;
  483. while (*p) {
  484. if (!((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F'))) {
  485. return FALSE;
  486. }
  487. if (*p <= '9') {
  488. ch |= *p - '0';
  489. } else if (*p <= 'F') {
  490. ch |= *p - 'A' + 10;
  491. } else {
  492. ch |= *p - 'a' + 10;
  493. }
  494. p++;
  495. nible++;
  496. if ((nible & 1) == 0) {
  497. *dest++ = ch;
  498. ch = 0;
  499. } else {
  500. ch <<= 4;
  501. }
  502. }
  503. return TRUE;
  504. }
  505. BOOL
  506. StringDecodeNtOwfPasswordW (
  507. IN PCWSTR EncodedOwfPassword,
  508. OUT PNT_OWF_PASSWORD OwfPassword
  509. )
  510. {
  511. DWORD nible;
  512. PCWSTR p;
  513. PBYTE dest;
  514. WCHAR ch;
  515. if (lstrlenW (EncodedOwfPassword) != sizeof (NT_OWF_PASSWORD) * 2) {
  516. return FALSE;
  517. }
  518. nible = 0;
  519. p = EncodedOwfPassword;
  520. dest = (PBYTE)OwfPassword;
  521. ch = 0;
  522. while (*p) {
  523. if (!((*p >= L'0' && *p <= L'9') || (*p >= L'a' && *p <= L'f') || (*p >= L'A' && *p <= L'F'))) {
  524. return FALSE;
  525. }
  526. if (*p <= L'9') {
  527. ch |= *p - L'0';
  528. } else if (*p <= L'F') {
  529. ch |= *p - L'A' + 10;
  530. } else {
  531. ch |= *p - L'a' + 10;
  532. }
  533. p++;
  534. nible++;
  535. if ((nible & 1) == 0) {
  536. *dest++ = (BYTE)ch;
  537. ch = 0;
  538. } else {
  539. ch <<= 4;
  540. }
  541. }
  542. return TRUE;
  543. }
  544. /*++
  545. Routine Description:
  546. StringEncodeOwfPassword converts a password to its hashed format, expressed as
  547. a string of characters (each byte converted to 2 hex digits). The result is
  548. obtained joining the 2 substrings, one representing LM OWF and the other NT OWF
  549. Arguments:
  550. Password - Specifies the password to be hashed
  551. EncodedPassword - Receives the hash form, as a string of hex digits
  552. ComplexNtPassword - Receives TRUE if the password is complex (longer than 14 chars);
  553. optional
  554. Return value:
  555. TRUE on successful hashing
  556. --*/
  557. BOOL
  558. StringEncodeOwfPasswordA (
  559. IN PCSTR Password,
  560. OUT PSTR EncodedPassword,
  561. OUT PBOOL ComplexNtPassword OPTIONAL
  562. )
  563. {
  564. return StringEncodeLmOwfPasswordA (Password, EncodedPassword, ComplexNtPassword) &&
  565. StringEncodeNtOwfPasswordA (Password, EncodedPassword + STRING_ENCODED_LM_OWF_PWD_LENGTH);
  566. }
  567. BOOL
  568. StringEncodeOwfPasswordW (
  569. IN PCWSTR Password,
  570. OUT PWSTR EncodedPassword,
  571. OUT PBOOL ComplexNtPassword OPTIONAL
  572. )
  573. {
  574. return StringEncodeLmOwfPasswordW (Password, EncodedPassword, ComplexNtPassword) &&
  575. StringEncodeNtOwfPasswordW (Password, EncodedPassword + STRING_ENCODED_LM_OWF_PWD_LENGTH);
  576. }
  577. /*++
  578. Routine Description:
  579. StringDecodeOwfPassword decodes a password's LM OWF and NT OWF forms from its hashed format,
  580. expressed as a string of hex digits.
  581. Arguments:
  582. EncodedOwfPassword - Specifies the password to be hashed
  583. LmOwfPassword - Receives the LM OWF hash form
  584. NtOwfPassword - Receives the NT OWF hash form
  585. ComplexNtPassword - Receives TRUE if the password is complex (longer than 14 chars);
  586. optional
  587. Return value:
  588. TRUE on successful hashing
  589. --*/
  590. BOOL
  591. StringDecodeOwfPasswordA (
  592. IN PCSTR EncodedOwfPassword,
  593. OUT PLM_OWF_PASSWORD LmOwfPassword,
  594. OUT PNT_OWF_PASSWORD NtOwfPassword,
  595. OUT PBOOL ComplexNtPassword OPTIONAL
  596. )
  597. {
  598. PSTR p;
  599. CHAR ch;
  600. BOOL b;
  601. CHAR buffer[sizeof (LM_OWF_PASSWORD) * 2 + sizeof (NT_OWF_PASSWORD) * 2 + 2];
  602. LM_OWF_PASSWORD lmNull;
  603. NT_OWF_PASSWORD ntNull;
  604. if (lstrlenA (EncodedOwfPassword) != sizeof (LM_OWF_PASSWORD) * 2 + sizeof (NT_OWF_PASSWORD) * 2) {
  605. return FALSE;
  606. }
  607. lstrcpyA (buffer, EncodedOwfPassword);
  608. //
  609. // split the string in two
  610. //
  611. p = buffer + (sizeof (LM_OWF_PASSWORD) * 2);
  612. ch = *p;
  613. *p = 0;
  614. b = StringDecodeLmOwfPasswordA (EncodedOwfPassword, LmOwfPassword);
  615. *p = ch;
  616. if (b) {
  617. b = StringDecodeNtOwfPasswordA (p, NtOwfPassword);
  618. }
  619. if (b && ComplexNtPassword) {
  620. b = EncodeLmOwfPasswordA ("", &lmNull, NULL) && EncodeNtOwfPasswordA ("", &ntNull);
  621. if (b) {
  622. //
  623. // it's a complex password if the LM hash is for NULL pwd
  624. // but NT hash it's not
  625. //
  626. *ComplexNtPassword = CompareLmPasswords (LmOwfPassword, &lmNull) == 0 &&
  627. CompareNtPasswords (NtOwfPassword, &ntNull) != 0;
  628. }
  629. }
  630. return b;
  631. }
  632. BOOL
  633. StringDecodeOwfPasswordW (
  634. IN PCWSTR EncodedOwfPassword,
  635. OUT PLM_OWF_PASSWORD LmOwfPassword,
  636. OUT PNT_OWF_PASSWORD NtOwfPassword,
  637. OUT PBOOL ComplexNtPassword OPTIONAL
  638. )
  639. {
  640. PWSTR p;
  641. WCHAR ch;
  642. BOOL b;
  643. WCHAR buffer[sizeof (LM_OWF_PASSWORD) * 2 + sizeof (NT_OWF_PASSWORD) * 2 + 2];
  644. LM_OWF_PASSWORD lmNull;
  645. NT_OWF_PASSWORD ntNull;
  646. if (lstrlenW (EncodedOwfPassword) != sizeof (LM_OWF_PASSWORD) * 2 + sizeof (NT_OWF_PASSWORD) * 2) {
  647. return FALSE;
  648. }
  649. lstrcpyW (buffer, EncodedOwfPassword);
  650. //
  651. // split the string in two
  652. //
  653. p = buffer + (sizeof (LM_OWF_PASSWORD) * 2);
  654. ch = *p;
  655. *p = 0;
  656. b = StringDecodeLmOwfPasswordW (buffer, LmOwfPassword);
  657. *p = ch;
  658. if (b) {
  659. b = StringDecodeNtOwfPasswordW (p, NtOwfPassword);
  660. }
  661. if (b && ComplexNtPassword) {
  662. b = EncodeLmOwfPasswordW (L"", &lmNull, NULL) && EncodeNtOwfPasswordW (L"", &ntNull);
  663. if (b) {
  664. //
  665. // it's a complex password if the LM hash is for NULL pwd
  666. // but NT hash it's not
  667. //
  668. *ComplexNtPassword = CompareLmPasswords (LmOwfPassword, &lmNull) == 0 &&
  669. CompareNtPasswords (NtOwfPassword, &ntNull) != 0;
  670. }
  671. }
  672. return b;
  673. }