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