| // 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.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.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.keyBits.sym; |
| alg = symKey->publicArea.parameters.symDetail.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; |
| } |