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
TPM2_EncryptDecrypt(EncryptDecrypt_In * in,EncryptDecrypt_Out * out)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