// 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;
}