1 // This file was extracted from the TCG Published 2 // Trusted Platform Module Library 3 // Part 3: Commands 4 // Family "2.0" 5 // Level 00 Revision 01.16 6 // October 30, 2014 7 8 #include "InternalRoutines.h" 9 #include "EncryptDecrypt_fp.h" 10 // 11 // 12 // Error Returns Meaning 13 // 14 // TPM_RC_KEY is not a symmetric decryption key with both public and private 15 // portions loaded 16 // TPM_RC_SIZE IvIn size is incompatible with the block cipher mode; or inData size is 17 // not an even multiple of the block size for CBC or ECB mode 18 // TPM_RC_VALUE keyHandle is restricted and the argument mode does not match the 19 // key's mode 20 // 21 TPM_RC 22 TPM2_EncryptDecrypt( 23 EncryptDecrypt_In *in, // IN: input parameter list 24 EncryptDecrypt_Out *out // OUT: output parameter list 25 ) 26 { 27 OBJECT *symKey; 28 UINT16 keySize; 29 UINT16 blockSize; 30 BYTE *key; 31 TPM_ALG_ID alg; 32 33 // Input Validation 34 symKey = ObjectGet(in->keyHandle); 35 36 // The input key should be a symmetric decrypt key. 37 if( symKey->publicArea.type != TPM_ALG_SYMCIPHER 38 || symKey->attributes.publicOnly == SET) 39 return TPM_RC_KEY + RC_EncryptDecrypt_keyHandle; 40 41 // If the input mode is TPM_ALG_NULL, use the key's mode 42 if( in->mode == TPM_ALG_NULL) 43 in->mode = symKey->publicArea.parameters.symDetail.sym.mode.sym; 44 45 // If the key is restricted, the input symmetric mode should match the key's 46 // symmetric mode 47 if( symKey->publicArea.objectAttributes.restricted == SET 48 && symKey->publicArea.parameters.symDetail.sym.mode.sym != in->mode) 49 return TPM_RC_VALUE + RC_EncryptDecrypt_mode; 50 51 // If the mode is null, then we have a problem. 52 // Note: Construction of a TPMT_SYM_DEF does not allow the 'mode' to be 53 // TPM_ALG_NULL so setting in->mode to the mode of the key should have 54 // produced a valid mode. However, this is suspenders. 55 if(in->mode == TPM_ALG_NULL) 56 return TPM_RC_VALUE + RC_EncryptDecrypt_mode; 57 58 // The input iv for ECB mode should be null. All the other modes should 59 // have an iv size same as encryption block size 60 61 keySize = symKey->publicArea.parameters.symDetail.sym.keyBits.sym; 62 alg = symKey->publicArea.parameters.symDetail.sym.algorithm; 63 blockSize = CryptGetSymmetricBlockSize(alg, keySize); 64 if( (in->mode == TPM_ALG_ECB && in->ivIn.t.size != 0) 65 || (in->mode != TPM_ALG_ECB && in->ivIn.t.size != blockSize)) 66 return TPM_RC_SIZE + RC_EncryptDecrypt_ivIn; 67 68 // The input data size of CBC mode or ECB mode must be an even multiple of 69 // the symmetric algorithm's block size 70 if( (in->mode == TPM_ALG_CBC || in->mode == TPM_ALG_ECB) 71 && (in->inData.t.size % blockSize) != 0) 72 return TPM_RC_SIZE + RC_EncryptDecrypt_inData; 73 74 // Copy IV 75 // Note: This is copied here so that the calls to the encrypt/decrypt functions 76 // will modify the output buffer, not the input buffer 77 out->ivOut = in->ivIn; 78 79 // Command Output 80 81 key = symKey->sensitive.sensitive.sym.t.buffer; 82 // For symmetric encryption, the cipher data size is the same as plain data 83 // size. 84 out->outData.t.size = in->inData.t.size; 85 if(in->decrypt == YES) 86 { 87 // Decrypt data to output 88 CryptSymmetricDecrypt(out->outData.t.buffer, 89 alg, 90 keySize, in->mode, key, 91 &(out->ivOut), 92 in->inData.t.size, 93 in->inData.t.buffer); 94 } 95 else 96 { 97 // Encrypt data to output 98 CryptSymmetricEncrypt(out->outData.t.buffer, 99 alg, 100 keySize, 101 in->mode, key, 102 &(out->ivOut), 103 in->inData.t.size, 104 in->inData.t.buffer); 105 } 106 107 return TPM_RC_SUCCESS; 108 } 109