• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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