crypt.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380
  1. /*++
  2. Copyright (c) 2015 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. crypt.c
  9. Abstract:
  10. This module implements the crypt library functions.
  11. Author:
  12. Evan Green 6-Mar-2015
  13. Environment:
  14. User Mode C Library
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include "cryptp.h"
  20. #include <minoca/lib/minocaos.h>
  21. #include <minoca/lib/crypto.h>
  22. #include <alloca.h>
  23. #include <errno.h>
  24. #include <sys/param.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <unistd.h>
  28. //
  29. // ---------------------------------------------------------------- Definitions
  30. //
  31. #define CRYPT_ALPHABET \
  32. "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
  33. //
  34. // The number of rounds in SHA-256 crypt can be specified.
  35. //
  36. #define CRYPT_SHA256_ROUNDS_DEFAULT 5000
  37. #define CRYPT_SHA256_ROUNDS_MIN 1000
  38. #define CRYPT_SHA256_ROUNDS_MAX 999999999
  39. #define CRYPT_SHA256_SALT_MAX 16
  40. //
  41. // The number of rounds in SHA-512 crypt can be specified.
  42. //
  43. #define CRYPT_SHA512_ROUNDS_DEFAULT 5000
  44. #define CRYPT_SHA512_ROUNDS_MIN 1000
  45. #define CRYPT_SHA512_ROUNDS_MAX 999999999
  46. #define CRYPT_SHA512_SALT_MAX 16
  47. //
  48. // ------------------------------------------------------ Data Type Definitions
  49. //
  50. typedef
  51. PSTR
  52. (*PCRYPT_FUNCTION) (
  53. PSTR Key,
  54. PSTR Salt
  55. );
  56. /*++
  57. Routine Description:
  58. This routine defines the format for a crypt algorithm function.
  59. Arguments:
  60. Key - Supplies the key, a user's plaintext password.
  61. Salt - Supplies the ID and salt information.
  62. Return Value:
  63. Returns a pointer to the encrypted password (plus ID and salt information
  64. in cases where an alternate mechanism is used). This is a static buffer,
  65. which may be overwritten by subsequent calls to crypt.
  66. --*/
  67. /*++
  68. Structure Description:
  69. This structure stores the tuple of a crypt hashing algorithm's ID and
  70. function pointer.
  71. Members:
  72. Name - Stores a pointer to a string containing the name of the algorithm.
  73. Id - Stores the ID string that needs to appear at the beginning of the
  74. salt to match this algorithm.
  75. CryptFunction - Stores a pointer to a function used to encrypt the data.
  76. --*/
  77. typedef struct _CRYPT_FORMAT {
  78. PSTR Name;
  79. PSTR Id;
  80. PCRYPT_FUNCTION CryptFunction;
  81. } CRYPT_FORMAT, *PCRYPT_FORMAT;
  82. //
  83. // ----------------------------------------------- Internal Function Prototypes
  84. //
  85. PSTR
  86. ClpCryptMd5 (
  87. PSTR Key,
  88. PSTR Salt
  89. );
  90. PSTR
  91. ClpCryptSha256 (
  92. PSTR Key,
  93. PSTR Salt
  94. );
  95. PSTR
  96. ClpCryptSha256Reentrant (
  97. PSTR Key,
  98. PSTR Salt,
  99. PSTR Buffer,
  100. UINTN BufferLength
  101. );
  102. PSTR
  103. ClpCryptSha512 (
  104. PSTR Key,
  105. PSTR Salt
  106. );
  107. PSTR
  108. ClpCryptSha512Reentrant (
  109. PSTR Key,
  110. PSTR Salt,
  111. PSTR Buffer,
  112. UINTN BufferLength
  113. );
  114. VOID
  115. ClpCryptConvertToCharacters (
  116. PSTR *StringPointer,
  117. UCHAR ValueHigh,
  118. UCHAR ValueMid,
  119. UCHAR ValueLow,
  120. INTN Size,
  121. PUINTN BufferLength
  122. );
  123. //
  124. // -------------------------------------------------------------------- Globals
  125. //
  126. CRYPT_FORMAT ClCryptFormats[] = {
  127. {"md5", "$1$", ClpCryptMd5},
  128. {"sha256", "$5$", ClpCryptSha256},
  129. {"sha512", "$6$", ClpCryptSha512},
  130. {NULL, NULL, NULL}
  131. };
  132. //
  133. // Store the static buffer containing crypt results.
  134. //
  135. char ClCryptBuffer[120];
  136. //
  137. // ------------------------------------------------------------------ Functions
  138. //
  139. LIBCRYPT_API
  140. char *
  141. crypt (
  142. const char *Key,
  143. const char *Salt
  144. )
  145. /*++
  146. Routine Description:
  147. This routine encrypts a user's password using various encryption/hashing
  148. standards. The default is DES, which is fairly weak and subject to
  149. dictionary attacks.
  150. Arguments:
  151. Key - Supplies the key, a user's plaintext password.
  152. Salt - Supplies a two character salt to use to perterb the results. If this
  153. string starts with a $ and a number, alternate hashing algorithms are
  154. selected. The format is $id$salt$encrypted. ID can be 1 for MD5, 5 for
  155. SHA-256, or 6 for SHA-512.
  156. Return Value:
  157. Returns a pointer to the encrypted password (plus ID and salt information
  158. in cases where an alternate mechanism is used). This is a static buffer,
  159. which may be overwritten by subsequent calls to crypt.
  160. --*/
  161. {
  162. PCRYPT_FORMAT Format;
  163. Format = ClCryptFormats;
  164. while (Format->CryptFunction != NULL) {
  165. if ((Format->Id != NULL) && (strstr(Salt, Format->Id) == Salt)) {
  166. return Format->CryptFunction((PSTR)Key, (PSTR)Salt);
  167. }
  168. Format += 1;
  169. }
  170. return ClpCryptSha512((PSTR)Key, (PSTR)Salt);
  171. }
  172. //
  173. // --------------------------------------------------------- Internal Functions
  174. //
  175. PSTR
  176. ClpCryptMd5 (
  177. PSTR Key,
  178. PSTR Salt
  179. )
  180. /*++
  181. Routine Description:
  182. This routine encrypts a user's password using the MD5 hash algorithm.
  183. Arguments:
  184. Key - Supplies the key, a user's plaintext password.
  185. Salt - Supplies the ID and salt information.
  186. Return Value:
  187. Returns a pointer to the encrypted password, plus ID and salt information.
  188. This is a static buffer, which may be overwritten by subsequent calls to
  189. crypt.
  190. --*/
  191. {
  192. int Bits;
  193. UINTN BufferSize;
  194. MD5_CONTEXT Context;
  195. MD5_CONTEXT Context2;
  196. UCHAR Hash[MD5_HASH_SIZE];
  197. size_t HashLength;
  198. PSTR Id;
  199. size_t IdLength;
  200. int Iteration;
  201. size_t KeyLength;
  202. char *Result;
  203. const char *SaltEnd;
  204. size_t SaltLength;
  205. Id = "$1$";
  206. IdLength = strlen(Id);
  207. KeyLength = strlen(Key);
  208. //
  209. // Skip the ID part of the salt.
  210. //
  211. if (strncmp(Salt, Id, IdLength) == 0) {
  212. Salt += IdLength;
  213. }
  214. //
  215. // Compute the salt length, capped at 8 characters.
  216. //
  217. SaltEnd = Salt;
  218. SaltLength = 0;
  219. while ((*SaltEnd != '\0') && (*SaltEnd != '$') && (SaltLength < 8)) {
  220. SaltLength += 1;
  221. SaltEnd += 1;
  222. }
  223. //
  224. // Add the password, the magic string, and the salt.
  225. //
  226. CyMd5Initialize(&Context);
  227. CyMd5AddContent(&Context, Key, KeyLength);
  228. CyMd5AddContent(&Context, Id, IdLength);
  229. CyMd5AddContent(&Context, Salt, SaltLength);
  230. //
  231. // Take the MD5 of password, salt, password, and add in that hash for an
  232. // amount that corresponds to the length of the password.
  233. //
  234. CyMd5Initialize(&Context2);
  235. CyMd5AddContent(&Context2, Key, KeyLength);
  236. CyMd5AddContent(&Context2, Salt, SaltLength);
  237. CyMd5AddContent(&Context2, Key, KeyLength);
  238. CyMd5GetHash(&Context2, Hash);
  239. for (HashLength = KeyLength;
  240. HashLength >= MD5_HASH_SIZE;
  241. HashLength -= MD5_HASH_SIZE) {
  242. CyMd5AddContent(&Context, Hash, MD5_HASH_SIZE);
  243. }
  244. CyMd5AddContent(&Context, Hash, HashLength);
  245. //
  246. // Don't leave security treasures floating around.
  247. //
  248. memset(Hash, 0, MD5_HASH_SIZE);
  249. //
  250. // Add in either a zero or the first character of the password depending
  251. // on how bits in the length of the password are set.
  252. //
  253. Bits = KeyLength;
  254. while (Bits != 0) {
  255. if ((Bits & 0x1) != 0) {
  256. CyMd5AddContent(&Context, Hash, 1);
  257. } else {
  258. CyMd5AddContent(&Context, Key, 1);
  259. }
  260. Bits = Bits >> 1;
  261. }
  262. strcpy(ClCryptBuffer, Id);
  263. strncat(ClCryptBuffer, Salt, SaltLength);
  264. strcat(ClCryptBuffer, "$");
  265. CyMd5GetHash(&Context, Hash);
  266. //
  267. // Do some more iterations just to slow things down a little.
  268. //
  269. for (Iteration = 0; Iteration < 1000; Iteration += 1) {
  270. CyMd5Initialize(&Context2);
  271. if ((Iteration & 0x1) != 0) {
  272. CyMd5AddContent(&Context2, Key, KeyLength);
  273. } else {
  274. CyMd5AddContent(&Context2, Hash, MD5_HASH_SIZE);
  275. }
  276. if ((Iteration % 3) != 0) {
  277. CyMd5AddContent(&Context2, Salt, SaltLength);
  278. }
  279. if ((Iteration % 7) != 0) {
  280. CyMd5AddContent(&Context2, Key, KeyLength);
  281. }
  282. if ((Iteration & 0x1) != 0) {
  283. CyMd5AddContent(&Context2, Hash, MD5_HASH_SIZE);
  284. } else {
  285. CyMd5AddContent(&Context2, Key, KeyLength);
  286. }
  287. CyMd5GetHash(&Context2, Hash);
  288. }
  289. Result = ClCryptBuffer + strlen(ClCryptBuffer);
  290. BufferSize = sizeof(ClCryptBuffer) - ((UINTN)Result - (UINTN)ClCryptBuffer);
  291. ClpCryptConvertToCharacters(&Result,
  292. Hash[0],
  293. Hash[6],
  294. Hash[12],
  295. 4,
  296. &BufferSize);
  297. ClpCryptConvertToCharacters(&Result,
  298. Hash[1],
  299. Hash[7],
  300. Hash[13],
  301. 4,
  302. &BufferSize);
  303. ClpCryptConvertToCharacters(&Result,
  304. Hash[2],
  305. Hash[8],
  306. Hash[14],
  307. 4,
  308. &BufferSize);
  309. ClpCryptConvertToCharacters(&Result,
  310. Hash[3],
  311. Hash[9],
  312. Hash[15],
  313. 4,
  314. &BufferSize);
  315. ClpCryptConvertToCharacters(&Result,
  316. Hash[4],
  317. Hash[10],
  318. Hash[5],
  319. 4,
  320. &BufferSize);
  321. ClpCryptConvertToCharacters(&Result, 0, 0, Hash[11], 2, &BufferSize);
  322. *Result = '\0';
  323. //
  324. // No security droppings.
  325. //
  326. SECURITY_ZERO(Hash, MD5_HASH_SIZE);
  327. return ClCryptBuffer;
  328. }
  329. PSTR
  330. ClpCryptSha256 (
  331. PSTR Key,
  332. PSTR Salt
  333. )
  334. /*++
  335. Routine Description:
  336. This routine encrypts a user's password using the SHA-256 hash algorithm.
  337. Arguments:
  338. Key - Supplies the key, a user's plaintext password.
  339. Salt - Supplies the ID and salt information.
  340. Return Value:
  341. Returns a pointer to the encrypted password, plus ID and salt information.
  342. This is a static buffer, which may be overwritten by subsequent calls to
  343. crypt.
  344. --*/
  345. {
  346. PSTR Result;
  347. Result = ClpCryptSha256Reentrant(Key,
  348. Salt,
  349. ClCryptBuffer,
  350. sizeof(ClCryptBuffer));
  351. return Result;
  352. }
  353. PSTR
  354. ClpCryptSha256Reentrant (
  355. PSTR Key,
  356. PSTR Salt,
  357. PSTR Buffer,
  358. UINTN BufferLength
  359. )
  360. /*++
  361. Routine Description:
  362. This routine encrypts a user's password using the SHA-256 hash algorithm.
  363. Arguments:
  364. Key - Supplies the key, a user's plaintext password.
  365. Salt - Supplies the ID and salt information.
  366. Buffer - Supplies a pointer where the result will be returned.
  367. BufferLength - Supplies the length of the buffer in bytes.
  368. Return Value:
  369. Returns a pointer to the encrypted password, plus ID and salt information.
  370. --*/
  371. {
  372. PSTR AfterScan;
  373. UINTN Bits;
  374. SHA256_CONTEXT Context;
  375. SHA256_CONTEXT Context2;
  376. PSTR CurrentByte;
  377. UCHAR Hash[SHA256_HASH_SIZE];
  378. UCHAR Hash2[SHA256_HASH_SIZE];
  379. UINTN HashLength;
  380. PSTR Id;
  381. UINTN IdLength;
  382. UINTN Iteration;
  383. UINTN KeyLength;
  384. PSTR PBytes;
  385. UINTN Rounds;
  386. PSTR RoundsPrefix;
  387. UINTN RoundsPrefixLength;
  388. BOOL RoundsSpecified;
  389. PSTR RoundsString;
  390. UINTN SaltLength;
  391. UINTN SaltRounds;
  392. PSTR SBytes;
  393. UINTN StringLength;
  394. Id = "$5$";
  395. IdLength = strlen(Id);
  396. Rounds = CRYPT_SHA256_ROUNDS_DEFAULT;
  397. RoundsPrefix = "rounds=";
  398. RoundsPrefixLength = strlen(RoundsPrefix);
  399. RoundsSpecified = FALSE;
  400. //
  401. // Move over the salt ID.
  402. //
  403. if (strncmp(Salt, Id, IdLength) == 0) {
  404. Salt += IdLength;
  405. }
  406. if (strncmp(Salt, RoundsPrefix, RoundsPrefixLength) == 0) {
  407. RoundsString = Salt + RoundsPrefixLength;
  408. SaltRounds = strtoul(RoundsString, &AfterScan, 10);
  409. if (*AfterScan == '$') {
  410. Salt = AfterScan + 1;
  411. Rounds = SaltRounds;
  412. if (Rounds < CRYPT_SHA256_ROUNDS_MIN) {
  413. Rounds = CRYPT_SHA256_ROUNDS_MIN;
  414. } else if (Rounds > CRYPT_SHA256_ROUNDS_MAX) {
  415. Rounds = CRYPT_SHA256_ROUNDS_MAX;
  416. }
  417. RoundsSpecified = TRUE;
  418. }
  419. }
  420. SaltLength = strcspn(Salt, "$");
  421. if (SaltLength > CRYPT_SHA256_SALT_MAX) {
  422. SaltLength = CRYPT_SHA256_SALT_MAX;
  423. }
  424. KeyLength = strlen(Key);
  425. CySha256Initialize(&Context);
  426. CySha256AddContent(&Context, Key, KeyLength);
  427. CySha256AddContent(&Context, Salt, SaltLength);
  428. //
  429. // In a different context, add the key, salt, and key again.
  430. //
  431. CySha256Initialize(&Context2);
  432. CySha256AddContent(&Context2, Key, KeyLength);
  433. CySha256AddContent(&Context2, Salt, SaltLength);
  434. CySha256AddContent(&Context2, Key, KeyLength);
  435. CySha256GetHash(&Context2, Hash);
  436. //
  437. // For each character of the key, add the alternate sum.
  438. //
  439. for (HashLength = KeyLength;
  440. HashLength >= SHA256_HASH_SIZE;
  441. HashLength -= SHA256_HASH_SIZE) {
  442. CySha256AddContent(&Context, Hash, SHA256_HASH_SIZE);
  443. }
  444. CySha256AddContent(&Context, Hash, HashLength);
  445. //
  446. // For the bits in the key length, add in either the hash or the key,
  447. // depending on the bit value.
  448. //
  449. for (Bits = KeyLength; Bits > 0; Bits >>= 1) {
  450. if ((Bits & 0x1) != 0) {
  451. CySha256AddContent(&Context, Hash, SHA256_HASH_SIZE);
  452. } else {
  453. CySha256AddContent(&Context, Key, KeyLength);
  454. }
  455. }
  456. CySha256GetHash(&Context, Hash);
  457. //
  458. // Compute another alternate hash. For every byte in the password add the
  459. // password.
  460. //
  461. CySha256Initialize(&Context2);
  462. for (Iteration = 0; Iteration < KeyLength; Iteration += 1) {
  463. CySha256AddContent(&Context2, Key, KeyLength);
  464. }
  465. CySha256GetHash(&Context2, Hash2);
  466. //
  467. // Create a P-Sequence.
  468. //
  469. PBytes = alloca(KeyLength);
  470. CurrentByte = PBytes;
  471. for (HashLength = KeyLength;
  472. HashLength >= SHA256_HASH_SIZE;
  473. HashLength -= SHA256_HASH_SIZE) {
  474. memcpy(CurrentByte, Hash2, SHA256_HASH_SIZE);
  475. CurrentByte += SHA256_HASH_SIZE;
  476. }
  477. memcpy(CurrentByte, Hash2, HashLength);
  478. //
  479. // Begin computation of the S-Sequence.
  480. //
  481. CySha256Initialize(&Context2);
  482. for (Iteration = 0; Iteration < 16 + Hash[0]; Iteration += 1) {
  483. CySha256AddContent(&Context2, Salt, SaltLength);
  484. }
  485. CySha256GetHash(&Context2, Hash2);
  486. //
  487. // Create and compute the S-Sequence.
  488. //
  489. SBytes = alloca(SaltLength);
  490. CurrentByte = SBytes;
  491. for (HashLength = SaltLength;
  492. HashLength >= SHA256_HASH_SIZE;
  493. HashLength -= SHA256_HASH_SIZE) {
  494. memcpy(CurrentByte, Hash2, SHA256_HASH_SIZE);
  495. }
  496. memcpy(CurrentByte, Hash2, HashLength);
  497. //
  498. // Re-crunch the hash for the given rounds to make things computationally
  499. // expensive.
  500. //
  501. for (Iteration = 0; Iteration < Rounds; Iteration += 1) {
  502. CySha256Initialize(&Context);
  503. if ((Iteration & 0x1) != 0) {
  504. CySha256AddContent(&Context, PBytes, KeyLength);
  505. } else {
  506. CySha256AddContent(&Context, Hash, SHA256_HASH_SIZE);
  507. }
  508. if ((Iteration % 3) != 0) {
  509. CySha256AddContent(&Context, SBytes, SaltLength);
  510. }
  511. if ((Iteration % 7) != 0) {
  512. CySha256AddContent(&Context, PBytes, KeyLength);
  513. }
  514. if ((Iteration & 0x1) != 0) {
  515. CySha256AddContent(&Context, Hash, SHA256_HASH_SIZE);
  516. } else {
  517. CySha256AddContent(&Context, PBytes, KeyLength);
  518. }
  519. CySha256GetHash(&Context, Hash);
  520. }
  521. //
  522. // The heavy lifting is done. Start to create the output string.
  523. //
  524. CurrentByte = stpncpy(Buffer, Id, BufferLength);
  525. if (BufferLength >= IdLength) {
  526. BufferLength -= IdLength;
  527. } else {
  528. BufferLength = 0;
  529. }
  530. if (RoundsSpecified != FALSE) {
  531. StringLength = snprintf(CurrentByte,
  532. BufferLength,
  533. "%s%zu$",
  534. RoundsPrefix,
  535. Rounds);
  536. CurrentByte += StringLength;
  537. if (BufferLength >= StringLength) {
  538. BufferLength -= StringLength;
  539. } else {
  540. BufferLength = 0;
  541. }
  542. }
  543. CurrentByte = stpncpy(CurrentByte, Salt, MIN(BufferLength, SaltLength));
  544. if (BufferLength >= SaltLength) {
  545. BufferLength -= SaltLength;
  546. } else {
  547. BufferLength = 0;
  548. }
  549. if (BufferLength > 0) {
  550. *CurrentByte = '$';
  551. CurrentByte += 1;
  552. BufferLength -= 1;
  553. }
  554. ClpCryptConvertToCharacters(&CurrentByte,
  555. Hash[0],
  556. Hash[10],
  557. Hash[20],
  558. 4,
  559. &BufferLength);
  560. ClpCryptConvertToCharacters(&CurrentByte,
  561. Hash[21],
  562. Hash[1],
  563. Hash[11],
  564. 4,
  565. &BufferLength);
  566. ClpCryptConvertToCharacters(&CurrentByte,
  567. Hash[12],
  568. Hash[22],
  569. Hash[2],
  570. 4,
  571. &BufferLength);
  572. ClpCryptConvertToCharacters(&CurrentByte,
  573. Hash[3],
  574. Hash[13],
  575. Hash[23],
  576. 4,
  577. &BufferLength);
  578. ClpCryptConvertToCharacters(&CurrentByte,
  579. Hash[24],
  580. Hash[4],
  581. Hash[14],
  582. 4,
  583. &BufferLength);
  584. ClpCryptConvertToCharacters(&CurrentByte,
  585. Hash[15],
  586. Hash[25],
  587. Hash[5],
  588. 4,
  589. &BufferLength);
  590. ClpCryptConvertToCharacters(&CurrentByte,
  591. Hash[6],
  592. Hash[16],
  593. Hash[26],
  594. 4,
  595. &BufferLength);
  596. ClpCryptConvertToCharacters(&CurrentByte,
  597. Hash[27],
  598. Hash[7],
  599. Hash[17],
  600. 4,
  601. &BufferLength);
  602. ClpCryptConvertToCharacters(&CurrentByte,
  603. Hash[18],
  604. Hash[28],
  605. Hash[8],
  606. 4,
  607. &BufferLength);
  608. ClpCryptConvertToCharacters(&CurrentByte,
  609. Hash[9],
  610. Hash[19],
  611. Hash[29],
  612. 4,
  613. &BufferLength);
  614. ClpCryptConvertToCharacters(&CurrentByte,
  615. 0,
  616. Hash[31],
  617. Hash[30],
  618. 3,
  619. &BufferLength);
  620. if (BufferLength == 0) {
  621. errno = ERANGE;
  622. Buffer = NULL;
  623. } else {
  624. *CurrentByte = '\0';
  625. }
  626. //
  627. // Clear things out to avoid leaving security context around.
  628. //
  629. SECURITY_ZERO(Hash, SHA256_HASH_SIZE);
  630. SECURITY_ZERO(Hash2, SHA256_HASH_SIZE);
  631. SECURITY_ZERO(PBytes, KeyLength);
  632. SECURITY_ZERO(SBytes, SaltLength);
  633. SECURITY_ZERO(&Context, sizeof(Context));
  634. SECURITY_ZERO(&Context2, sizeof(Context2));
  635. return Buffer;
  636. }
  637. PSTR
  638. ClpCryptSha512 (
  639. PSTR Key,
  640. PSTR Salt
  641. )
  642. /*++
  643. Routine Description:
  644. This routine encrypts a user's password using the SHA-512 hash algorithm.
  645. Arguments:
  646. Key - Supplies the key, a user's plaintext password.
  647. Salt - Supplies the ID and salt information.
  648. Return Value:
  649. Returns a pointer to the encrypted password, plus ID and salt information.
  650. This is a static buffer, which may be overwritten by subsequent calls to
  651. crypt.
  652. --*/
  653. {
  654. PSTR Result;
  655. Result = ClpCryptSha512Reentrant(Key,
  656. Salt,
  657. ClCryptBuffer,
  658. sizeof(ClCryptBuffer));
  659. return Result;
  660. }
  661. PSTR
  662. ClpCryptSha512Reentrant (
  663. PSTR Key,
  664. PSTR Salt,
  665. PSTR Buffer,
  666. UINTN BufferLength
  667. )
  668. /*++
  669. Routine Description:
  670. This routine encrypts a user's password using the SHA-512 hash algorithm.
  671. Arguments:
  672. Key - Supplies the key, a user's plaintext password.
  673. Salt - Supplies the ID and salt information.
  674. Buffer - Supplies a pointer where the result will be returned.
  675. BufferLength - Supplies the length of the buffer in bytes.
  676. Return Value:
  677. Returns a pointer to the encrypted password, plus ID and salt information.
  678. --*/
  679. {
  680. PSTR AfterScan;
  681. UINTN Bits;
  682. SHA512_CONTEXT Context;
  683. SHA512_CONTEXT Context2;
  684. PSTR CurrentByte;
  685. UCHAR Hash[SHA512_HASH_SIZE];
  686. UCHAR Hash2[SHA512_HASH_SIZE];
  687. UINTN HashLength;
  688. PSTR Id;
  689. UINTN IdLength;
  690. UINTN Iteration;
  691. UINTN KeyLength;
  692. PSTR PBytes;
  693. UINTN Rounds;
  694. PSTR RoundsPrefix;
  695. UINTN RoundsPrefixLength;
  696. BOOL RoundsSpecified;
  697. PSTR RoundsString;
  698. UINTN SaltLength;
  699. UINTN SaltRounds;
  700. PSTR SBytes;
  701. UINTN StringLength;
  702. Id = "$6$";
  703. IdLength = strlen(Id);
  704. Rounds = CRYPT_SHA512_ROUNDS_DEFAULT;
  705. RoundsPrefix = "rounds=";
  706. RoundsPrefixLength = strlen(RoundsPrefix);
  707. RoundsSpecified = FALSE;
  708. //
  709. // Move over the salt ID.
  710. //
  711. if (strncmp(Salt, Id, IdLength) == 0) {
  712. Salt += IdLength;
  713. }
  714. if (strncmp(Salt, RoundsPrefix, RoundsPrefixLength) == 0) {
  715. RoundsString = Salt + RoundsPrefixLength;
  716. SaltRounds = strtoul(RoundsString, &AfterScan, 10);
  717. if (*AfterScan == '$') {
  718. Salt = AfterScan + 1;
  719. Rounds = SaltRounds;
  720. if (Rounds < CRYPT_SHA512_ROUNDS_MIN) {
  721. Rounds = CRYPT_SHA512_ROUNDS_MIN;
  722. } else if (Rounds > CRYPT_SHA512_ROUNDS_MAX) {
  723. Rounds = CRYPT_SHA512_ROUNDS_MAX;
  724. }
  725. RoundsSpecified = TRUE;
  726. }
  727. }
  728. SaltLength = strcspn(Salt, "$");
  729. if (SaltLength > CRYPT_SHA512_SALT_MAX) {
  730. SaltLength = CRYPT_SHA512_SALT_MAX;
  731. }
  732. KeyLength = strlen(Key);
  733. CySha512Initialize(&Context);
  734. CySha512AddContent(&Context, Key, KeyLength);
  735. CySha512AddContent(&Context, Salt, SaltLength);
  736. //
  737. // In a different context, add the key, salt, and key again.
  738. //
  739. CySha512Initialize(&Context2);
  740. CySha512AddContent(&Context2, Key, KeyLength);
  741. CySha512AddContent(&Context2, Salt, SaltLength);
  742. CySha512AddContent(&Context2, Key, KeyLength);
  743. CySha512GetHash(&Context2, Hash);
  744. //
  745. // For each character of the key, add the alternate sum.
  746. //
  747. for (HashLength = KeyLength;
  748. HashLength > SHA512_HASH_SIZE;
  749. HashLength -= SHA512_HASH_SIZE) {
  750. CySha512AddContent(&Context, Hash, SHA512_HASH_SIZE);
  751. }
  752. CySha512AddContent(&Context, Hash, HashLength);
  753. //
  754. // For the bits in the key length, add in either the hash or the key,
  755. // depending on the bit value.
  756. //
  757. for (Bits = KeyLength; Bits > 0; Bits >>= 1) {
  758. if ((Bits & 0x1) != 0) {
  759. CySha512AddContent(&Context, Hash, SHA512_HASH_SIZE);
  760. } else {
  761. CySha512AddContent(&Context, Key, KeyLength);
  762. }
  763. }
  764. CySha512GetHash(&Context, Hash);
  765. //
  766. // Compute another alternate hash. For every byte in the password add the
  767. // password.
  768. //
  769. CySha512Initialize(&Context2);
  770. for (Iteration = 0; Iteration < KeyLength; Iteration += 1) {
  771. CySha512AddContent(&Context2, Key, KeyLength);
  772. }
  773. CySha512GetHash(&Context2, Hash2);
  774. //
  775. // Create a P-Sequence.
  776. //
  777. PBytes = alloca(KeyLength);
  778. CurrentByte = PBytes;
  779. for (HashLength = KeyLength;
  780. HashLength >= SHA512_HASH_SIZE;
  781. HashLength -= SHA512_HASH_SIZE) {
  782. memcpy(CurrentByte, Hash2, SHA512_HASH_SIZE);
  783. CurrentByte += SHA512_HASH_SIZE;
  784. }
  785. memcpy(CurrentByte, Hash2, HashLength);
  786. //
  787. // Begin computation of the S-Sequence.
  788. //
  789. CySha512Initialize(&Context2);
  790. for (Iteration = 0; Iteration < 16 + Hash[0]; Iteration += 1) {
  791. CySha512AddContent(&Context2, Salt, SaltLength);
  792. }
  793. CySha512GetHash(&Context2, Hash2);
  794. //
  795. // Create and compute the S-Sequence.
  796. //
  797. SBytes = alloca(SaltLength);
  798. CurrentByte = SBytes;
  799. for (HashLength = SaltLength;
  800. HashLength >= SHA512_HASH_SIZE;
  801. HashLength -= SHA512_HASH_SIZE) {
  802. memcpy(CurrentByte, Hash2, SHA512_HASH_SIZE);
  803. }
  804. memcpy(CurrentByte, Hash2, HashLength);
  805. //
  806. // Re-crunch the hash for the given rounds to make things computationally
  807. // expensive.
  808. //
  809. for (Iteration = 0; Iteration < Rounds; Iteration += 1) {
  810. CySha512Initialize(&Context);
  811. if ((Iteration & 0x1) != 0) {
  812. CySha512AddContent(&Context, PBytes, KeyLength);
  813. } else {
  814. CySha512AddContent(&Context, Hash, SHA512_HASH_SIZE);
  815. }
  816. if ((Iteration % 3) != 0) {
  817. CySha512AddContent(&Context, SBytes, SaltLength);
  818. }
  819. if ((Iteration % 7) != 0) {
  820. CySha512AddContent(&Context, PBytes, KeyLength);
  821. }
  822. if ((Iteration & 0x1) != 0) {
  823. CySha512AddContent(&Context, Hash, SHA512_HASH_SIZE);
  824. } else {
  825. CySha512AddContent(&Context, PBytes, KeyLength);
  826. }
  827. CySha512GetHash(&Context, Hash);
  828. }
  829. //
  830. // The heavy lifting is done. Start to create the output string.
  831. //
  832. CurrentByte = stpncpy(Buffer, Id, BufferLength);
  833. if (BufferLength >= IdLength) {
  834. BufferLength -= IdLength;
  835. } else {
  836. BufferLength = 0;
  837. }
  838. if (RoundsSpecified != FALSE) {
  839. StringLength = snprintf(CurrentByte,
  840. BufferLength,
  841. "%s%zu$",
  842. RoundsPrefix,
  843. Rounds);
  844. CurrentByte += StringLength;
  845. if (BufferLength >= StringLength) {
  846. BufferLength -= StringLength;
  847. } else {
  848. BufferLength = 0;
  849. }
  850. }
  851. CurrentByte = stpncpy(CurrentByte, Salt, MIN(BufferLength, SaltLength));
  852. if (BufferLength >= SaltLength) {
  853. BufferLength -= SaltLength;
  854. } else {
  855. BufferLength = 0;
  856. }
  857. if (BufferLength > 0) {
  858. *CurrentByte = '$';
  859. CurrentByte += 1;
  860. BufferLength -= 1;
  861. }
  862. ClpCryptConvertToCharacters(&CurrentByte,
  863. Hash[0],
  864. Hash[21],
  865. Hash[42],
  866. 4,
  867. &BufferLength);
  868. ClpCryptConvertToCharacters(&CurrentByte,
  869. Hash[22],
  870. Hash[43],
  871. Hash[1],
  872. 4,
  873. &BufferLength);
  874. ClpCryptConvertToCharacters(&CurrentByte,
  875. Hash[44],
  876. Hash[2],
  877. Hash[23],
  878. 4,
  879. &BufferLength);
  880. ClpCryptConvertToCharacters(&CurrentByte,
  881. Hash[3],
  882. Hash[24],
  883. Hash[45],
  884. 4,
  885. &BufferLength);
  886. ClpCryptConvertToCharacters(&CurrentByte,
  887. Hash[25],
  888. Hash[46],
  889. Hash[4],
  890. 4,
  891. &BufferLength);
  892. ClpCryptConvertToCharacters(&CurrentByte,
  893. Hash[47],
  894. Hash[5],
  895. Hash[26],
  896. 4,
  897. &BufferLength);
  898. ClpCryptConvertToCharacters(&CurrentByte,
  899. Hash[6],
  900. Hash[27],
  901. Hash[48],
  902. 4,
  903. &BufferLength);
  904. ClpCryptConvertToCharacters(&CurrentByte,
  905. Hash[28],
  906. Hash[49],
  907. Hash[7],
  908. 4,
  909. &BufferLength);
  910. ClpCryptConvertToCharacters(&CurrentByte,
  911. Hash[50],
  912. Hash[8],
  913. Hash[29],
  914. 4,
  915. &BufferLength);
  916. ClpCryptConvertToCharacters(&CurrentByte,
  917. Hash[9],
  918. Hash[30],
  919. Hash[51],
  920. 4,
  921. &BufferLength);
  922. ClpCryptConvertToCharacters(&CurrentByte,
  923. Hash[31],
  924. Hash[52],
  925. Hash[10],
  926. 4,
  927. &BufferLength);
  928. ClpCryptConvertToCharacters(&CurrentByte,
  929. Hash[53],
  930. Hash[11],
  931. Hash[32],
  932. 4,
  933. &BufferLength);
  934. ClpCryptConvertToCharacters(&CurrentByte,
  935. Hash[12],
  936. Hash[33],
  937. Hash[54],
  938. 4,
  939. &BufferLength);
  940. ClpCryptConvertToCharacters(&CurrentByte,
  941. Hash[34],
  942. Hash[55],
  943. Hash[13],
  944. 4,
  945. &BufferLength);
  946. ClpCryptConvertToCharacters(&CurrentByte,
  947. Hash[56],
  948. Hash[14],
  949. Hash[35],
  950. 4,
  951. &BufferLength);
  952. ClpCryptConvertToCharacters(&CurrentByte,
  953. Hash[15],
  954. Hash[36],
  955. Hash[57],
  956. 4,
  957. &BufferLength);
  958. ClpCryptConvertToCharacters(&CurrentByte,
  959. Hash[37],
  960. Hash[58],
  961. Hash[16],
  962. 4,
  963. &BufferLength);
  964. ClpCryptConvertToCharacters(&CurrentByte,
  965. Hash[59],
  966. Hash[17],
  967. Hash[38],
  968. 4,
  969. &BufferLength);
  970. ClpCryptConvertToCharacters(&CurrentByte,
  971. Hash[18],
  972. Hash[39],
  973. Hash[60],
  974. 4,
  975. &BufferLength);
  976. ClpCryptConvertToCharacters(&CurrentByte,
  977. Hash[40],
  978. Hash[61],
  979. Hash[19],
  980. 4,
  981. &BufferLength);
  982. ClpCryptConvertToCharacters(&CurrentByte,
  983. Hash[62],
  984. Hash[20],
  985. Hash[41],
  986. 4,
  987. &BufferLength);
  988. ClpCryptConvertToCharacters(&CurrentByte,
  989. 0,
  990. 0,
  991. Hash[63],
  992. 2,
  993. &BufferLength);
  994. if (BufferLength == 0) {
  995. errno = ERANGE;
  996. Buffer = NULL;
  997. } else {
  998. *CurrentByte = '\0';
  999. }
  1000. //
  1001. // Clear things out to avoid leaving security context around.
  1002. //
  1003. SECURITY_ZERO(Hash, SHA512_HASH_SIZE);
  1004. SECURITY_ZERO(Hash2, SHA512_HASH_SIZE);
  1005. SECURITY_ZERO(PBytes, KeyLength);
  1006. SECURITY_ZERO(SBytes, SaltLength);
  1007. SECURITY_ZERO(&Context, sizeof(Context));
  1008. SECURITY_ZERO(&Context2, sizeof(Context2));
  1009. return Buffer;
  1010. }
  1011. VOID
  1012. ClpCryptConvertToCharacters (
  1013. PSTR *StringPointer,
  1014. UCHAR ValueHigh,
  1015. UCHAR ValueMid,
  1016. UCHAR ValueLow,
  1017. INTN Size,
  1018. PUINTN BufferLength
  1019. )
  1020. /*++
  1021. Routine Description:
  1022. This routine converts an integer into characters, 6 bits at a time.
  1023. Arguments:
  1024. StringPointer - Supplies a pointer that on input contains a pointer where
  1025. the characters will be returned. On output this value will be advanced.
  1026. ValueHigh - Supplies the value from bits 16-23.
  1027. ValueMid - Supplies the value from bits 8-15.
  1028. ValueLow - Supplies the value from bits 0-7.
  1029. Size - Supplies the number of characters to generate.
  1030. BufferLength - Supplies a pointer that on input contains the remaining
  1031. buffer space. On output this will be updated.
  1032. Return Value:
  1033. None.
  1034. --*/
  1035. {
  1036. PSTR String;
  1037. ULONG Value;
  1038. String = *StringPointer;
  1039. Value = (ValueHigh << 16) | (ValueMid << 8) | ValueLow;
  1040. while ((Size > 0) && (*BufferLength > 0)) {
  1041. *String = CRYPT_ALPHABET[Value & 0x3F];
  1042. String += 1;
  1043. Value >>= 6;
  1044. Size -= 1;
  1045. *BufferLength -= 1;
  1046. }
  1047. *StringPointer = String;
  1048. return;
  1049. }