// This file was extracted from the TCG Published // Trusted Platform Module Library // Part 3: Commands // Family "2.0" // Level 00 Revision 01.16 // October 30, 2014 #include "InternalRoutines.h" #include "EncryptDecrypt_fp.h" // // // Error Returns Meaning // // 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 ) { OBJECT *symKey; UINT16 keySize; UINT16 blockSize; BYTE *key; TPM_ALG_ID alg; // Input Validation symKey = ObjectGet(in->keyHandle); // The input key should be a symmetric decrypt key. if( symKey->publicArea.type != TPM_ALG_SYMCIPHER || symKey->attributes.publicOnly == SET) return TPM_RC_KEY + RC_EncryptDecrypt_keyHandle; // If the input mode is TPM_ALG_NULL, use the key's mode if( in->mode == TPM_ALG_NULL) in->mode = symKey->publicArea.parameters.symDetail.sym.mode.sym; // If the key is restricted, the input symmetric mode should match the key's // symmetric mode if( symKey->publicArea.objectAttributes.restricted == SET && symKey->publicArea.parameters.symDetail.sym.mode.sym != in->mode) return TPM_RC_VALUE + RC_EncryptDecrypt_mode; // If the mode is null, then we have a problem. // Note: Construction of a TPMT_SYM_DEF does not allow the 'mode' to be // TPM_ALG_NULL so setting in->mode to the mode of the key should have // produced a valid mode. However, this is suspenders. if(in->mode == TPM_ALG_NULL) return TPM_RC_VALUE + RC_EncryptDecrypt_mode; // The input iv for ECB mode should be null. 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); if( (in->mode == TPM_ALG_ECB && in->ivIn.t.size != 0) || (in->mode != TPM_ALG_ECB && in->ivIn.t.size != blockSize)) return TPM_RC_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( (in->mode == TPM_ALG_CBC || in->mode == TPM_ALG_ECB) && (in->inData.t.size % blockSize) != 0) return TPM_RC_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 CryptSymmetricDecrypt(out->outData.t.buffer, alg, keySize, in->mode, key, &(out->ivOut), in->inData.t.size, in->inData.t.buffer); } else { // Encrypt data to output CryptSymmetricEncrypt(out->outData.t.buffer, alg, keySize, in->mode, key, &(out->ivOut), in->inData.t.size, in->inData.t.buffer); } return TPM_RC_SUCCESS; }