1 /* Microsoft Reference Implementation for TPM 2.0
2 *
3 * The copyright in this software is being made available under the BSD License,
4 * included below. This software may be subject to other third party and
5 * contributor rights, including patent rights, and no such rights are granted
6 * under this license.
7 *
8 * Copyright (c) Microsoft Corporation
9 *
10 * All rights reserved.
11 *
12 * BSD License
13 *
14 * Redistribution and use in source and binary forms, with or without modification,
15 * are permitted provided that the following conditions are met:
16 *
17 * Redistributions of source code must retain the above copyright notice, this list
18 * of conditions and the following disclaimer.
19 *
20 * Redistributions in binary form must reproduce the above copyright notice, this
21 * list of conditions and the following disclaimer in the documentation and/or
22 * other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 //** Introduction
36 //
37 // This file contains the implementation of the symmetric block cipher modes
38 // allowed for a TPM. These functions only use the single block encryption functions
39 // of the selected symmetric crypto library.
40
41 //** Includes, Defines, and Typedefs
42 #include "Tpm.h"
43
44 #include "CryptSym.h"
45
46 #define KEY_BLOCK_SIZES(ALG, alg) \
47 static const INT16 alg##KeyBlockSizes[] = { \
48 ALG##_KEY_SIZES_BITS, -1, ALG##_BLOCK_SIZES };
49
FOR_EACH_SYM(KEY_BLOCK_SIZES)50 FOR_EACH_SYM(KEY_BLOCK_SIZES)
51
52 //** Initialization and Data Access Functions
53 //
54 //*** CryptSymInit()
55 // This function is called to do _TPM_Init processing
56 BOOL
57 CryptSymInit(
58 void
59 )
60 {
61 return TRUE;
62 }
63
64 //*** CryptSymStartup()
65 // This function is called to do TPM2_Startup() processing
66 BOOL
CryptSymStartup(void)67 CryptSymStartup(
68 void
69 )
70 {
71 return TRUE;
72 }
73
74 //*** CryptGetSymmetricBlockSize()
75 // This function returns the block size of the algorithm. The table of bit sizes has
76 // an entry for each allowed key size. The entry for a key size is 0 if the TPM does
77 // not implement that key size. The key size table is delimited with a negative number
78 // (-1). After the delimiter is a list of block sizes with each entry corresponding
79 // to the key bit size. For most symmetric algorithms, the block size is the same
80 // regardless of the key size but this arrangement allows them to be different.
81 // Return Type: INT16
82 // <= 0 cipher not supported
83 // > 0 the cipher block size in bytes
84 LIB_EXPORT INT16
CryptGetSymmetricBlockSize(TPM_ALG_ID symmetricAlg,UINT16 keySizeInBits)85 CryptGetSymmetricBlockSize(
86 TPM_ALG_ID symmetricAlg, // IN: the symmetric algorithm
87 UINT16 keySizeInBits // IN: the key size
88 )
89 {
90 const INT16 *sizes;
91 INT16 i;
92 #define ALG_CASE(SYM, sym) case TPM_ALG_##SYM: sizes = sym##KeyBlockSizes; break
93 switch(symmetricAlg)
94 {
95 #define GET_KEY_BLOCK_POINTER(SYM, sym) \
96 case TPM_ALG_##SYM: \
97 sizes = sym##KeyBlockSizes; \
98 break;
99 // Get the pointer to the block size array
100 FOR_EACH_SYM(GET_KEY_BLOCK_POINTER);
101
102 default:
103 return 0;
104 }
105 // Find the index of the indicated keySizeInBits
106 for(i = 0; *sizes >= 0; i++, sizes++)
107 {
108 if(*sizes == keySizeInBits)
109 break;
110 }
111 // If sizes is pointing at the end of the list of key sizes, then the desired
112 // key size was not found so set the block size to zero.
113 if(*sizes++ < 0)
114 return 0;
115 // Advance until the end of the list is found
116 while(*sizes++ >= 0);
117 // sizes is pointing to the first entry in the list of block sizes. Use the
118 // ith index to find the block size for the corresponding key size.
119 return sizes[i];
120 }
121
122 //** Symmetric Encryption
123 // This function performs symmetric encryption based on the mode.
124 // Return Type: TPM_RC
125 // TPM_RC_SIZE 'dSize' is not a multiple of the block size for an
126 // algorithm that requires it
127 // TPM_RC_FAILURE Fatal error
128 LIB_EXPORT TPM_RC
CryptSymmetricEncrypt(BYTE * dOut,TPM_ALG_ID algorithm,UINT16 keySizeInBits,const BYTE * key,TPM2B_IV * ivInOut,TPM_ALG_ID mode,INT32 dSize,const BYTE * dIn)129 CryptSymmetricEncrypt(
130 BYTE *dOut, // OUT:
131 TPM_ALG_ID algorithm, // IN: the symmetric algorithm
132 UINT16 keySizeInBits, // IN: key size in bits
133 const BYTE *key, // IN: key buffer. The size of this buffer
134 // in bytes is (keySizeInBits + 7) / 8
135 TPM2B_IV *ivInOut, // IN/OUT: IV for decryption.
136 TPM_ALG_ID mode, // IN: Mode to use
137 INT32 dSize, // IN: data size (may need to be a
138 // multiple of the blockSize)
139 const BYTE *dIn // IN: data buffer
140 )
141 {
142 BYTE *pIv;
143 int i;
144 BYTE tmp[MAX_SYM_BLOCK_SIZE];
145 BYTE *pT;
146 tpmCryptKeySchedule_t keySchedule;
147 INT16 blockSize;
148 TpmCryptSetSymKeyCall_t encrypt;
149 BYTE *iv;
150 BYTE defaultIv[MAX_SYM_BLOCK_SIZE] = {0};
151 //
152 pAssert(dOut != NULL && key != NULL && dIn != NULL);
153 if(dSize == 0)
154 return TPM_RC_SUCCESS;
155
156 TEST(algorithm);
157 blockSize = CryptGetSymmetricBlockSize(algorithm, keySizeInBits);
158 if(blockSize == 0)
159 return TPM_RC_FAILURE;
160 // If the iv is provided, then it is expected to be block sized. In some cases,
161 // the caller is providing an array of 0's that is equal to [MAX_SYM_BLOCK_SIZE]
162 // with no knowledge of the actual block size. This function will set it.
163 if((ivInOut != NULL) && (mode != TPM_ALG_ECB))
164 {
165 ivInOut->t.size = blockSize;
166 iv = ivInOut->t.buffer;
167 }
168 else
169 iv = defaultIv;
170 pIv = iv;
171
172 // Create encrypt key schedule and set the encryption function pointer.
173 switch (algorithm)
174 {
175 FOR_EACH_SYM(ENCRYPT_CASE)
176
177 default:
178 return TPM_RC_SYMMETRIC;
179 }
180 switch(mode)
181 {
182 #if ALG_CTR
183 case TPM_ALG_CTR:
184 for(; dSize > 0; dSize -= blockSize)
185 {
186 // Encrypt the current value of the IV(counter)
187 ENCRYPT(&keySchedule, iv, tmp);
188
189 //increment the counter (counter is big-endian so start at end)
190 for(i = blockSize - 1; i >= 0; i--)
191 if((iv[i] += 1) != 0)
192 break;
193 // XOR the encrypted counter value with input and put into output
194 pT = tmp;
195 for(i = (dSize < blockSize) ? dSize : blockSize; i > 0; i--)
196 *dOut++ = *dIn++ ^ *pT++;
197 }
198 break;
199 #endif
200 #if ALG_OFB
201 case TPM_ALG_OFB:
202 // This is written so that dIn and dOut may be the same
203 for(; dSize > 0; dSize -= blockSize)
204 {
205 // Encrypt the current value of the "IV"
206 ENCRYPT(&keySchedule, iv, iv);
207
208 // XOR the encrypted IV into dIn to create the cipher text (dOut)
209 pIv = iv;
210 for(i = (dSize < blockSize) ? dSize : blockSize; i > 0; i--)
211 *dOut++ = (*pIv++ ^ *dIn++);
212 }
213 break;
214 #endif
215 #if ALG_CBC
216 case TPM_ALG_CBC:
217 // For CBC the data size must be an even multiple of the
218 // cipher block size
219 if((dSize % blockSize) != 0)
220 return TPM_RC_SIZE;
221 // XOR the data block into the IV, encrypt the IV into the IV
222 // and then copy the IV to the output
223 for(; dSize > 0; dSize -= blockSize)
224 {
225 pIv = iv;
226 for(i = blockSize; i > 0; i--)
227 *pIv++ ^= *dIn++;
228 ENCRYPT(&keySchedule, iv, iv);
229 pIv = iv;
230 for(i = blockSize; i > 0; i--)
231 *dOut++ = *pIv++;
232 }
233 break;
234 #endif
235 // CFB is not optional
236 case TPM_ALG_CFB:
237 // Encrypt the IV into the IV, XOR in the data, and copy to output
238 for(; dSize > 0; dSize -= blockSize)
239 {
240 // Encrypt the current value of the IV
241 ENCRYPT(&keySchedule, iv, iv);
242 pIv = iv;
243 for(i = (int)(dSize < blockSize) ? dSize : blockSize; i > 0; i--)
244 // XOR the data into the IV to create the cipher text
245 // and put into the output
246 *dOut++ = *pIv++ ^= *dIn++;
247 }
248 // If the inner loop (i loop) was smaller than blockSize, then dSize
249 // would have been smaller than blockSize and it is now negative. If
250 // it is negative, then it indicates how many bytes are needed to pad
251 // out the IV for the next round.
252 for(; dSize < 0; dSize++)
253 *pIv++ = 0;
254 break;
255 #if ALG_ECB
256 case TPM_ALG_ECB:
257 // For ECB the data size must be an even multiple of the
258 // cipher block size
259 if((dSize % blockSize) != 0)
260 return TPM_RC_SIZE;
261 // Encrypt the input block to the output block
262 for(; dSize > 0; dSize -= blockSize)
263 {
264 ENCRYPT(&keySchedule, dIn, dOut);
265 dIn = &dIn[blockSize];
266 dOut = &dOut[blockSize];
267 }
268 break;
269 #endif
270 default:
271 return TPM_RC_FAILURE;
272 }
273 return TPM_RC_SUCCESS;
274 }
275
276 //*** CryptSymmetricDecrypt()
277 // This function performs symmetric decryption based on the mode.
278 // Return Type: TPM_RC
279 // TPM_RC_FAILURE A fatal error
280 // TPM_RCS_SIZE 'dSize' is not a multiple of the block size for an
281 // algorithm that requires it
282 LIB_EXPORT TPM_RC
CryptSymmetricDecrypt(BYTE * dOut,TPM_ALG_ID algorithm,UINT16 keySizeInBits,const BYTE * key,TPM2B_IV * ivInOut,TPM_ALG_ID mode,INT32 dSize,const BYTE * dIn)283 CryptSymmetricDecrypt(
284 BYTE *dOut, // OUT: decrypted data
285 TPM_ALG_ID algorithm, // IN: the symmetric algorithm
286 UINT16 keySizeInBits, // IN: key size in bits
287 const BYTE *key, // IN: key buffer. The size of this buffer
288 // in bytes is (keySizeInBits + 7) / 8
289 TPM2B_IV *ivInOut, // IN/OUT: IV for decryption.
290 TPM_ALG_ID mode, // IN: Mode to use
291 INT32 dSize, // IN: data size (may need to be a
292 // multiple of the blockSize)
293 const BYTE *dIn // IN: data buffer
294 )
295 {
296 BYTE *pIv;
297 int i;
298 BYTE tmp[MAX_SYM_BLOCK_SIZE];
299 BYTE *pT;
300 tpmCryptKeySchedule_t keySchedule;
301 INT16 blockSize;
302 BYTE *iv;
303 TpmCryptSetSymKeyCall_t encrypt;
304 TpmCryptSetSymKeyCall_t decrypt;
305 BYTE defaultIv[MAX_SYM_BLOCK_SIZE] = {0};
306
307 // These are used but the compiler can't tell because they are initialized
308 // in case statements and it can't tell if they are always initialized
309 // when needed, so... Comment these out if the compiler can tell or doesn't
310 // care that these are initialized before use.
311 encrypt = NULL;
312 decrypt = NULL;
313
314 pAssert(dOut != NULL && key != NULL && dIn != NULL);
315 if(dSize == 0)
316 return TPM_RC_SUCCESS;
317
318 TEST(algorithm);
319 blockSize = CryptGetSymmetricBlockSize(algorithm, keySizeInBits);
320 if(blockSize == 0)
321 return TPM_RC_FAILURE;
322 // If the iv is provided, then it is expected to be block sized. In some cases,
323 // the caller is providing an array of 0's that is equal to [MAX_SYM_BLOCK_SIZE]
324 // with no knowledge of the actual block size. This function will set it.
325 if((ivInOut != NULL) && (mode != TPM_ALG_ECB))
326 {
327 ivInOut->t.size = blockSize;
328 iv = ivInOut->t.buffer;
329 }
330 else
331 iv = defaultIv;
332
333 pIv = iv;
334 // Use the mode to select the key schedule to create. Encrypt always uses the
335 // encryption schedule. Depending on the mode, decryption might use either
336 // the decryption or encryption schedule.
337 switch(mode)
338 {
339 #if ALG_CBC || ALG_ECB
340 case TPM_ALG_CBC: // decrypt = decrypt
341 case TPM_ALG_ECB:
342 // For ECB and CBC, the data size must be an even multiple of the
343 // cipher block size
344 if((dSize % blockSize) != 0)
345 return TPM_RC_SIZE;
346 switch (algorithm)
347 {
348 FOR_EACH_SYM(DECRYPT_CASE)
349 default:
350 return TPM_RC_SYMMETRIC;
351 }
352 break;
353 #endif
354 default:
355 // For the remaining stream ciphers, use encryption to decrypt
356 switch (algorithm)
357 {
358 FOR_EACH_SYM(ENCRYPT_CASE)
359 default:
360 return TPM_RC_SYMMETRIC;
361 }
362 }
363 // Now do the mode-dependent decryption
364 switch(mode)
365 {
366 #if ALG_CBC
367 case TPM_ALG_CBC:
368 // Copy the input data to a temp buffer, decrypt the buffer into the
369 // output, XOR in the IV, and copy the temp buffer to the IV and repeat.
370 for(; dSize > 0; dSize -= blockSize)
371 {
372 pT = tmp;
373 for(i = blockSize; i > 0; i--)
374 *pT++ = *dIn++;
375 DECRYPT(&keySchedule, tmp, dOut);
376 pIv = iv;
377 pT = tmp;
378 for(i = blockSize; i > 0; i--)
379 {
380 *dOut++ ^= *pIv;
381 *pIv++ = *pT++;
382 }
383 }
384 break;
385 #endif
386 case TPM_ALG_CFB:
387 for(; dSize > 0; dSize -= blockSize)
388 {
389 // Encrypt the IV into the temp buffer
390 ENCRYPT(&keySchedule, iv, tmp);
391 pT = tmp;
392 pIv = iv;
393 for(i = (dSize < blockSize) ? dSize : blockSize; i > 0; i--)
394 // Copy the current cipher text to IV, XOR
395 // with the temp buffer and put into the output
396 *dOut++ = *pT++ ^ (*pIv++ = *dIn++);
397 }
398 // If the inner loop (i loop) was smaller than blockSize, then dSize
399 // would have been smaller than blockSize and it is now negative
400 // If it is negative, then it indicates how may fill bytes
401 // are needed to pad out the IV for the next round.
402 for(; dSize < 0; dSize++)
403 *pIv++ = 0;
404
405 break;
406 #if ALG_CTR
407 case TPM_ALG_CTR:
408 for(; dSize > 0; dSize -= blockSize)
409 {
410 // Encrypt the current value of the IV(counter)
411 ENCRYPT(&keySchedule, iv, tmp);
412
413 //increment the counter (counter is big-endian so start at end)
414 for(i = blockSize - 1; i >= 0; i--)
415 if((iv[i] += 1) != 0)
416 break;
417 // XOR the encrypted counter value with input and put into output
418 pT = tmp;
419 for(i = (dSize < blockSize) ? dSize : blockSize; i > 0; i--)
420 *dOut++ = *dIn++ ^ *pT++;
421 }
422 break;
423 #endif
424 #if ALG_ECB
425 case TPM_ALG_ECB:
426 for(; dSize > 0; dSize -= blockSize)
427 {
428 DECRYPT(&keySchedule, dIn, dOut);
429 dIn = &dIn[blockSize];
430 dOut = &dOut[blockSize];
431 }
432 break;
433 #endif
434 #if ALG_OFB
435 case TPM_ALG_OFB:
436 // This is written so that dIn and dOut may be the same
437 for(; dSize > 0; dSize -= blockSize)
438 {
439 // Encrypt the current value of the "IV"
440 ENCRYPT(&keySchedule, iv, iv);
441
442 // XOR the encrypted IV into dIn to create the cipher text (dOut)
443 pIv = iv;
444 for(i = (dSize < blockSize) ? dSize : blockSize; i > 0; i--)
445 *dOut++ = (*pIv++ ^ *dIn++);
446 }
447 break;
448 #endif
449 default:
450 return TPM_RC_FAILURE;
451 }
452 return TPM_RC_SUCCESS;
453 }
454
455 //*** CryptSymKeyValidate()
456 // Validate that a provided symmetric key meets the requirements of the TPM
457 // Return Type: TPM_RC
458 // TPM_RC_KEY_SIZE Key size specifiers do not match
459 // TPM_RC_KEY Key is not allowed
460 TPM_RC
CryptSymKeyValidate(TPMT_SYM_DEF_OBJECT * symDef,TPM2B_SYM_KEY * key)461 CryptSymKeyValidate(
462 TPMT_SYM_DEF_OBJECT *symDef,
463 TPM2B_SYM_KEY *key
464 )
465 {
466 if(key->t.size != BITS_TO_BYTES(symDef->keyBits.sym))
467 return TPM_RCS_KEY_SIZE;
468 #if ALG_TDES
469 if(symDef->algorithm == TPM_ALG_TDES && !CryptDesValidateKey(key))
470 return TPM_RCS_KEY;
471 #endif // ALG_TDES
472 return TPM_RC_SUCCESS;
473 }
474
475
476