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