/* Microsoft Reference Implementation for TPM 2.0 * * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and * contributor rights, including patent rights, and no such rights are granted * under this license. * * Copyright (c) Microsoft Corporation * * All rights reserved. * * BSD License * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "Tpm.h" #include "EncryptDecrypt_fp.h" #if CC_EncryptDecrypt2 #include "EncryptDecrypt_spt_fp.h" #endif #if CC_EncryptDecrypt // Conditional expansion of this file /*(See part 3 specification) // symmetric encryption or decryption */ // Return Type: TPM_RC // TPM_RC_KEY is not a symmetric decryption key with both // public and private portions loaded // TPM_RC_SIZE 'IvIn' size is incompatible with the block cipher mode; // or 'inData' size is not an even multiple of the block // size for CBC or ECB mode // TPM_RC_VALUE 'keyHandle' is restricted and the argument 'mode' does // not match the key's mode TPM_RC TPM2_EncryptDecrypt( EncryptDecrypt_In *in, // IN: input parameter list EncryptDecrypt_Out *out // OUT: output parameter list ) { #if CC_EncryptDecrypt2 return EncryptDecryptShared(in->keyHandle, in->decrypt, in->mode, &in->ivIn, &in->inData, out); #else OBJECT *symKey; UINT16 keySize; UINT16 blockSize; BYTE *key; TPM_ALG_ID alg; TPM_ALG_ID mode; TPM_RC result; BOOL OK; TPMA_OBJECT attributes; // Input Validation symKey = HandleToObject(in->keyHandle); mode = symKey->publicArea.parameters.symDetail.sym.mode.sym; attributes = symKey->publicArea.objectAttributes; // The input key should be a symmetric key if(symKey->publicArea.type != TPM_ALG_SYMCIPHER) return TPM_RCS_KEY + RC_EncryptDecrypt_keyHandle; // The key must be unrestricted and allow the selected operation OK = IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted) if(YES == in->decrypt) OK = OK && IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt); else OK = OK && IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign); if(!OK) return TPM_RCS_ATTRIBUTES + RC_EncryptDecrypt_keyHandle; // If the key mode is not TPM_ALG_NULL... // or TPM_ALG_NULL if(mode != TPM_ALG_NULL) { // then the input mode has to be TPM_ALG_NULL or the same as the key if((in->mode != TPM_ALG_NULL) && (in->mode != mode)) return TPM_RCS_MODE + RC_EncryptDecrypt_mode; } else { // if the key mode is null, then the input can't be null if(in->mode == TPM_ALG_NULL) return TPM_RCS_MODE + RC_EncryptDecrypt_mode; mode = in->mode; } // The input iv for ECB mode should be an Empty Buffer. All the other modes // should have an iv size same as encryption block size keySize = symKey->publicArea.parameters.symDetail.sym.keyBits.sym; alg = symKey->publicArea.parameters.symDetail.sym.algorithm; blockSize = CryptGetSymmetricBlockSize(alg, keySize); // reverify the algorithm. This is mainly to keep static analysis tools happy if(blockSize == 0) return TPM_RCS_KEY + RC_EncryptDecrypt_keyHandle; // Note: When an algorithm is not supported by a TPM, the TPM_ALG_xxx for that // algorithm is not defined. However, it is assumed that the TPM_ALG_xxx for // the algorithm is always defined. Both have the same numeric value. // TPM_ALG_xxx is used here so that the code does not get cluttered with // #ifdef's. Having this check does not mean that the algorithm is supported. // If it was not supported the unmarshaling code would have rejected it before // this function were called. This means that, depending on the implementation, // the check could be redundant but it doesn't hurt. if(((mode == TPM_ALG_ECB) && (in->ivIn.t.size != 0)) || ((mode != TPM_ALG_ECB) && (in->ivIn.t.size != blockSize))) return TPM_RCS_SIZE + RC_EncryptDecrypt_ivIn; // The input data size of CBC mode or ECB mode must be an even multiple of // the symmetric algorithm's block size if(((mode == TPM_ALG_CBC) || (mode == TPM_ALG_ECB)) && ((in->inData.t.size % blockSize) != 0)) return TPM_RCS_SIZE + RC_EncryptDecrypt_inData; // Copy IV // Note: This is copied here so that the calls to the encrypt/decrypt functions // will modify the output buffer, not the input buffer out->ivOut = in->ivIn; // Command Output key = symKey->sensitive.sensitive.sym.t.buffer; // For symmetric encryption, the cipher data size is the same as plain data // size. out->outData.t.size = in->inData.t.size; if(in->decrypt == YES) { // Decrypt data to output result = CryptSymmetricDecrypt(out->outData.t.buffer, alg, keySize, key, &(out->ivOut), mode, in->inData.t.size, in->inData.t.buffer); } else { // Encrypt data to output result = CryptSymmetricEncrypt(out->outData.t.buffer, alg, keySize, key, &(out->ivOut), mode, in->inData.t.size, in->inData.t.buffer); } return result; #endif // CC_EncryptDecrypt2 } #endif // CC_EncryptDecrypt