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