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 #include "Tpm.h"
36 #include "EncryptDecrypt_fp.h"
37 #if CC_EncryptDecrypt2
38 #include  "EncryptDecrypt_spt_fp.h"
39 #endif
40 
41 #if CC_EncryptDecrypt  // Conditional expansion of this file
42 
43 /*(See part 3 specification)
44 // symmetric encryption or decryption
45 */
46 //  Return Type: TPM_RC
47 //      TPM_RC_KEY          is not a symmetric decryption key with both
48 //                          public and private portions loaded
49 //      TPM_RC_SIZE         'IvIn' size is incompatible with the block cipher mode;
50 //                          or 'inData' size is not an even multiple of the block
51 //                          size for CBC or ECB mode
52 //      TPM_RC_VALUE        'keyHandle' is restricted and the argument 'mode' does
53 //                          not match the key's mode
54 TPM_RC
TPM2_EncryptDecrypt(EncryptDecrypt_In * in,EncryptDecrypt_Out * out)55 TPM2_EncryptDecrypt(
56     EncryptDecrypt_In   *in,            // IN: input parameter list
57     EncryptDecrypt_Out  *out            // OUT: output parameter list
58     )
59 {
60 #if CC_EncryptDecrypt2
61     return EncryptDecryptShared(in->keyHandle, in->decrypt, in->mode,
62                                 &in->ivIn, &in->inData, out);
63 #else
64     OBJECT              *symKey;
65     UINT16               keySize;
66     UINT16               blockSize;
67     BYTE                *key;
68     TPM_ALG_ID           alg;
69     TPM_ALG_ID           mode;
70     TPM_RC               result;
71     BOOL                 OK;
72     TPMA_OBJECT          attributes;
73 
74 // Input Validation
75     symKey = HandleToObject(in->keyHandle);
76     mode = symKey->publicArea.parameters.symDetail.sym.mode.sym;
77     attributes = symKey->publicArea.objectAttributes;
78 
79     // The input key should be a symmetric key
80     if(symKey->publicArea.type != TPM_ALG_SYMCIPHER)
81         return TPM_RCS_KEY + RC_EncryptDecrypt_keyHandle;
82     // The key must be unrestricted and allow the selected operation
83     OK = IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted)
84     if(YES == in->decrypt)
85         OK = OK && IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt);
86     else
87         OK = OK && IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign);
88     if(!OK)
89         return TPM_RCS_ATTRIBUTES + RC_EncryptDecrypt_keyHandle;
90 
91     // If the key mode is not TPM_ALG_NULL...
92     // or TPM_ALG_NULL
93     if(mode != TPM_ALG_NULL)
94     {
95         // then the input mode has to be TPM_ALG_NULL or the same as the key
96         if((in->mode != TPM_ALG_NULL) && (in->mode != mode))
97             return TPM_RCS_MODE + RC_EncryptDecrypt_mode;
98     }
99     else
100     {
101         // if the key mode is null, then the input can't be null
102         if(in->mode == TPM_ALG_NULL)
103             return TPM_RCS_MODE + RC_EncryptDecrypt_mode;
104         mode = in->mode;
105     }
106     // The input iv for ECB mode should be an Empty Buffer.  All the other modes
107     // should have an iv size same as encryption block size
108     keySize = symKey->publicArea.parameters.symDetail.sym.keyBits.sym;
109     alg = symKey->publicArea.parameters.symDetail.sym.algorithm;
110     blockSize = CryptGetSymmetricBlockSize(alg, keySize);
111 
112     // reverify the algorithm. This is mainly to keep static analysis tools happy
113     if(blockSize == 0)
114         return TPM_RCS_KEY + RC_EncryptDecrypt_keyHandle;
115 
116     // Note: When an algorithm is not supported by a TPM, the TPM_ALG_xxx for that
117     // algorithm is not defined. However, it is assumed that the TPM_ALG_xxx for
118     // the algorithm is always defined. Both have the same numeric value.
119     // TPM_ALG_xxx is used here so that the code does not get cluttered with
120     // #ifdef's. Having this check does not mean that the algorithm is supported.
121     // If it was not supported the unmarshaling code would have rejected it before
122     // this function were called. This means that, depending on the implementation,
123     // the check could be redundant but it doesn't hurt.
124     if(((mode == TPM_ALG_ECB) && (in->ivIn.t.size != 0))
125        || ((mode != TPM_ALG_ECB) && (in->ivIn.t.size != blockSize)))
126         return TPM_RCS_SIZE + RC_EncryptDecrypt_ivIn;
127 
128     // The input data size of CBC mode or ECB mode must be an even multiple of
129     // the symmetric algorithm's block size
130     if(((mode == TPM_ALG_CBC) || (mode == TPM_ALG_ECB))
131        && ((in->inData.t.size % blockSize) != 0))
132         return TPM_RCS_SIZE + RC_EncryptDecrypt_inData;
133 
134     // Copy IV
135     // Note: This is copied here so that the calls to the encrypt/decrypt functions
136     // will modify the output buffer, not the input buffer
137     out->ivOut = in->ivIn;
138 
139 // Command Output
140     key = symKey->sensitive.sensitive.sym.t.buffer;
141     // For symmetric encryption, the cipher data size is the same as plain data
142     // size.
143     out->outData.t.size = in->inData.t.size;
144     if(in->decrypt == YES)
145     {
146         // Decrypt data to output
147         result = CryptSymmetricDecrypt(out->outData.t.buffer, alg, keySize, key,
148                                        &(out->ivOut), mode, in->inData.t.size,
149                                        in->inData.t.buffer);
150     }
151     else
152     {
153         // Encrypt data to output
154         result = CryptSymmetricEncrypt(out->outData.t.buffer, alg, keySize, key,
155                                        &(out->ivOut), mode, in->inData.t.size,
156                                        in->inData.t.buffer);
157     }
158     return result;
159 #endif // CC_EncryptDecrypt2
160 
161 }
162 
163 #endif // CC_EncryptDecrypt