summaryrefslogtreecommitdiffstats
path: root/src/tpm2/crypto/openssl/CryptHash.c
blob: cb5bd0fb5f95c4ea498483439fbdce4252a95823 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
/********************************************************************************/
/*										*/
/*		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. */
#if 0		// libtpms added
LIB_EXPORT const BYTE *
CryptHashGetOid(
		TPM_ALG_ID      hashAlg
		)
{
    return CryptGetHashDef(hashAlg)->OID;
}
#endif		// libtpms added
/* 10.2.13.4.8	CryptHashGetContextAlg() */
/* This function returns the hash algorithm associated with a hash context. */
#if 0		// libtpms added
TPM_ALG_ID
CryptHashGetContextAlg(
		       PHASH_STATE      state          // IN: the context to check
		       )
{
    return state->hashAlg;
}
#endif		// libtpms added
/* 10.2.13.5	State Import and Export */
/* 10.2.13.5.1	CryptHashCopyState */
/* This function is used to clone a HASH_STATE. */
#if 0 // libtpms added
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;
}
#endif // libtpms added
#if 0  // libtpms added
/* 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));
		}
	}
}
#endif  // libtpms added
/* 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);
}