There are some limitations on which parameters can be encrypted and decrypted and the number of encrypt and decrypt sessions per command.
Only the first command parameter can be encrypted and only the first response parameter can be decrypted, and in both cases, only if that first parameter is a TPM2B as defined in Chapter 5. Commands that don't have a TPM2B as the first command parameter cannot be sent to the TPM using sessions set for decrypt; likewise, if a response's first parameter isn't a TPM2B, the response can't be received using an encrypt session.
As you learned in Chapter 13, commands can be sent with up to three sessions.
But a maximum of one session per command can be set for decrypt and a maximum of one for encrypt. If a command allows the use of both decrypt and encrypt sessions, the same session can be used to set both attributes or separate sessions can be used, one for each attribute.
So how do you enable decrypt and encrypt sessions?
At first glance, configuring sessions as decrypt and/or encrypt sessions is very easy. For an open session, all you have to do is set either or both of the session attributes bits in the authorization area for the command: sessionAttributes.decrypt and/or sessionAttributes.encrypt.
Of course, things are rarely that simple, and it's certainly true here. For a decrypt session, the caller has to properly encrypt the first parameter. Likewise for an encrypt session, the caller has to properly decrypt the first response parameter after receiving it from the TPM; otherwise, it will be meaningless gibberish to the caller. Two modes of encryption are used for decrypt and encrypt sessions: XOR and CFB mode. These modes are set when the session is created. Both modes have the property that the plain text and ciphertext are the same length, so the byte stream lengths don't change. Session nonces figure into the encryption, which ensures that the encryption and decryption operations function as one-time pads.
For XOR mode, a mask (one-time pad) is generated and XORed with the data to be encrypted or decrypted. The mask is generated by passing the hashAlg (authHash parameter used when the session was started), the HMAC key, the string “XOR”, nonceNewer, nonceOlder, and the message size to the key derivation function (KDFa).
The output is a mask that is as long as the message to be decrypted or encrypted. A simple XOR of the mask with the data completes the encryption or decryption operation.
For CFB mode, the KDFa is used to generate the encryption key and initialization vector (IV). The inputs to the KDFa are hashAlg (the authHash parameter used when the session was started), sessionKey, the “CFB” string, nonceNewer, nonceOlder, and the number of bits (bits) needed for the symmetric key plus the IV. The output is a string of bits length, with the key in the upper octets and the IV in the lower octets. The IV size is determined by the block size of the encryption algorithm. The key and IV are used as inputs to the encryption algorithm to perform the required encryption or decryption operation.
For both XOR and CFB modes, nonceNewer and nonceOlder figure into the encryption. For XOR mode, because the nonces change, a different mask is generated for encryption of command parameters than the one used for response parameters. Likewise, for CFB mode, a different encryption key and IV are generated for commands and responses. In both XOR and CFB modes, because the nonces roll for every usage of the session, encrypt and decrypt sessions act as one-time pads.