17.3 TLS record payload protection
As illustrated in Figure 17.1, before data is transmitted over the wire, the TLS record protection functions – denoted by E in Figure 17.1 – encrypt TLSPlaintext structures into TLSCiphertext structures.

Figure 17.1: Protection of TLS record payload
On the receiver side, TLS record layer functions are used to reverse the process by translating TLSCiphertext structures into TLSPlaintext structures. Every encrypted TLS record is composed of a plaintext header and an encrypted body. The body contains a type and optional padding.
In TLS 1.3, all ciphers used to encrypt TLSPlaintext into TLSCiphertext use the Authenticated Encryption with Associated Data (AEAD) mode of operation. Recall that AEAD offers encryption and message authentication in a single cryptographic algorithm that turns plaintext into an authenticated ciphertext. This, in turn, allows the receiving party to verify that the ciphertext was not manipulated while in transit and was indeed sent by the legitimate sender before decrypting the ciphertext.
The structure of the TLS 1.3 TLSCiphertext and TLSInnerPlaintext record is shown in Listing 17.2. The content field in TLSInnerPlaintext is the value of TLSPlaintext’s fragment field. That is, content holds the byte encoding of a TLS handshake message, a TLS alert message, or the application data (raw bytes) to be transmitted.
Listing 17.2: Structure of TLSCiphertext records
struct {
opaque content[TLSPlaintext.length];
ContentType type;
uint8 zeros[length_of_padding];
} TLSInnerPlaintext;
struct {
ContentType opaque_type = application_data; /* 23 */
ProtocolVersion legacy_record_version = 0x0303; /* TLS v1.2 */
uint16 length;
opaque encrypted_record[TLSCiphertext.length];
} TLSCiphertext;
The field type stores the content type of the record. This value is equal to the value of the type field in TLSPlaintext. The zeros field contains a sequence of 0s that allows to pad a TLS record.
The opaque˙type field of the TLSCiphertext structure is always set to application˙data. Its constant value of 23 is used to ensure compatibility with middleboxes supporting older TLS versions. The cleartext content of opaque˙type is in the field type of TLSInnerPlaintext.
Recall from Chapter 15, Authenticated Encryption, that an AEAD algorithm expands the ciphertext by adding an authentication tag T. The encrypted˙record field contains the AEAD-encrypted data from the serialized TLSInnerPlaintext structure.
The length field holds the size of the encrypted˙record field of TLSCiphertext in bytes. This value is computed as:

where len(⋅) is the size in bytes, and 1 is added for len(inner content type). The maximum length value is 214 + 256 bytes, and the legacy˙record˙version field is always set to the value 0x0303.
Recall that an AEAD algorithm takes as inputs a shared secret key, a nonce, a plaintext, and additional data to be authenticated but not encrypted. The shared secret key is either client˙write˙key or server˙write˙key. The nonce used by the AEAD algorithm is derived from the sequence number and client˙write˙iv or server˙write˙iv. The additional data is the record header; that means it consists of the following data:
additional_data = TLSCiphertext.opaque_type || TLSCiphertext.legacy_record_version || TLSCiphertext.length
The encoded TLSInnerPlaintext data structure is the plaintext input of the AEAD algorithm, and the shared secret key used is one of the traffic keys. The output of the AEAD algorithm is computed as follows:
AEADEncrypted = AEAD-Encrypt(write_key, nonce, additional_data, plaintext)
Once the AEAD encryption is computed, the encrypted˙record field of TLSCiphertext is set to the AEADEncrypted value. To invert the computation – that is, decrypt the ciphertext and verify its integrity and authenticity – the receiver computes the following:
plaintext of encrypted_record = AEAD-Decrypt(peer_write_key, nonce, additional_data, AEADEncrypted)
The AEAD decryption and verification routine outputs the plaintext if verification of the message’s authenticity and integrity is successful. Otherwise, it outputs an error indicating that something went wrong and, as a result, the receiving party terminates the TLS connection and transmits the bad˙record˙mac alert.
In TLS 1.3, the maximum expansion the AEAD algorithm may output is 255 bytes. If Alice or Bob receive a TLS record with the length field of TLSCiphertext having a larger value than 214 + 256 bytes, they terminate the TLS connection and transmit the record˙overflow alert. This limit is determined by the maximum size of TLSInnerPlaintext (214 bytes) plus the size of ContentType (1 byte) plus the maximum size of the AEAD expansion (255 bytes).