• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
_cpri__StartHMAC(TPM_ALG_ID hashAlg,BOOL sequence,CPRI_HASH_STATE * state,UINT16 keySize,BYTE * key,TPM2B * oPadKey)9 UINT16 _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 
_cpri__CompleteHMAC(CPRI_HASH_STATE * hashState,TPM2B * oPadKey,UINT32 dOutSize,BYTE * dOut)61 UINT16 _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 
_cpri__KDFa(TPM_ALG_ID hashAlg,TPM2B * key,const char * label,TPM2B * contextU,TPM2B * contextV,UINT32 sizeInBits,BYTE * keyStream,UINT32 * counterInOut,BOOL once)81 UINT16 _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 
_cpri__KDFe(TPM_ALG_ID hashAlg,TPM2B * Z,const char * label,TPM2B * partyUInfo,TPM2B * partyVInfo,UINT32 sizeInBits,BYTE * keyStream)166 UINT16 _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 
_cpri__GenerateSeededRandom(INT32 randomSize,BYTE * random,TPM_ALG_ID hashAlg,TPM2B * seed,const char * label,TPM2B * partyU,TPM2B * partyV)243 UINT16 _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