1/* This file includes functions that were extracted from the TPM2
2 * source, but were present in files not included in compilation.
3 */
4#include "Global.h"
5#include "CryptoEngine.h"
6
7#include <string.h>
8
9UINT16 _cpri__StartHMAC(
10  TPM_ALG_ID hashAlg,           //   IN: the algorithm to use
11  BOOL sequence,                //   IN: indicates if the state should be saved
12  CPRI_HASH_STATE * state,      //   IN/OUT: the state buffer
13  UINT16 keySize,               //   IN: the size of the HMAC key
14  BYTE * key,                   //   IN: the HMAC key
15  TPM2B * oPadKey               //   OUT: the key prepared for the oPad round
16  )
17{
18      CPRI_HASH_STATE localState;
19      UINT16           blockSize = _cpri__GetHashBlockSize(hashAlg);
20      UINT16           digestSize;
21      BYTE            *pb;         // temp pointer
22      UINT32           i;
23      // If the key size is larger than the block size, then the hash of the key
24      // is used as the key
25      if(keySize > blockSize)
26      {
27          // large key so digest
28          if((digestSize = _cpri__StartHash(hashAlg, FALSE, &localState)) == 0)
29              return 0;
30          _cpri__UpdateHash(&localState, keySize, key);
31          _cpri__CompleteHash(&localState, digestSize, oPadKey->buffer);
32          oPadKey->size = digestSize;
33      }
34      else
35      {
36          // key size is ok
37          memcpy(oPadKey->buffer, key, keySize);
38          oPadKey->size = keySize;
39      }
40      // XOR the key with iPad (0x36)
41      pb = oPadKey->buffer;
42      for(i = oPadKey->size; i > 0; i--)
43          *pb++ ^= 0x36;
44      // if the keySize is smaller than a block, fill the rest with 0x36
45      for(i = blockSize - oPadKey->size; i > 0; i--)
46          *pb++ = 0x36;
47      // Increase the oPadSize to a full block
48      oPadKey->size = blockSize;
49      // Start a new hash with the HMAC key
50      // This will go in the caller's state structure and may be a sequence or not
51      if((digestSize = _cpri__StartHash(hashAlg, sequence, state)) > 0)
52      {
53          _cpri__UpdateHash(state, oPadKey->size, oPadKey->buffer);
54          // XOR the key block with 0x5c ^ 0x36
55          for(pb = oPadKey->buffer, i = blockSize; i > 0; i--)
56              *pb++ ^= (0x5c ^ 0x36);
57      }
58      return digestSize;
59}
60
61UINT16 _cpri__CompleteHMAC(
62  CPRI_HASH_STATE * hashState,  //   IN: the state of hash stack
63  TPM2B * oPadKey,              //   IN: the HMAC key in oPad format
64  UINT32 dOutSize,              //   IN: size of digest buffer
65  BYTE * dOut                   //   OUT: hash digest
66  )
67{
68      BYTE             digest[MAX_DIGEST_SIZE];
69      CPRI_HASH_STATE *state = (CPRI_HASH_STATE *)hashState;
70      CPRI_HASH_STATE localState;
71      UINT16           digestSize = _cpri__GetDigestSize(state->hashAlg);
72      _cpri__CompleteHash(hashState, digestSize, digest);
73      // Using the local hash state, do a hash with the oPad
74      if(_cpri__StartHash(state->hashAlg, FALSE, &localState) != digestSize)
75          return 0;
76      _cpri__UpdateHash(&localState, oPadKey->size, oPadKey->buffer);
77      _cpri__UpdateHash(&localState, digestSize, digest);
78      return _cpri__CompleteHash(&localState, dOutSize, dOut);
79}
80
81UINT16 _cpri__KDFa(
82  TPM_ALG_ID hashAlg,           //   IN: hash algorithm used in HMAC
83  TPM2B * key,                  //   IN: HMAC key
84  const char *label,            //   IN: a 0-byte terminated label used in KDF
85  TPM2B * contextU,             //   IN: context U
86  TPM2B * contextV,             //   IN: context V
87  UINT32 sizeInBits,            //   IN: size of generated key in bit
88  BYTE * keyStream,             //   OUT: key buffer
89  UINT32 * counterInOut,        //   IN/OUT: caller may provide the iteration
90  //   counter for incremental operations to
91  //   avoid large intermediate buffers.
92  BOOL once                     //   IN: TRUE if only one iteration is
93  // performed FALSE if iteration count determined by "sizeInBits"
94  )
95{
96    UINT32                         counter = 0;    // counter value
97    INT32                          lLen = 0;       // length of the label
98    INT16                          hLen;           // length of the hash
99    INT16                          bytes;          // number of bytes to produce
100    BYTE                          *stream = keyStream;
101    BYTE                           marshaledUint32[4];
102    CPRI_HASH_STATE                hashState;
103    TPM2B_MAX_HASH_BLOCK           hmacKey;
104    pAssert(key != NULL && keyStream != NULL);
105    pAssert(once == FALSE || (sizeInBits & 7) == 0);
106    if(counterInOut != NULL)
107        counter = *counterInOut;
108    // Prepare label buffer. Calculate its size and keep the last 0 byte
109    if(label != NULL)
110        for(lLen = 0; label[lLen++] != 0; );
111    // Get the hash size. If it is less than or 0, either the
112    // algorithm is not supported or the hash is TPM_ALG_NULL
113//
114   // In either case the digest size is zero. This is the only return
115   // other than the one at the end. All other exits from this function
116   // are fatal errors. After we check that the algorithm is supported
117   // anything else that goes wrong is an implementation flaw.
118   if((hLen = (INT16) _cpri__GetDigestSize(hashAlg)) == 0)
119       return 0;
120   // If the size of the request is larger than the numbers will handle,
121   // it is a fatal error.
122   pAssert(((sizeInBits + 7)/ 8) <= INT16_MAX);
123   bytes = once ? hLen : (INT16)((sizeInBits + 7) / 8);
124   // Generate required bytes
125   for (; bytes > 0; stream = &stream[hLen], bytes = bytes - hLen)
126   {
127       if(bytes < hLen)
128           hLen = bytes;
129        counter++;
130        // Start HMAC
131        if(_cpri__StartHMAC(hashAlg,
132                            FALSE,
133                            &hashState,
134                            key->size,
135                            &key->buffer[0],
136                            &hmacKey.b)          <= 0)
137            FAIL(FATAL_ERROR_INTERNAL);
138        // Adding counter
139        UINT32_TO_BYTE_ARRAY(counter, marshaledUint32);
140        _cpri__UpdateHash(&hashState, sizeof(UINT32), marshaledUint32);
141        // Adding label
142        if(label != NULL)
143            _cpri__UpdateHash(&hashState,   lLen, (BYTE *)label);
144        // Adding contextU
145        if(contextU != NULL)
146            _cpri__UpdateHash(&hashState, contextU->size, contextU->buffer);
147        // Adding contextV
148        if(contextV != NULL)
149            _cpri__UpdateHash(&hashState, contextV->size, contextV->buffer);
150        // Adding size in bits
151        UINT32_TO_BYTE_ARRAY(sizeInBits, marshaledUint32);
152        _cpri__UpdateHash(&hashState, sizeof(UINT32), marshaledUint32);
153        // Compute HMAC. At the start of each iteration, hLen is set
154        // to the smaller of hLen and bytes. This causes bytes to decrement
155        // exactly to zero to complete the loop
156        _cpri__CompleteHMAC(&hashState, &hmacKey.b, hLen, stream);
157   }
158   // Mask off bits if the required bits is not a multiple of byte size
159   if((sizeInBits % 8) != 0)
160       keyStream[0] &= ((1 << (sizeInBits % 8)) - 1);
161   if(counterInOut != NULL)
162       *counterInOut = counter;
163   return (CRYPT_RESULT)((sizeInBits + 7)/8);
164}
165
166UINT16 _cpri__KDFe(
167  TPM_ALG_ID hashAlg,           //   IN: hash algorithm used in HMAC
168  TPM2B * Z,                    //   IN: Z
169  const char *label,            //   IN: a 0 terminated label using in KDF
170  TPM2B * partyUInfo,           //   IN: PartyUInfo
171  TPM2B * partyVInfo,           //   IN: PartyVInfo
172  UINT32 sizeInBits,            //   IN: size of generated key in bit
173  BYTE * keyStream              //   OUT: key buffer
174  )
175{
176    UINT32       counter = 0;        // counter value
177    UINT32       lSize = 0;
178    BYTE        *stream = keyStream;
179    CPRI_HASH_STATE         hashState;
180    INT16        hLen = (INT16) _cpri__GetDigestSize(hashAlg);
181    INT16        bytes;              // number of bytes to generate
182    BYTE         marshaledUint32[4];
183    pAssert(     keyStream != NULL
184                 && Z != NULL
185                 && ((sizeInBits + 7) / 8) < INT16_MAX);
186    if(hLen == 0)
187        return 0;
188    bytes = (INT16)((sizeInBits + 7) / 8);
189    // Prepare label buffer. Calculate its size and keep the last 0 byte
190    if(label != NULL)
191        for(lSize = 0; label[lSize++] != 0;);
192    // Generate required bytes
193    //The inner loop of that KDF uses:
194    // Hashi := H(counter | Z | OtherInfo) (5)
195    // Where:
196    // Hashi    the hash generated on the i-th iteration of the loop.
197    // H()      an approved hash function
198    // counter a 32-bit counter that is initialized to 1 and incremented
199    //          on each iteration
200    // Z        the X coordinate of the product of a public ECC key and a
201    //          different private ECC key.
202    // OtherInfo    a collection of qualifying data for the KDF defined below.
203    // In this specification, OtherInfo will be constructed by:
204    //      OtherInfo := Use | PartyUInfo | PartyVInfo
205    for (; bytes > 0; stream = &stream[hLen], bytes = bytes - hLen)
206    {
207        if(bytes < hLen)
208            hLen = bytes;
209//
210        counter++;
211        // Start hash
212        if(_cpri__StartHash(hashAlg, FALSE,   &hashState) == 0)
213            return 0;
214        // Add counter
215        UINT32_TO_BYTE_ARRAY(counter, marshaledUint32);
216        _cpri__UpdateHash(&hashState, sizeof(UINT32), marshaledUint32);
217        // Add Z
218        if(Z != NULL)
219            _cpri__UpdateHash(&hashState, Z->size, Z->buffer);
220        // Add label
221        if(label != NULL)
222             _cpri__UpdateHash(&hashState, lSize, (BYTE *)label);
223        else
224              // The SP800-108 specification requires a zero between the label
225              // and the context.
226              _cpri__UpdateHash(&hashState, 1, (BYTE *)"");
227        // Add PartyUInfo
228        if(partyUInfo != NULL)
229            _cpri__UpdateHash(&hashState, partyUInfo->size, partyUInfo->buffer);
230        // Add PartyVInfo
231        if(partyVInfo != NULL)
232            _cpri__UpdateHash(&hashState, partyVInfo->size, partyVInfo->buffer);
233        // Compute Hash. hLen was changed to be the smaller of bytes or hLen
234        // at the start of each iteration.
235        _cpri__CompleteHash(&hashState, hLen, stream);
236   }
237   // Mask off bits if the required bits is not a multiple of byte size
238   if((sizeInBits % 8) != 0)
239       keyStream[0] &= ((1 << (sizeInBits % 8)) - 1);
240   return (CRYPT_RESULT)((sizeInBits + 7) / 8);
241}
242
243UINT16 _cpri__GenerateSeededRandom(
244  INT32 randomSize,             //   IN: the size of the request
245  BYTE * random,                //   OUT: receives the data
246  TPM_ALG_ID hashAlg,           //   IN: used by KDF version but not here
247  TPM2B * seed,                 //   IN: the seed value
248  const char *label,            //   IN: a label string (optional)
249  TPM2B * partyU,               //   IN: other data (oprtional)
250  TPM2B * partyV                //   IN: still more (optional)
251  )
252{
253   return (_cpri__KDFa(hashAlg, seed, label, partyU, partyV,
254                       randomSize * 8, random, NULL, FALSE));
255}
256