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