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