123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863 |
- /********************************************************************************/
- /* */
- /* Implementation of cryptographic functions for hashing. */
- /* Written by Ken Goldman */
- /* IBM Thomas J. Watson Research Center */
- /* $Id: CryptHash.c 1658 2021-01-22 23:14:01Z kgoldman $ */
- /* */
- /* Licenses and Notices */
- /* */
- /* 1. Copyright Licenses: */
- /* */
- /* - Trusted Computing Group (TCG) grants to the user of the source code in */
- /* this specification (the "Source Code") a worldwide, irrevocable, */
- /* nonexclusive, royalty free, copyright license to reproduce, create */
- /* derivative works, distribute, display and perform the Source Code and */
- /* derivative works thereof, and to grant others the rights granted herein. */
- /* */
- /* - The TCG grants to the user of the other parts of the specification */
- /* (other than the Source Code) the rights to reproduce, distribute, */
- /* display, and perform the specification solely for the purpose of */
- /* developing products based on such documents. */
- /* */
- /* 2. Source Code Distribution Conditions: */
- /* */
- /* - Redistributions of Source Code must retain the above copyright licenses, */
- /* this list of conditions and the following disclaimers. */
- /* */
- /* - Redistributions in binary form must reproduce the above copyright */
- /* licenses, this list of conditions and the following disclaimers in the */
- /* documentation and/or other materials provided with the distribution. */
- /* */
- /* 3. Disclaimers: */
- /* */
- /* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */
- /* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */
- /* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */
- /* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */
- /* Contact TCG Administration (admin@trustedcomputinggroup.org) for */
- /* information on specification licensing rights available through TCG */
- /* membership agreements. */
- /* */
- /* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */
- /* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */
- /* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */
- /* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */
- /* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */
- /* */
- /* - Without limitation, TCG and its members and licensors disclaim all */
- /* liability, including liability for infringement of any proprietary */
- /* rights, relating to use of information in this specification and to the */
- /* implementation of this specification, and TCG disclaims all liability for */
- /* cost of procurement of substitute goods or services, lost profits, loss */
- /* of use, loss of data or any incidental, consequential, direct, indirect, */
- /* or special damages, whether under contract, tort, warranty or otherwise, */
- /* arising in any way out of use or reliance upon this specification or any */
- /* information herein. */
- /* */
- /* (c) Copyright IBM Corp. and others, 2016 - 2021 */
- /* */
- /********************************************************************************/
- /* 10.2.13 CryptHash.c */
- /* 10.2.13.1 Description */
- /* This file contains implementation of cryptographic functions for hashing. */
- /* 10.2.13.2 Includes, Defines, and Types */
- #define _CRYPT_HASH_C_
- #include "Tpm.h"
- #include "CryptHash_fp.h"
- #include "CryptHash.h"
- #include "OIDs.h"
- /* Instance each of the hash descriptors based on the implemented algorithms */
- FOR_EACH_HASH(HASH_DEF_TEMPLATE)
- /* Instance a null def. */
- HASH_DEF NULL_Def = {{0}};
- /* Create a table of pointers to the defined hash definitions */
- #define HASH_DEF_ENTRY(HASH, Hash) &Hash##_Def,
- PHASH_DEF HashDefArray[] = {
- // for each implemented HASH, expands to: &HASH_Def,
- FOR_EACH_HASH(HASH_DEF_ENTRY)
- &NULL_Def
- };
- /* 10.2.13.3 Obligatory Initialization Functions */
- /* 10.2.13.3.1 CryptHashInit() */
- /* This function is called by _TPM_Init() do perform the initialization operations for the
- library. */
- BOOL
- CryptHashInit(
- void
- )
- {
- LibHashInit();
- return TRUE;
- }
- /* 10.2.13.3.2 CryptHashStartup() */
- /* This function is called by TPM2_Startup(). It checks that the size of the HashDefArray() is
- consistent with the HASH_COUNT. */
- BOOL
- CryptHashStartup(
- void
- )
- {
- int i = sizeof(HashDefArray) / sizeof(PHASH_DEF) - 1;
- return (i == HASH_COUNT);
- }
- /* 10.2.13.4 Hash Information Access Functions */
- /* 10.2.13.4.1 Introduction */
- /* These functions provide access to the hash algorithm description information. */
- /* 10.2.13.4.2 CryptGetHashDef() */
- /* This function accesses the hash descriptor associated with a hash a algorithm. The function
- returns a pointer to a null descriptor if hashAlg is TPM_ALG_NULL or not a defined algorithm. */
- PHASH_DEF
- CryptGetHashDef(
- TPM_ALG_ID hashAlg
- )
- {
- #define GET_DEF(HASH, Hash) case ALG_##HASH##_VALUE: return &Hash##_Def;
- switch(hashAlg)
- {
- FOR_EACH_HASH(GET_DEF)
- default:
- return &NULL_Def;
- }
- #undef GET_DEF
- }
- /* 10.2.13.4.3 CryptHashIsValidAlg() */
- /* This function tests to see if an algorithm ID is a valid hash algorithm. If flag is true, then
- TPM_ALG_NULL is a valid hash. */
- /* Return Value Meaning */
- /* TRUE(1) hashAlg is a valid, implemented hash on this TPM */
- /* FALSE(0) hashAlg is not valid for this TPM */
- BOOL
- CryptHashIsValidAlg(
- TPM_ALG_ID hashAlg, // IN: the algorithm to check
- BOOL flag // IN: TRUE if TPM_ALG_NULL is to be treated
- // as a valid hash
- )
- {
- if(hashAlg == TPM_ALG_NULL)
- return flag;
- return CryptGetHashDef(hashAlg) != &NULL_Def;
- }
- /* 10.2.13.4.4 CryptHashGetAlgByIndex() */
- /* This function is used to iterate through the hashes. TPM_ALG_NULL is returned for all indexes
- that are not valid hashes. If the TPM implements 3 hashes, then an index value of 0 will return
- the first implemented hash and an index of 2 will return the last. All other index values will
- return TPM_ALG_NULL. */
- /* Return Value Meaning */
- /* TPM_ALG_xxx a hash algorithm */
- /* TPM_ALG_NULL this can be used as a stop value */
- LIB_EXPORT TPM_ALG_ID
- CryptHashGetAlgByIndex(
- UINT32 index // IN: the index
- )
- {
- TPM_ALG_ID hashAlg;
- if(index >= HASH_COUNT)
- hashAlg = TPM_ALG_NULL;
- else
- hashAlg = HashDefArray[index]->hashAlg;
- return hashAlg;
- }
- /* 10.2.13.4.5 CryptHashGetDigestSize() */
- /* Returns the size of the digest produced by the hash. If hashAlg is not a hash algorithm, the TPM
- will FAIL. */
- /* Return Value Meaning */
- /* 0 TPM_ALG_NULL */
- /* > 0 the digest size */
- LIB_EXPORT UINT16
- CryptHashGetDigestSize(
- TPM_ALG_ID hashAlg // IN: hash algorithm to look up
- )
- {
- return CryptGetHashDef(hashAlg)->digestSize;
- }
- /* 10.2.13.4.6 CryptHashGetBlockSize() */
- /* Returns the size of the block used by the hash. If hashAlg is not a hash algorithm, the TPM will
- FAIL. */
- /* Return Value Meaning */
- /* 0 TPM_ALG_NULL */
- /* > 0 the digest size */
- LIB_EXPORT UINT16
- CryptHashGetBlockSize(
- TPM_ALG_ID hashAlg // IN: hash algorithm to look up
- )
- {
- return CryptGetHashDef(hashAlg)->blockSize;
- }
- /* 10.2.13.4.7 CryptHashGetOid() */
- /* This function returns a pointer to DER=encoded OID for a hash algorithm. All OIDs are full OID
- values including the Tag (0x06) and length byte. */
- LIB_EXPORT const BYTE *
- CryptHashGetOid(
- TPM_ALG_ID hashAlg
- )
- {
- return CryptGetHashDef(hashAlg)->OID;
- }
- /* 10.2.13.4.8 CryptHashGetContextAlg() */
- /* This function returns the hash algorithm associated with a hash context. */
- TPM_ALG_ID
- CryptHashGetContextAlg(
- PHASH_STATE state // IN: the context to check
- )
- {
- return state->hashAlg;
- }
- /* 10.2.13.5 State Import and Export */
- /* 10.2.13.5.1 CryptHashCopyState */
- /* This function is used to clone a HASH_STATE. */
- LIB_EXPORT void
- CryptHashCopyState(
- HASH_STATE *out, // OUT: destination of the state
- const HASH_STATE *in // IN: source of the state
- )
- {
- pAssert(out->type == in->type);
- out->hashAlg = in->hashAlg;
- out->def = in->def;
- if(in->hashAlg != TPM_ALG_NULL)
- {
- HASH_STATE_COPY(out, in);
- }
- if(in->type == HASH_STATE_HMAC)
- {
- const HMAC_STATE *hIn = (HMAC_STATE *)in;
- HMAC_STATE *hOut = (HMAC_STATE *)out;
- hOut->hmacKey = hIn->hmacKey;
- }
- return;
- }
- /* 10.2.13.5.2 CryptHashExportState() */
- /* This function is used to export a hash or HMAC hash state. This function would be called when
- preparing to context save a sequence object. */
- void
- CryptHashExportState(
- PCHASH_STATE internalFmt, // IN: the hash state formatted for use by
- // library
- PEXPORT_HASH_STATE externalFmt // OUT: the exported hash state
- )
- {
- BYTE *outBuf = (BYTE *)externalFmt;
- //
- cAssert(sizeof(HASH_STATE) <= sizeof(EXPORT_HASH_STATE));
- // the following #define is used to move data from an aligned internal data
- // structure to a byte buffer (external format data.
- #define CopyToOffset(value) \
- memcpy(&outBuf[offsetof(HASH_STATE,value)], &internalFmt->value, \
- sizeof(internalFmt->value))
- // Copy the hashAlg
- CopyToOffset(hashAlg);
- CopyToOffset(type);
- #ifdef HASH_STATE_SMAC
- if(internalFmt->type == HASH_STATE_SMAC)
- {
- memcpy(outBuf, internalFmt, sizeof(HASH_STATE));
- return;
-
- }
- #endif
- if(internalFmt->type == HASH_STATE_HMAC)
- {
- HMAC_STATE *from = (HMAC_STATE *)internalFmt;
- memcpy(&outBuf[offsetof(HMAC_STATE, hmacKey)], &from->hmacKey,
- sizeof(from->hmacKey));
- }
- if(internalFmt->hashAlg != TPM_ALG_NULL)
- HASH_STATE_EXPORT(externalFmt, internalFmt);
- }
- /* 10.2.13.5.3 CryptHashImportState() */
- /* This function is used to import the hash state. This function would be called to import a hash
- state when the context of a sequence object was being loaded. */
- void
- CryptHashImportState(
- PHASH_STATE internalFmt, // OUT: the hash state formatted for use by
- // the library
- PCEXPORT_HASH_STATE externalFmt // IN: the exported hash state
- )
- {
- BYTE *inBuf = (BYTE *)externalFmt;
- //
- #define CopyFromOffset(value) \
- memcpy(&internalFmt->value, &inBuf[offsetof(HASH_STATE,value)], \
- sizeof(internalFmt->value))
-
- // Copy the hashAlg of the byte-aligned input structure to the structure-aligned
- // internal structure.
- CopyFromOffset(hashAlg);
- CopyFromOffset(type);
- if(internalFmt->hashAlg != TPM_ALG_NULL)
- {
- #ifdef HASH_STATE_SMAC
- if(internalFmt->type == HASH_STATE_SMAC)
- {
- memcpy(internalFmt, inBuf, sizeof(HASH_STATE));
- return;
- }
- #endif
- internalFmt->def = CryptGetHashDef(internalFmt->hashAlg);
- HASH_STATE_IMPORT(internalFmt, inBuf);
- if(internalFmt->type == HASH_STATE_HMAC)
- {
- HMAC_STATE *to = (HMAC_STATE *)internalFmt;
- memcpy(&to->hmacKey, &inBuf[offsetof(HMAC_STATE, hmacKey)],
- sizeof(to->hmacKey));
- }
- }
- }
- /* 10.2.13.6 State Modification Functions */
- /* 10.2.13.6.1 HashEnd() */
- /* Local function to complete a hash that uses the hashDef instead of an algorithm ID. This function
- is used to complete the hash and only return a partial digest. The return value is the size of
- the data copied. */
- static UINT16
- HashEnd(
- PHASH_STATE hashState, // IN: the hash state
- UINT32 dOutSize, // IN: the size of receive buffer
- PBYTE dOut // OUT: the receive buffer
- )
- {
- BYTE temp[MAX_DIGEST_SIZE];
- if((hashState->hashAlg == TPM_ALG_NULL)
- || (hashState->type != HASH_STATE_HASH))
- dOutSize = 0;
- if(dOutSize > 0)
- {
- hashState->def = CryptGetHashDef(hashState->hashAlg);
- // Set the final size
- dOutSize = MIN(dOutSize, hashState->def->digestSize);
- // Complete into the temp buffer and then copy
- HASH_END(hashState, temp);
- // Don't want any other functions calling the HASH_END method
- // directly.
- #undef HASH_END
- memcpy(dOut, &temp, dOutSize);
- }
- hashState->type = HASH_STATE_EMPTY;
- return (UINT16)dOutSize;
- }
- /* 10.2.13.6.2 CryptHashStart() */
- /* Functions starts a hash stack Start a hash stack and returns the digest size. As a side effect,
- the value of stateSize in hashState is updated to indicate the number of bytes of state that were
- saved. This function calls GetHashServer() and that function will put the TPM into failure mode
- if the hash algorithm is not supported. */
- /* This function does not use the sequence parameter. If it is necessary to import or export
- context, this will start the sequence in a local state and export the state to the input
- buffer. Will need to add a flag to the state structure to indicate that it needs to be imported
- before it can be used. (BLEH). */
- /* Return Value Meaning */
- /* 0 hash is TPM_ALG_NULL */
- /* >0 digest size */
- LIB_EXPORT UINT16
- CryptHashStart(
- PHASH_STATE hashState, // OUT: the running hash state
- TPM_ALG_ID hashAlg // IN: hash algorithm
- )
- {
- UINT16 retVal;
-
- TEST(hashAlg);
-
- hashState->hashAlg = hashAlg;
- if(hashAlg == TPM_ALG_NULL)
- {
- retVal = 0;
- }
- else
- {
- hashState->def = CryptGetHashDef(hashAlg);
- HASH_START(hashState);
- retVal = hashState->def->digestSize;
- }
- #undef HASH_START
- hashState->type = HASH_STATE_HASH;
- return retVal;
- }
- /* 10.2.13.6.3 CryptDigestUpdate() */
- /* Add data to a hash or HMAC, SMAC stack. */
- void
- CryptDigestUpdate(
- PHASH_STATE hashState, // IN: the hash context information
- UINT32 dataSize, // IN: the size of data to be added
- const BYTE *data // IN: data to be hashed
- )
- {
- if(hashState->hashAlg != TPM_ALG_NULL)
- {
- if((hashState->type == HASH_STATE_HASH)
- || (hashState->type == HASH_STATE_HMAC))
- HASH_DATA(hashState, dataSize, (BYTE *)data);
- #if SMAC_IMPLEMENTED
- else if(hashState->type == HASH_STATE_SMAC)
- (hashState->state.smac.smacMethods.data)(&hashState->state.smac.state,
- dataSize, data);
- #endif // SMAC_IMPLEMENTED
- else
- FAIL(FATAL_ERROR_INTERNAL);
- }
- return;
- }
- /* 10.2.13.6.4 CryptHashEnd() */
- /* Complete a hash or HMAC computation. This function will place the smaller of digestSize or the
- size of the digest in dOut. The number of bytes in the placed in the buffer is returned. If there
- is a failure, the returned value is <= 0. */
- /* Return Value Meaning */
- /* 0 no data returned */
- /* > 0 the number of bytes in the digest or dOutSize, whichever is smaller */
- LIB_EXPORT UINT16
- CryptHashEnd(
- PHASH_STATE hashState, // IN: the state of hash stack
- UINT32 dOutSize, // IN: size of digest buffer
- BYTE *dOut // OUT: hash digest
- )
- {
- pAssert(hashState->type == HASH_STATE_HASH);
- return HashEnd(hashState, dOutSize, dOut);
- }
- /* 10.2.13.6.5 CryptHashBlock() */
- /* Start a hash, hash a single block, update digest and return the size of the results. */
- /* The digestSize parameter can be smaller than the digest. If so, only the more significant
- bytes are returned. */
- /* Return Value Meaning */
- /* >= 0 number of bytes placed in dOut */
- LIB_EXPORT UINT16
- CryptHashBlock(
- TPM_ALG_ID hashAlg, // IN: The hash algorithm
- UINT32 dataSize, // IN: size of buffer to hash
- const BYTE *data, // IN: the buffer to hash
- UINT32 dOutSize, // IN: size of the digest buffer
- BYTE *dOut // OUT: digest buffer
- )
- {
- HASH_STATE state;
- CryptHashStart(&state, hashAlg);
- CryptDigestUpdate(&state, dataSize, data);
- return HashEnd(&state, dOutSize, dOut);
- }
- /* 10.2.13.6.6 CryptDigestUpdate2B() */
- /* This function updates a digest (hash or HMAC) with a TPM2B. */
- /* This function can be used for both HMAC and hash functions so the digestState is void so that
- either state type can be passed. */
- LIB_EXPORT void
- CryptDigestUpdate2B(
- PHASH_STATE state, // IN: the digest state
- const TPM2B *bIn // IN: 2B containing the data
- )
- {
- // Only compute the digest if a pointer to the 2B is provided.
- // In CryptDigestUpdate(), if size is zero or buffer is NULL, then no change
- // to the digest occurs. This function should not provide a buffer if bIn is
- // not provided.
- pAssert(bIn != NULL);
- CryptDigestUpdate(state, bIn->size, bIn->buffer);
- return;
- }
- /* 10.2.13.6.7 CryptHashEnd2B() */
- /* This function is the same as CryptCompleteHash() but the digest is placed in a TPM2B. This is the
- most common use and this is provided for specification clarity. digest.size should be set to
- indicate the number of bytes to place in the buffer */
- /* Return Value Meaning */
- /* >=0 the number of bytes placed in digest.buffer */
- LIB_EXPORT UINT16
- CryptHashEnd2B(
- PHASH_STATE state, // IN: the hash state
- P2B digest // IN: the size of the buffer Out: requested
- // number of bytes
- )
- {
- return CryptHashEnd(state, digest->size, digest->buffer);
- }
- /* 10.2.13.6.8 CryptDigestUpdateInt() */
- /* This function is used to include an integer value to a hash stack. The function marshals the
- integer into its canonical form before calling CryptDigestUpdate(). */
- LIB_EXPORT void
- CryptDigestUpdateInt(
- void *state, // IN: the state of hash stack
- UINT32 intSize, // IN: the size of 'intValue' in bytes
- UINT64 intValue // IN: integer value to be hashed
- )
- {
- #if LITTLE_ENDIAN_TPM
- intValue = REVERSE_ENDIAN_64(intValue);
- #endif
- CryptDigestUpdate(state, intSize, &((BYTE *)&intValue)[8 - intSize]);
- }
- /* 10.2.13.7 HMAC Functions */
- /* 10.2.13.7.1 CryptHmacStart() */
- /* This function is used to start an HMAC using a temp hash context. The function does the
- initialization of the hash with the HMAC key XOR iPad and updates the HMAC key XOR oPad. */
- /* The function returns the number of bytes in a digest produced by hashAlg. */
- /* Return Value Meaning */
- /* >= 0 number of bytes in digest produced by hashAlg (may be zero) */
- LIB_EXPORT UINT16
- CryptHmacStart(
- PHMAC_STATE state, // IN/OUT: the state buffer
- TPM_ALG_ID hashAlg, // IN: the algorithm to use
- UINT16 keySize, // IN: the size of the HMAC key
- const BYTE *key // IN: the HMAC key
- )
- {
- PHASH_DEF hashDef;
- BYTE * pb;
- UINT32 i;
- //
- hashDef = CryptGetHashDef(hashAlg);
- if(hashDef->digestSize != 0)
- {
- // If the HMAC key is larger than the hash block size, it has to be reduced
- // to fit. The reduction is a digest of the hashKey.
- if(keySize > hashDef->blockSize)
- {
- // if the key is too big, reduce it to a digest of itself
- state->hmacKey.t.size = CryptHashBlock(hashAlg, keySize, key,
- hashDef->digestSize,
- state->hmacKey.t.buffer);
- }
- else
- {
- memcpy(state->hmacKey.t.buffer, key, keySize);
- state->hmacKey.t.size = keySize;
- }
- // XOR the key with iPad (0x36)
- pb = state->hmacKey.t.buffer;
- for(i = state->hmacKey.t.size; i > 0; i--)
- *pb++ ^= 0x36;
-
- // if the keySize is smaller than a block, fill the rest with 0x36
- for(i = hashDef->blockSize - state->hmacKey.t.size; i > 0; i--)
- *pb++ = 0x36;
-
- // Increase the oPadSize to a full block
- state->hmacKey.t.size = hashDef->blockSize;
-
- // Start a new hash with the HMAC key
- // This will go in the caller's state structure and may be a sequence or not
- CryptHashStart((PHASH_STATE)state, hashAlg);
- CryptDigestUpdate((PHASH_STATE)state, state->hmacKey.t.size,
- state->hmacKey.t.buffer);
- // XOR the key block with 0x5c ^ 0x36
- for(pb = state->hmacKey.t.buffer, i = hashDef->blockSize; i > 0; i--)
- *pb++ ^= (0x5c ^ 0x36);
- }
- // Set the hash algorithm
- state->hashState.hashAlg = hashAlg;
- // Set the hash state type
- state->hashState.type = HASH_STATE_HMAC;
-
- return hashDef->digestSize;
- }
- /* 10.2.13.7.2 CryptHmacEnd() */
- /* This function is called to complete an HMAC. It will finish the current digest, and start a new digest. It will then add the oPadKey and the completed digest and return the results in dOut. It will not return more than dOutSize bytes. */
- /* Return Value Meaning */
- /* >= 0 number of bytes in dOut (may be zero) */
- LIB_EXPORT UINT16
- CryptHmacEnd(
- PHMAC_STATE state, // IN: the hash state buffer
- UINT32 dOutSize, // IN: size of digest buffer
- BYTE *dOut // OUT: hash digest
- )
- {
- BYTE temp[MAX_DIGEST_SIZE];
- PHASH_STATE hState = (PHASH_STATE)&state->hashState;
-
- #if SMAC_IMPLEMENTED
- if(hState->type == HASH_STATE_SMAC)
- return (state->hashState.state.smac.smacMethods.end)
- (&state->hashState.state.smac.state,
- dOutSize,
- dOut);
- #endif
- pAssert(hState->type == HASH_STATE_HMAC);
- hState->def = CryptGetHashDef(hState->hashAlg);
- // Change the state type for completion processing
- hState->type = HASH_STATE_HASH;
- if(hState->hashAlg == TPM_ALG_NULL)
- dOutSize = 0;
- else
- {
-
- // Complete the current hash
- HashEnd(hState, hState->def->digestSize, temp);
- // Do another hash starting with the oPad
- CryptHashStart(hState, hState->hashAlg);
- CryptDigestUpdate(hState, state->hmacKey.t.size, state->hmacKey.t.buffer);
- CryptDigestUpdate(hState, hState->def->digestSize, temp);
- }
- return HashEnd(hState, dOutSize, dOut);
- }
- /* 10.2.13.7.3 CryptHmacStart2B() */
- /* This function starts an HMAC and returns the size of the digest that will be produced. */
- /* This function is provided to support the most common use of starting an HMAC with a TPM2B key. */
- /* The caller must provide a block of memory in which the hash sequence state is kept. The caller
- should not alter the contents of this buffer until the hash sequence is completed or
- abandoned. */
- /* Return Value Meaning */
- /* > 0 the digest size of the algorithm */
- /* = 0 the hashAlg was TPM_ALG_NULL */
- LIB_EXPORT UINT16
- CryptHmacStart2B(
- PHMAC_STATE hmacState, // OUT: the state of HMAC stack. It will be used
- // in HMAC update and completion
- TPMI_ALG_HASH hashAlg, // IN: hash algorithm
- P2B key // IN: HMAC key
- )
- {
- return CryptHmacStart(hmacState, hashAlg, key->size, key->buffer);
- }
- /* 10.2.13.7.4 CryptHmacEnd2B() */
- /* This function is the same as CryptHmacEnd() but the HMAC result is returned in a TPM2B which is the most common use. */
- /* Return Value Meaning */
- /* >=0 the number of bytes placed in digest */
- LIB_EXPORT UINT16
- CryptHmacEnd2B(
- PHMAC_STATE hmacState, // IN: the state of HMAC stack
- P2B digest // OUT: HMAC
- )
- {
- return CryptHmacEnd(hmacState, digest->size, digest->buffer);
- }
- /* 10.2.13.8 Mask and Key Generation Functions */
- /* 10.2.13.8.1 CryptMGF_KDF() */
- /* This function performs MGF1/KDF1 or KDF2 using the selected hash. KDF1 and KDF2 are T(n) = T(n-1)
- || H(seed || counter) with the difference being that, with KDF1, counter starts at 0 but with
- KDF2, counter starts at 1. The caller determines which version by setting the initial value of
- counter to either 0 or 1. */
- /* Return Value Meaning */
- /* 0 hash algorithm was TPM_ALG_NULL */
- /* > 0 should be the same as mSize */
- LIB_EXPORT UINT16
- CryptMGF_KDF(
- UINT32 mSize, // IN: length of the mask to be produced
- BYTE *mask, // OUT: buffer to receive the mask
- TPM_ALG_ID hashAlg, // IN: hash to use
- UINT32 seedSize, // IN: size of the seed
- BYTE *seed, // IN: seed size
- UINT32 counter // IN: counter initial value
- )
- {
- HASH_STATE hashState;
- PHASH_DEF hDef = CryptGetHashDef(hashAlg);
- UINT32 hLen;
- UINT32 bytes;
- //
- // If there is no digest to compute return
- if((hDef->digestSize == 0) || (mSize == 0))
- return 0;
- if(counter != 0)
- counter = 1;
- hLen = hDef->digestSize;
- for(bytes = 0; bytes < mSize; bytes += hLen)
- {
- // Start the hash and include the seed and counter
- CryptHashStart(&hashState, hashAlg);
- CryptDigestUpdate(&hashState, seedSize, seed);
- CryptDigestUpdateInt(&hashState, 4, counter);
- // Get as much as will fit.
- CryptHashEnd(&hashState, MIN((mSize - bytes), hLen),
- &mask[bytes]);
- counter++;
- }
- return (UINT16)mSize;
- }
- /* 10.2.13.8.2 CryptKDFa() */
- /* This function performs the key generation according to Part 1 of the TPM specification. */
- /* This function returns the number of bytes generated which may be zero. */
- /* The key and keyStream pointers are not allowed to be NULL. The other pointer values may be
- NULL. The value of sizeInBits must be no larger than (2^18)-1 = 256K bits (32385 bytes). */
- /* The once parameter is set to allow incremental generation of a large value. If this flag is
- TRUE, sizeInBits will be used in the HMAC computation but only one iteration of the KDF is
- performed. This would be used for XOR obfuscation so that the mask value can be generated in
- digest-sized chunks rather than having to be generated all at once in an arbitrarily large
- buffer and then XORed into the result. If once is TRUE, then sizeInBits must be a multiple of
- 8. */
- /* Any error in the processing of this command is considered fatal. */
- /* Return Value Meaning */
- /* 0 hash algorithm is not supported or is TPM_ALG_NULL */
- /* > 0 the number of bytes in the keyStream buffer */
- LIB_EXPORT UINT16
- CryptKDFa(
- TPM_ALG_ID hashAlg, // IN: hash algorithm used in HMAC
- const TPM2B *key, // IN: HMAC key
- const TPM2B *label, // IN: a label for the KDF
- const TPM2B *contextU, // IN: context U
- const TPM2B *contextV, // IN: context V
- UINT32 sizeInBits, // IN: size of generated key in bits
- BYTE *keyStream, // OUT: key buffer
- UINT32 *counterInOut, // IN/OUT: caller may provide the iteration
- // counter for incremental operations to
- // avoid large intermediate buffers.
- UINT16 blocks // IN: If non-zero, this is the maximum number
- // of blocks to be returned, regardless
- // of sizeInBits
- )
- {
- UINT32 counter = 0; // counter value
- INT16 bytes; // number of bytes to produce
- UINT16 generated; // number of bytes generated
- BYTE *stream = keyStream;
- HMAC_STATE hState;
- UINT16 digestSize = CryptHashGetDigestSize(hashAlg);
-
- pAssert(key != NULL && keyStream != NULL);
-
- TEST(TPM_ALG_KDF1_SP800_108);
-
- if(digestSize == 0)
- return 0;
-
- if(counterInOut != NULL)
- counter = *counterInOut;
-
- // If the size of the request is larger than the numbers will handle,
- // it is a fatal error.
- pAssert(((sizeInBits + 7) / 8) <= INT16_MAX);
-
- // The number of bytes to be generated is the smaller of the sizeInBits bytes or
- // the number of requested blocks. The number of blocks is the smaller of the
- // number requested or the number allowed by sizeInBits. A partial block is
- // a full block.
- bytes = (blocks > 0) ? blocks * digestSize : (UINT16)BITS_TO_BYTES(sizeInBits);
- generated = bytes;
-
- // Generate required bytes
- for(; bytes > 0; bytes -= digestSize)
- {
- counter++;
- // Start HMAC
- if(CryptHmacStart(&hState, hashAlg, key->size, key->buffer) == 0)
- return 0;
- // Adding counter
- CryptDigestUpdateInt(&hState.hashState, 4, counter);
-
- // Adding label
- if(label != NULL)
- HASH_DATA(&hState.hashState, label->size, (BYTE *)label->buffer);
- // Add a null. SP108 is not very clear about when the 0 is needed but to
- // make this like the previous version that did not add an 0x00 after
- // a null-terminated string, this version will only add a null byte
- // if the label parameter did not end in a null byte, or if no label
- // is present.
- if((label == NULL)
- || (label->size == 0)
- || (label->buffer[label->size - 1] != 0))
- CryptDigestUpdateInt(&hState.hashState, 1, 0);
- // Adding contextU
- if(contextU != NULL)
- HASH_DATA(&hState.hashState, contextU->size, contextU->buffer);
- // Adding contextV
- if(contextV != NULL)
- HASH_DATA(&hState.hashState, contextV->size, contextV->buffer);
- // Adding size in bits
- CryptDigestUpdateInt(&hState.hashState, 4, sizeInBits);
-
- // Complete and put the data in the buffer
- CryptHmacEnd(&hState, bytes, stream);
- stream = &stream[digestSize];
- }
- // Masking in the KDF is disabled. If the calling function wants something
- // less than even number of bytes, then the caller should do the masking
- // because there is no universal way to do it here
- if(counterInOut != NULL)
- *counterInOut = counter;
- return generated;
- }
- /* 10.2.13.8.3 CryptKDFe() */
- /* This function implements KDFe() as defined in TPM specification part 1. */
- /* This function returns the number of bytes generated which may be zero. */
- /* The Z and keyStream pointers are not allowed to be NULL. The other pointer values may be
- NULL. The value of sizeInBits must be no larger than (2^18)-1 = 256K bits (32385 bytes). Any
- error in the processing of this command is considered fatal. */
- /* Return Value Meaning */
- /* 0 hash algorithm is not supported or is TPM_ALG_NULL */
- /* > 0 the number of bytes in the keyStream buffer */
- LIB_EXPORT UINT16
- CryptKDFe(
- TPM_ALG_ID hashAlg, // IN: hash algorithm used in HMAC
- TPM2B *Z, // IN: Z
- const TPM2B *label, // IN: a label value for the KDF
- TPM2B *partyUInfo, // IN: PartyUInfo
- TPM2B *partyVInfo, // IN: PartyVInfo
- UINT32 sizeInBits, // IN: size of generated key in bits
- BYTE *keyStream // OUT: key buffer
- )
- {
- HASH_STATE hashState;
- PHASH_DEF hashDef = CryptGetHashDef(hashAlg);
-
- UINT32 counter = 0; // counter value
- UINT16 hLen;
- BYTE *stream = keyStream;
- INT16 bytes; // number of bytes to generate
-
- pAssert(keyStream != NULL && Z != NULL && ((sizeInBits + 7) / 8) < INT16_MAX);
- //
- hLen = hashDef->digestSize;
- bytes = (INT16)((sizeInBits + 7) / 8);
- if(hashAlg == TPM_ALG_NULL || bytes == 0)
- return 0;
-
- // Generate required bytes
- //The inner loop of that KDF uses:
- // Hash[i] := H(counter | Z | OtherInfo) (5)
- // Where:
- // Hash[i] the hash generated on the i-th iteration of the loop.
- // H() an approved hash function
- // counter a 32-bit counter that is initialized to 1 and incremented
- // on each iteration
- // Z the X coordinate of the product of a public ECC key and a
- // different private ECC key.
- // OtherInfo a collection of qualifying data for the KDF defined below.
- // In this specification, OtherInfo will be constructed by:
- // OtherInfo := Use | PartyUInfo | PartyVInfo
- for(; bytes > 0; stream = &stream[hLen], bytes = bytes - hLen)
- {
- if(bytes < hLen)
- hLen = bytes;
- counter++;
- // Do the hash
- CryptHashStart(&hashState, hashAlg);
- // Add counter
- CryptDigestUpdateInt(&hashState, 4, counter);
-
- // Add Z
- if(Z != NULL)
- CryptDigestUpdate2B(&hashState, Z);
- // Add label
- if(label != NULL)
- CryptDigestUpdate2B(&hashState, label);
- // Add a null. SP108 is not very clear about when the 0 is needed but to
- // make this like the previous version that did not add an 0x00 after
- // a null-terminated string, this version will only add a null byte
- // if the label parameter did not end in a null byte, or if no label
- // is present.
- if((label == NULL)
- || (label->size == 0)
- || (label->buffer[label->size - 1] != 0))
- CryptDigestUpdateInt(&hashState, 1, 0);
- // Add PartyUInfo
- if(partyUInfo != NULL)
- CryptDigestUpdate2B(&hashState, partyUInfo);
-
- // Add PartyVInfo
- if(partyVInfo != NULL)
- CryptDigestUpdate2B(&hashState, partyVInfo);
-
- // Compute Hash. hLen was changed to be the smaller of bytes or hLen
- // at the start of each iteration.
- CryptHashEnd(&hashState, hLen, stream);
- }
-
- // Mask off bits if the required bits is not a multiple of byte size
- if((sizeInBits % 8) != 0)
- keyStream[0] &= ((1 << (sizeInBits % 8)) - 1);
-
- return (UINT16)((sizeInBits + 7) / 8);
- }
|