123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380 |
- /*++
- Copyright (c) 2015 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- crypt.c
- Abstract:
- This module implements the crypt library functions.
- Author:
- Evan Green 6-Mar-2015
- Environment:
- User Mode C Library
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "cryptp.h"
- #include <minoca/lib/minocaos.h>
- #include <minoca/lib/crypto.h>
- #include <alloca.h>
- #include <errno.h>
- #include <sys/param.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define CRYPT_ALPHABET \
- "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- //
- // The number of rounds in SHA-256 crypt can be specified.
- //
- #define CRYPT_SHA256_ROUNDS_DEFAULT 5000
- #define CRYPT_SHA256_ROUNDS_MIN 1000
- #define CRYPT_SHA256_ROUNDS_MAX 999999999
- #define CRYPT_SHA256_SALT_MAX 16
- //
- // The number of rounds in SHA-512 crypt can be specified.
- //
- #define CRYPT_SHA512_ROUNDS_DEFAULT 5000
- #define CRYPT_SHA512_ROUNDS_MIN 1000
- #define CRYPT_SHA512_ROUNDS_MAX 999999999
- #define CRYPT_SHA512_SALT_MAX 16
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef
- PSTR
- (*PCRYPT_FUNCTION) (
- PSTR Key,
- PSTR Salt
- );
- /*++
- Routine Description:
- This routine defines the format for a crypt algorithm function.
- Arguments:
- Key - Supplies the key, a user's plaintext password.
- Salt - Supplies the ID and salt information.
- Return Value:
- Returns a pointer to the encrypted password (plus ID and salt information
- in cases where an alternate mechanism is used). This is a static buffer,
- which may be overwritten by subsequent calls to crypt.
- --*/
- /*++
- Structure Description:
- This structure stores the tuple of a crypt hashing algorithm's ID and
- function pointer.
- Members:
- Name - Stores a pointer to a string containing the name of the algorithm.
- Id - Stores the ID string that needs to appear at the beginning of the
- salt to match this algorithm.
- CryptFunction - Stores a pointer to a function used to encrypt the data.
- --*/
- typedef struct _CRYPT_FORMAT {
- PSTR Name;
- PSTR Id;
- PCRYPT_FUNCTION CryptFunction;
- } CRYPT_FORMAT, *PCRYPT_FORMAT;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- PSTR
- ClpCryptMd5 (
- PSTR Key,
- PSTR Salt
- );
- PSTR
- ClpCryptSha256 (
- PSTR Key,
- PSTR Salt
- );
- PSTR
- ClpCryptSha256Reentrant (
- PSTR Key,
- PSTR Salt,
- PSTR Buffer,
- UINTN BufferLength
- );
- PSTR
- ClpCryptSha512 (
- PSTR Key,
- PSTR Salt
- );
- PSTR
- ClpCryptSha512Reentrant (
- PSTR Key,
- PSTR Salt,
- PSTR Buffer,
- UINTN BufferLength
- );
- VOID
- ClpCryptConvertToCharacters (
- PSTR *StringPointer,
- UCHAR ValueHigh,
- UCHAR ValueMid,
- UCHAR ValueLow,
- INTN Size,
- PUINTN BufferLength
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- CRYPT_FORMAT ClCryptFormats[] = {
- {"md5", "$1$", ClpCryptMd5},
- {"sha256", "$5$", ClpCryptSha256},
- {"sha512", "$6$", ClpCryptSha512},
- {NULL, NULL, NULL}
- };
- //
- // Store the static buffer containing crypt results.
- //
- char ClCryptBuffer[120];
- //
- // ------------------------------------------------------------------ Functions
- //
- LIBCRYPT_API
- char *
- crypt (
- const char *Key,
- const char *Salt
- )
- /*++
- Routine Description:
- This routine encrypts a user's password using various encryption/hashing
- standards. The default is DES, which is fairly weak and subject to
- dictionary attacks.
- Arguments:
- Key - Supplies the key, a user's plaintext password.
- Salt - Supplies a two character salt to use to perterb the results. If this
- string starts with a $ and a number, alternate hashing algorithms are
- selected. The format is $id$salt$encrypted. ID can be 1 for MD5, 5 for
- SHA-256, or 6 for SHA-512.
- Return Value:
- Returns a pointer to the encrypted password (plus ID and salt information
- in cases where an alternate mechanism is used). This is a static buffer,
- which may be overwritten by subsequent calls to crypt.
- --*/
- {
- PCRYPT_FORMAT Format;
- Format = ClCryptFormats;
- while (Format->CryptFunction != NULL) {
- if ((Format->Id != NULL) && (strstr(Salt, Format->Id) == Salt)) {
- return Format->CryptFunction((PSTR)Key, (PSTR)Salt);
- }
- Format += 1;
- }
- return ClpCryptSha512((PSTR)Key, (PSTR)Salt);
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- PSTR
- ClpCryptMd5 (
- PSTR Key,
- PSTR Salt
- )
- /*++
- Routine Description:
- This routine encrypts a user's password using the MD5 hash algorithm.
- Arguments:
- Key - Supplies the key, a user's plaintext password.
- Salt - Supplies the ID and salt information.
- Return Value:
- Returns a pointer to the encrypted password, plus ID and salt information.
- This is a static buffer, which may be overwritten by subsequent calls to
- crypt.
- --*/
- {
- int Bits;
- UINTN BufferSize;
- MD5_CONTEXT Context;
- MD5_CONTEXT Context2;
- UCHAR Hash[MD5_HASH_SIZE];
- size_t HashLength;
- PSTR Id;
- size_t IdLength;
- int Iteration;
- size_t KeyLength;
- char *Result;
- const char *SaltEnd;
- size_t SaltLength;
- Id = "$1$";
- IdLength = strlen(Id);
- KeyLength = strlen(Key);
- //
- // Skip the ID part of the salt.
- //
- if (strncmp(Salt, Id, IdLength) == 0) {
- Salt += IdLength;
- }
- //
- // Compute the salt length, capped at 8 characters.
- //
- SaltEnd = Salt;
- SaltLength = 0;
- while ((*SaltEnd != '\0') && (*SaltEnd != '$') && (SaltLength < 8)) {
- SaltLength += 1;
- SaltEnd += 1;
- }
- //
- // Add the password, the magic string, and the salt.
- //
- CyMd5Initialize(&Context);
- CyMd5AddContent(&Context, Key, KeyLength);
- CyMd5AddContent(&Context, Id, IdLength);
- CyMd5AddContent(&Context, Salt, SaltLength);
- //
- // Take the MD5 of password, salt, password, and add in that hash for an
- // amount that corresponds to the length of the password.
- //
- CyMd5Initialize(&Context2);
- CyMd5AddContent(&Context2, Key, KeyLength);
- CyMd5AddContent(&Context2, Salt, SaltLength);
- CyMd5AddContent(&Context2, Key, KeyLength);
- CyMd5GetHash(&Context2, Hash);
- for (HashLength = KeyLength;
- HashLength >= MD5_HASH_SIZE;
- HashLength -= MD5_HASH_SIZE) {
- CyMd5AddContent(&Context, Hash, MD5_HASH_SIZE);
- }
- CyMd5AddContent(&Context, Hash, HashLength);
- //
- // Don't leave security treasures floating around.
- //
- memset(Hash, 0, MD5_HASH_SIZE);
- //
- // Add in either a zero or the first character of the password depending
- // on how bits in the length of the password are set.
- //
- Bits = KeyLength;
- while (Bits != 0) {
- if ((Bits & 0x1) != 0) {
- CyMd5AddContent(&Context, Hash, 1);
- } else {
- CyMd5AddContent(&Context, Key, 1);
- }
- Bits = Bits >> 1;
- }
- strcpy(ClCryptBuffer, Id);
- strncat(ClCryptBuffer, Salt, SaltLength);
- strcat(ClCryptBuffer, "$");
- CyMd5GetHash(&Context, Hash);
- //
- // Do some more iterations just to slow things down a little.
- //
- for (Iteration = 0; Iteration < 1000; Iteration += 1) {
- CyMd5Initialize(&Context2);
- if ((Iteration & 0x1) != 0) {
- CyMd5AddContent(&Context2, Key, KeyLength);
- } else {
- CyMd5AddContent(&Context2, Hash, MD5_HASH_SIZE);
- }
- if ((Iteration % 3) != 0) {
- CyMd5AddContent(&Context2, Salt, SaltLength);
- }
- if ((Iteration % 7) != 0) {
- CyMd5AddContent(&Context2, Key, KeyLength);
- }
- if ((Iteration & 0x1) != 0) {
- CyMd5AddContent(&Context2, Hash, MD5_HASH_SIZE);
- } else {
- CyMd5AddContent(&Context2, Key, KeyLength);
- }
- CyMd5GetHash(&Context2, Hash);
- }
- Result = ClCryptBuffer + strlen(ClCryptBuffer);
- BufferSize = sizeof(ClCryptBuffer) - ((UINTN)Result - (UINTN)ClCryptBuffer);
- ClpCryptConvertToCharacters(&Result,
- Hash[0],
- Hash[6],
- Hash[12],
- 4,
- &BufferSize);
- ClpCryptConvertToCharacters(&Result,
- Hash[1],
- Hash[7],
- Hash[13],
- 4,
- &BufferSize);
- ClpCryptConvertToCharacters(&Result,
- Hash[2],
- Hash[8],
- Hash[14],
- 4,
- &BufferSize);
- ClpCryptConvertToCharacters(&Result,
- Hash[3],
- Hash[9],
- Hash[15],
- 4,
- &BufferSize);
- ClpCryptConvertToCharacters(&Result,
- Hash[4],
- Hash[10],
- Hash[5],
- 4,
- &BufferSize);
- ClpCryptConvertToCharacters(&Result, 0, 0, Hash[11], 2, &BufferSize);
- *Result = '\0';
- //
- // No security droppings.
- //
- SECURITY_ZERO(Hash, MD5_HASH_SIZE);
- return ClCryptBuffer;
- }
- PSTR
- ClpCryptSha256 (
- PSTR Key,
- PSTR Salt
- )
- /*++
- Routine Description:
- This routine encrypts a user's password using the SHA-256 hash algorithm.
- Arguments:
- Key - Supplies the key, a user's plaintext password.
- Salt - Supplies the ID and salt information.
- Return Value:
- Returns a pointer to the encrypted password, plus ID and salt information.
- This is a static buffer, which may be overwritten by subsequent calls to
- crypt.
- --*/
- {
- PSTR Result;
- Result = ClpCryptSha256Reentrant(Key,
- Salt,
- ClCryptBuffer,
- sizeof(ClCryptBuffer));
- return Result;
- }
- PSTR
- ClpCryptSha256Reentrant (
- PSTR Key,
- PSTR Salt,
- PSTR Buffer,
- UINTN BufferLength
- )
- /*++
- Routine Description:
- This routine encrypts a user's password using the SHA-256 hash algorithm.
- Arguments:
- Key - Supplies the key, a user's plaintext password.
- Salt - Supplies the ID and salt information.
- Buffer - Supplies a pointer where the result will be returned.
- BufferLength - Supplies the length of the buffer in bytes.
- Return Value:
- Returns a pointer to the encrypted password, plus ID and salt information.
- --*/
- {
- PSTR AfterScan;
- UINTN Bits;
- SHA256_CONTEXT Context;
- SHA256_CONTEXT Context2;
- PSTR CurrentByte;
- UCHAR Hash[SHA256_HASH_SIZE];
- UCHAR Hash2[SHA256_HASH_SIZE];
- UINTN HashLength;
- PSTR Id;
- UINTN IdLength;
- UINTN Iteration;
- UINTN KeyLength;
- PSTR PBytes;
- UINTN Rounds;
- PSTR RoundsPrefix;
- UINTN RoundsPrefixLength;
- BOOL RoundsSpecified;
- PSTR RoundsString;
- UINTN SaltLength;
- UINTN SaltRounds;
- PSTR SBytes;
- UINTN StringLength;
- Id = "$5$";
- IdLength = strlen(Id);
- Rounds = CRYPT_SHA256_ROUNDS_DEFAULT;
- RoundsPrefix = "rounds=";
- RoundsPrefixLength = strlen(RoundsPrefix);
- RoundsSpecified = FALSE;
- //
- // Move over the salt ID.
- //
- if (strncmp(Salt, Id, IdLength) == 0) {
- Salt += IdLength;
- }
- if (strncmp(Salt, RoundsPrefix, RoundsPrefixLength) == 0) {
- RoundsString = Salt + RoundsPrefixLength;
- SaltRounds = strtoul(RoundsString, &AfterScan, 10);
- if (*AfterScan == '$') {
- Salt = AfterScan + 1;
- Rounds = SaltRounds;
- if (Rounds < CRYPT_SHA256_ROUNDS_MIN) {
- Rounds = CRYPT_SHA256_ROUNDS_MIN;
- } else if (Rounds > CRYPT_SHA256_ROUNDS_MAX) {
- Rounds = CRYPT_SHA256_ROUNDS_MAX;
- }
- RoundsSpecified = TRUE;
- }
- }
- SaltLength = strcspn(Salt, "$");
- if (SaltLength > CRYPT_SHA256_SALT_MAX) {
- SaltLength = CRYPT_SHA256_SALT_MAX;
- }
- KeyLength = strlen(Key);
- CySha256Initialize(&Context);
- CySha256AddContent(&Context, Key, KeyLength);
- CySha256AddContent(&Context, Salt, SaltLength);
- //
- // In a different context, add the key, salt, and key again.
- //
- CySha256Initialize(&Context2);
- CySha256AddContent(&Context2, Key, KeyLength);
- CySha256AddContent(&Context2, Salt, SaltLength);
- CySha256AddContent(&Context2, Key, KeyLength);
- CySha256GetHash(&Context2, Hash);
- //
- // For each character of the key, add the alternate sum.
- //
- for (HashLength = KeyLength;
- HashLength >= SHA256_HASH_SIZE;
- HashLength -= SHA256_HASH_SIZE) {
- CySha256AddContent(&Context, Hash, SHA256_HASH_SIZE);
- }
- CySha256AddContent(&Context, Hash, HashLength);
- //
- // For the bits in the key length, add in either the hash or the key,
- // depending on the bit value.
- //
- for (Bits = KeyLength; Bits > 0; Bits >>= 1) {
- if ((Bits & 0x1) != 0) {
- CySha256AddContent(&Context, Hash, SHA256_HASH_SIZE);
- } else {
- CySha256AddContent(&Context, Key, KeyLength);
- }
- }
- CySha256GetHash(&Context, Hash);
- //
- // Compute another alternate hash. For every byte in the password add the
- // password.
- //
- CySha256Initialize(&Context2);
- for (Iteration = 0; Iteration < KeyLength; Iteration += 1) {
- CySha256AddContent(&Context2, Key, KeyLength);
- }
- CySha256GetHash(&Context2, Hash2);
- //
- // Create a P-Sequence.
- //
- PBytes = alloca(KeyLength);
- CurrentByte = PBytes;
- for (HashLength = KeyLength;
- HashLength >= SHA256_HASH_SIZE;
- HashLength -= SHA256_HASH_SIZE) {
- memcpy(CurrentByte, Hash2, SHA256_HASH_SIZE);
- CurrentByte += SHA256_HASH_SIZE;
- }
- memcpy(CurrentByte, Hash2, HashLength);
- //
- // Begin computation of the S-Sequence.
- //
- CySha256Initialize(&Context2);
- for (Iteration = 0; Iteration < 16 + Hash[0]; Iteration += 1) {
- CySha256AddContent(&Context2, Salt, SaltLength);
- }
- CySha256GetHash(&Context2, Hash2);
- //
- // Create and compute the S-Sequence.
- //
- SBytes = alloca(SaltLength);
- CurrentByte = SBytes;
- for (HashLength = SaltLength;
- HashLength >= SHA256_HASH_SIZE;
- HashLength -= SHA256_HASH_SIZE) {
- memcpy(CurrentByte, Hash2, SHA256_HASH_SIZE);
- }
- memcpy(CurrentByte, Hash2, HashLength);
- //
- // Re-crunch the hash for the given rounds to make things computationally
- // expensive.
- //
- for (Iteration = 0; Iteration < Rounds; Iteration += 1) {
- CySha256Initialize(&Context);
- if ((Iteration & 0x1) != 0) {
- CySha256AddContent(&Context, PBytes, KeyLength);
- } else {
- CySha256AddContent(&Context, Hash, SHA256_HASH_SIZE);
- }
- if ((Iteration % 3) != 0) {
- CySha256AddContent(&Context, SBytes, SaltLength);
- }
- if ((Iteration % 7) != 0) {
- CySha256AddContent(&Context, PBytes, KeyLength);
- }
- if ((Iteration & 0x1) != 0) {
- CySha256AddContent(&Context, Hash, SHA256_HASH_SIZE);
- } else {
- CySha256AddContent(&Context, PBytes, KeyLength);
- }
- CySha256GetHash(&Context, Hash);
- }
- //
- // The heavy lifting is done. Start to create the output string.
- //
- CurrentByte = stpncpy(Buffer, Id, BufferLength);
- if (BufferLength >= IdLength) {
- BufferLength -= IdLength;
- } else {
- BufferLength = 0;
- }
- if (RoundsSpecified != FALSE) {
- StringLength = snprintf(CurrentByte,
- BufferLength,
- "%s%zu$",
- RoundsPrefix,
- Rounds);
- CurrentByte += StringLength;
- if (BufferLength >= StringLength) {
- BufferLength -= StringLength;
- } else {
- BufferLength = 0;
- }
- }
- CurrentByte = stpncpy(CurrentByte, Salt, MIN(BufferLength, SaltLength));
- if (BufferLength >= SaltLength) {
- BufferLength -= SaltLength;
- } else {
- BufferLength = 0;
- }
- if (BufferLength > 0) {
- *CurrentByte = '$';
- CurrentByte += 1;
- BufferLength -= 1;
- }
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[0],
- Hash[10],
- Hash[20],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[21],
- Hash[1],
- Hash[11],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[12],
- Hash[22],
- Hash[2],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[3],
- Hash[13],
- Hash[23],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[24],
- Hash[4],
- Hash[14],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[15],
- Hash[25],
- Hash[5],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[6],
- Hash[16],
- Hash[26],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[27],
- Hash[7],
- Hash[17],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[18],
- Hash[28],
- Hash[8],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[9],
- Hash[19],
- Hash[29],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- 0,
- Hash[31],
- Hash[30],
- 3,
- &BufferLength);
- if (BufferLength == 0) {
- errno = ERANGE;
- Buffer = NULL;
- } else {
- *CurrentByte = '\0';
- }
- //
- // Clear things out to avoid leaving security context around.
- //
- SECURITY_ZERO(Hash, SHA256_HASH_SIZE);
- SECURITY_ZERO(Hash2, SHA256_HASH_SIZE);
- SECURITY_ZERO(PBytes, KeyLength);
- SECURITY_ZERO(SBytes, SaltLength);
- SECURITY_ZERO(&Context, sizeof(Context));
- SECURITY_ZERO(&Context2, sizeof(Context2));
- return Buffer;
- }
- PSTR
- ClpCryptSha512 (
- PSTR Key,
- PSTR Salt
- )
- /*++
- Routine Description:
- This routine encrypts a user's password using the SHA-512 hash algorithm.
- Arguments:
- Key - Supplies the key, a user's plaintext password.
- Salt - Supplies the ID and salt information.
- Return Value:
- Returns a pointer to the encrypted password, plus ID and salt information.
- This is a static buffer, which may be overwritten by subsequent calls to
- crypt.
- --*/
- {
- PSTR Result;
- Result = ClpCryptSha512Reentrant(Key,
- Salt,
- ClCryptBuffer,
- sizeof(ClCryptBuffer));
- return Result;
- }
- PSTR
- ClpCryptSha512Reentrant (
- PSTR Key,
- PSTR Salt,
- PSTR Buffer,
- UINTN BufferLength
- )
- /*++
- Routine Description:
- This routine encrypts a user's password using the SHA-512 hash algorithm.
- Arguments:
- Key - Supplies the key, a user's plaintext password.
- Salt - Supplies the ID and salt information.
- Buffer - Supplies a pointer where the result will be returned.
- BufferLength - Supplies the length of the buffer in bytes.
- Return Value:
- Returns a pointer to the encrypted password, plus ID and salt information.
- --*/
- {
- PSTR AfterScan;
- UINTN Bits;
- SHA512_CONTEXT Context;
- SHA512_CONTEXT Context2;
- PSTR CurrentByte;
- UCHAR Hash[SHA512_HASH_SIZE];
- UCHAR Hash2[SHA512_HASH_SIZE];
- UINTN HashLength;
- PSTR Id;
- UINTN IdLength;
- UINTN Iteration;
- UINTN KeyLength;
- PSTR PBytes;
- UINTN Rounds;
- PSTR RoundsPrefix;
- UINTN RoundsPrefixLength;
- BOOL RoundsSpecified;
- PSTR RoundsString;
- UINTN SaltLength;
- UINTN SaltRounds;
- PSTR SBytes;
- UINTN StringLength;
- Id = "$6$";
- IdLength = strlen(Id);
- Rounds = CRYPT_SHA512_ROUNDS_DEFAULT;
- RoundsPrefix = "rounds=";
- RoundsPrefixLength = strlen(RoundsPrefix);
- RoundsSpecified = FALSE;
- //
- // Move over the salt ID.
- //
- if (strncmp(Salt, Id, IdLength) == 0) {
- Salt += IdLength;
- }
- if (strncmp(Salt, RoundsPrefix, RoundsPrefixLength) == 0) {
- RoundsString = Salt + RoundsPrefixLength;
- SaltRounds = strtoul(RoundsString, &AfterScan, 10);
- if (*AfterScan == '$') {
- Salt = AfterScan + 1;
- Rounds = SaltRounds;
- if (Rounds < CRYPT_SHA512_ROUNDS_MIN) {
- Rounds = CRYPT_SHA512_ROUNDS_MIN;
- } else if (Rounds > CRYPT_SHA512_ROUNDS_MAX) {
- Rounds = CRYPT_SHA512_ROUNDS_MAX;
- }
- RoundsSpecified = TRUE;
- }
- }
- SaltLength = strcspn(Salt, "$");
- if (SaltLength > CRYPT_SHA512_SALT_MAX) {
- SaltLength = CRYPT_SHA512_SALT_MAX;
- }
- KeyLength = strlen(Key);
- CySha512Initialize(&Context);
- CySha512AddContent(&Context, Key, KeyLength);
- CySha512AddContent(&Context, Salt, SaltLength);
- //
- // In a different context, add the key, salt, and key again.
- //
- CySha512Initialize(&Context2);
- CySha512AddContent(&Context2, Key, KeyLength);
- CySha512AddContent(&Context2, Salt, SaltLength);
- CySha512AddContent(&Context2, Key, KeyLength);
- CySha512GetHash(&Context2, Hash);
- //
- // For each character of the key, add the alternate sum.
- //
- for (HashLength = KeyLength;
- HashLength > SHA512_HASH_SIZE;
- HashLength -= SHA512_HASH_SIZE) {
- CySha512AddContent(&Context, Hash, SHA512_HASH_SIZE);
- }
- CySha512AddContent(&Context, Hash, HashLength);
- //
- // For the bits in the key length, add in either the hash or the key,
- // depending on the bit value.
- //
- for (Bits = KeyLength; Bits > 0; Bits >>= 1) {
- if ((Bits & 0x1) != 0) {
- CySha512AddContent(&Context, Hash, SHA512_HASH_SIZE);
- } else {
- CySha512AddContent(&Context, Key, KeyLength);
- }
- }
- CySha512GetHash(&Context, Hash);
- //
- // Compute another alternate hash. For every byte in the password add the
- // password.
- //
- CySha512Initialize(&Context2);
- for (Iteration = 0; Iteration < KeyLength; Iteration += 1) {
- CySha512AddContent(&Context2, Key, KeyLength);
- }
- CySha512GetHash(&Context2, Hash2);
- //
- // Create a P-Sequence.
- //
- PBytes = alloca(KeyLength);
- CurrentByte = PBytes;
- for (HashLength = KeyLength;
- HashLength >= SHA512_HASH_SIZE;
- HashLength -= SHA512_HASH_SIZE) {
- memcpy(CurrentByte, Hash2, SHA512_HASH_SIZE);
- CurrentByte += SHA512_HASH_SIZE;
- }
- memcpy(CurrentByte, Hash2, HashLength);
- //
- // Begin computation of the S-Sequence.
- //
- CySha512Initialize(&Context2);
- for (Iteration = 0; Iteration < 16 + Hash[0]; Iteration += 1) {
- CySha512AddContent(&Context2, Salt, SaltLength);
- }
- CySha512GetHash(&Context2, Hash2);
- //
- // Create and compute the S-Sequence.
- //
- SBytes = alloca(SaltLength);
- CurrentByte = SBytes;
- for (HashLength = SaltLength;
- HashLength >= SHA512_HASH_SIZE;
- HashLength -= SHA512_HASH_SIZE) {
- memcpy(CurrentByte, Hash2, SHA512_HASH_SIZE);
- }
- memcpy(CurrentByte, Hash2, HashLength);
- //
- // Re-crunch the hash for the given rounds to make things computationally
- // expensive.
- //
- for (Iteration = 0; Iteration < Rounds; Iteration += 1) {
- CySha512Initialize(&Context);
- if ((Iteration & 0x1) != 0) {
- CySha512AddContent(&Context, PBytes, KeyLength);
- } else {
- CySha512AddContent(&Context, Hash, SHA512_HASH_SIZE);
- }
- if ((Iteration % 3) != 0) {
- CySha512AddContent(&Context, SBytes, SaltLength);
- }
- if ((Iteration % 7) != 0) {
- CySha512AddContent(&Context, PBytes, KeyLength);
- }
- if ((Iteration & 0x1) != 0) {
- CySha512AddContent(&Context, Hash, SHA512_HASH_SIZE);
- } else {
- CySha512AddContent(&Context, PBytes, KeyLength);
- }
- CySha512GetHash(&Context, Hash);
- }
- //
- // The heavy lifting is done. Start to create the output string.
- //
- CurrentByte = stpncpy(Buffer, Id, BufferLength);
- if (BufferLength >= IdLength) {
- BufferLength -= IdLength;
- } else {
- BufferLength = 0;
- }
- if (RoundsSpecified != FALSE) {
- StringLength = snprintf(CurrentByte,
- BufferLength,
- "%s%zu$",
- RoundsPrefix,
- Rounds);
- CurrentByte += StringLength;
- if (BufferLength >= StringLength) {
- BufferLength -= StringLength;
- } else {
- BufferLength = 0;
- }
- }
- CurrentByte = stpncpy(CurrentByte, Salt, MIN(BufferLength, SaltLength));
- if (BufferLength >= SaltLength) {
- BufferLength -= SaltLength;
- } else {
- BufferLength = 0;
- }
- if (BufferLength > 0) {
- *CurrentByte = '$';
- CurrentByte += 1;
- BufferLength -= 1;
- }
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[0],
- Hash[21],
- Hash[42],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[22],
- Hash[43],
- Hash[1],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[44],
- Hash[2],
- Hash[23],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[3],
- Hash[24],
- Hash[45],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[25],
- Hash[46],
- Hash[4],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[47],
- Hash[5],
- Hash[26],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[6],
- Hash[27],
- Hash[48],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[28],
- Hash[49],
- Hash[7],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[50],
- Hash[8],
- Hash[29],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[9],
- Hash[30],
- Hash[51],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[31],
- Hash[52],
- Hash[10],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[53],
- Hash[11],
- Hash[32],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[12],
- Hash[33],
- Hash[54],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[34],
- Hash[55],
- Hash[13],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[56],
- Hash[14],
- Hash[35],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[15],
- Hash[36],
- Hash[57],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[37],
- Hash[58],
- Hash[16],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[59],
- Hash[17],
- Hash[38],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[18],
- Hash[39],
- Hash[60],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[40],
- Hash[61],
- Hash[19],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- Hash[62],
- Hash[20],
- Hash[41],
- 4,
- &BufferLength);
- ClpCryptConvertToCharacters(&CurrentByte,
- 0,
- 0,
- Hash[63],
- 2,
- &BufferLength);
- if (BufferLength == 0) {
- errno = ERANGE;
- Buffer = NULL;
- } else {
- *CurrentByte = '\0';
- }
- //
- // Clear things out to avoid leaving security context around.
- //
- SECURITY_ZERO(Hash, SHA512_HASH_SIZE);
- SECURITY_ZERO(Hash2, SHA512_HASH_SIZE);
- SECURITY_ZERO(PBytes, KeyLength);
- SECURITY_ZERO(SBytes, SaltLength);
- SECURITY_ZERO(&Context, sizeof(Context));
- SECURITY_ZERO(&Context2, sizeof(Context2));
- return Buffer;
- }
- VOID
- ClpCryptConvertToCharacters (
- PSTR *StringPointer,
- UCHAR ValueHigh,
- UCHAR ValueMid,
- UCHAR ValueLow,
- INTN Size,
- PUINTN BufferLength
- )
- /*++
- Routine Description:
- This routine converts an integer into characters, 6 bits at a time.
- Arguments:
- StringPointer - Supplies a pointer that on input contains a pointer where
- the characters will be returned. On output this value will be advanced.
- ValueHigh - Supplies the value from bits 16-23.
- ValueMid - Supplies the value from bits 8-15.
- ValueLow - Supplies the value from bits 0-7.
- Size - Supplies the number of characters to generate.
- BufferLength - Supplies a pointer that on input contains the remaining
- buffer space. On output this will be updated.
- Return Value:
- None.
- --*/
- {
- PSTR String;
- ULONG Value;
- String = *StringPointer;
- Value = (ValueHigh << 16) | (ValueMid << 8) | ValueLow;
- while ((Size > 0) && (*BufferLength > 0)) {
- *String = CRYPT_ALPHABET[Value & 0x3F];
- String += 1;
- Value >>= 6;
- Size -= 1;
- *BufferLength -= 1;
- }
- *StringPointer = String;
- return;
- }
|