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