tyler

2026-04-059 minsecuritytlscryptography

How to Read a TLS 1.3 Cipher Suite

A TLS 1.3 cipher suite names just two things: an AEAD cipher and a hash. How to read one, and where the key exchange and signature moved to.

A TLS 1.3 cipher suite has two parts: an AEAD cipher (one algorithm that both encrypts and authenticates) and a hash. That’s the whole thing. TLS_AES_256_GCM_SHA384 says the connection encrypts its records with AES-256 in GCM mode and runs its key schedule on SHA-384. It tells you nothing about how the two sides agreed on a key, and nothing about how the server proved its identity. Those decisions moved out of the suite in TLS 1.3, which is exactly the part that trips people up when they’re used to reading TLS 1.2 names.

So if you’ve ever stared at TLS_AES_256_GCM_SHA384 next to TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 and wondered why one is half the length of the other, this is the post.

Decoding TLS_AES_256_GCM_SHA384

Two components, not four: AES, 256, and GCM together name the AEAD cipher, and SHA-384 is the key-schedule hash.

In table form:

TokenWhat it isWhat it does in the connection
AESBlock cipher (FIPS 197)The primitive that actually encrypts bytes
256Key length, in bitsSize of the symmetric key
GCMAEAD mode (NIST SP 800-38D)Turns AES into authenticated encryption: confidentiality plus integrity in one pass
SHA384Hash, SHA-2 family (FIPS 180-4)The hash used by the key schedule and the handshake transcript, not a record MAC

AES and the 256

AES is the block cipher, standardized in FIPS 197. On its own it just maps one 16-byte block to another under a key; it isn’t a complete encryption scheme until you wrap it in a mode. The 256 is the key length in bits.

Here’s the honest version of the 128-vs-256 question. Against classical brute force, AES-128 is already not the weak link in your system; 2^128 work is out of reach. The larger key mostly buys margin against future attacks, including quantum, where Grover’s algorithm roughly halves the effective key length (256 bits down to a still-comfortable ~128, versus 128 down to a more nervous ~64). If a compliance regime mandates 256-bit keys, you use AES-256. If not, AES-128-GCM is a defensible default and usually a touch faster.

GCM

GCM is where AES becomes useful. Galois/Counter Mode, specified in NIST SP 800-38D, runs AES in counter mode for confidentiality and computes an authentication tag over the ciphertext and any associated data. That makes it an AEAD: authenticated encryption with associated data (the general construction is defined in RFC 5116). One operation gives you both “nobody can read this” and “nobody tampered with this,” and the receiver rejects the record if the tag doesn’t verify. TLS uses a 128-bit tag. As of the 2024 review of SP 800-38D, NIST also explicitly states that the way TLS 1.3 builds GCM nonces is approved, which is a nice thing to be able to point at.

GCM’s one sharp edge is nonce reuse: repeat an IV under the same key and the security guarantees fall apart badly. TLS 1.3 handles nonce construction for you in the key schedule, so this is the library’s problem, not yours, but it’s worth knowing why the IV handling is so carefully specified.

SHA-384, and the thing people get wrong

In a TLS 1.2 suite, the trailing SHA256 or SHA384 did double duty, including feeding the HMAC that authenticated each record. People carry that mental model into TLS 1.3 and assume the hash in TLS_AES_256_GCM_SHA384 is still the record MAC.

It isn’t. The AEAD already authenticates every record, that’s the “A” in AEAD, so there’s no separate per-record HMAC to compute.

In TLS 1.3 the hash has two other jobs. The first is key derivation: it’s the hash inside HKDF (RFC 5869), the function TLS 1.3 uses to turn the key-exchange output into the actual traffic keys and IVs, via the HKDF-Expand-Label construction in RFC 8446 section 7.1.

The second is the handshake transcript: the Finished message hashes the full transcript to prove both sides saw the same messages. SHA-384 here is the truncated variant of SHA-512 from FIPS 180-4.

The pairing of SHA-384 with AES-256, rather than SHA-256, isn’t arbitrary. The suite matches hash strength to cipher strength so the hash isn’t the floor on security: SHA-384 gives 192-bit collision resistance against AES-256’s larger key, where the AES-128 suite is content with SHA-256. The same logic runs through every defined suite.

If you’ve seen vendor blogs describe the trailing hash in a 1.3 suite as the “message authentication” algorithm, that’s the 1.2 model leaking through. The OWASP cipher-string guidance that a lot of people still link to is itself deprecated now and redirects to the broader Transport Layer Security Cheat Sheet; the old “pick a cipher string” exercise mostly stopped being necessary once 1.3 shrank the suite.

Why the names got shorter

A TLS 1.2 suite packs four separate choices into one identifier. Read TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 left to right and you get: ECDHE for key exchange, RSA for authentication, AES-128-GCM for bulk encryption, and SHA-256 as the hash feeding the PRF and the record MAC. Four decisions, one string. Every new combination of those four needed its own code point in IANA’s registry, and the list grew into hundreds of entries, most of them combinations nobody should pick.

TLS 1.3 cut that apart. RFC 8446 changed the cipher suite concept to separate the authentication and key-exchange mechanisms from the record-protection algorithm and the hash. What’s left in the suite is only the two things that have to be agreed on together: the AEAD that protects records, and the hash used in key derivation. Key exchange and authentication negotiate on their own, in extensions. The result is five defined suites instead of a sprawling table.

TLS 1.2 packed four choices into the suite. TLS 1.3 keeps two and moves key exchange and authentication into separate extensions.

Those five, with their IANA code points:

SuiteCode point
TLS_AES_128_GCM_SHA2560x1301
TLS_AES_256_GCM_SHA3840x1302
TLS_CHACHA20_POLY1305_SHA2560x1303
TLS_AES_128_CCM_SHA2560x1304
TLS_AES_128_CCM_8_SHA2560x1305

RFC 8446 section 9.1 says a compliant implementation MUST support TLS_AES_128_GCM_SHA256 and SHOULD support TLS_AES_256_GCM_SHA384 and TLS_CHACHA20_POLY1305_SHA256. The two CCM suites target constrained and embedded devices; the _8 in the last one means a truncated 8-byte authentication tag, which saves bytes on the wire at the cost of integrity margin. In practice, on the public web you’ll almost always see the first three.1

Where the key exchange and the signature went

This is the half of the old suite that 1.3 moved out. Two places to know about.

In TLS 1.3 each cryptographic choice is negotiated in its own ClientHello field, and the ServerHello selects one of each.

Key exchange lives in supported_groups plus key_share. The client advertises which groups it’ll do Diffie-Hellman over in the supported_groups extension (RFC 8446 section 4.2.7, the renamed descendant of the old elliptic_curves extension) and sends actual key material for its preferred ones in key_share. Groups include the elliptic curves x25519 (RFC 7748), secp256r1 (NIST P-256, called prime256v1 in OpenSSL), and secp384r1, plus the finite-field groups ffdhe2048 through ffdhe8192 (RFC 7919). TLS 1.3 key exchange is always ephemeral, so forward secrecy is built in rather than optional. (The exception is PSK resumption, which is its own topic.)

Authentication lives in signature_algorithms. The server proves it holds the private key for its certificate by signing part of the handshake, and the acceptable signature schemes are negotiated in the signature_algorithms extension (RFC 8446 section 4.2.3): schemes like ecdsa_secp256r1_sha256, rsa_pss_rsae_sha256, and ed25519 (EdDSA, RFC 8032). The certificate’s key type, RSA versus ECDSA versus Ed25519, the thing you might think of as the “keypair algorithm,” is decided here, not in the cipher suite. So two connections can share TLS_AES_256_GCM_SHA384 and still authenticate with completely different certificate types.

The cleanest confirmation of the split comes from OpenSSL itself. Ask it to describe the suite and the key-exchange and auth columns just say any:

secdev@testbench:~$ openssl ciphers -v
TLS_AES_256_GCM_SHA384   TLSv1.3 Kx=any   Au=any   Enc=AESGCM(256)   Mac=AEAD

Kx=any and Au=any because the suite doesn’t pin them. Mac=AEAD because the AEAD is the integrity mechanism, with no separate MAC.

One configuration consequence

If you’ve ever edited a cipher list, restarted the server, and watched your 1.3 suites refuse to change, here’s why. The suite no longer carries key exchange or authentication, so you can’t tune those by editing a cipher string, and the suites themselves are configured through a different path than the legacy ones. In OpenSSL-based stacks the TLS 1.3 suites are set separately (the SSL_CTX_set_ciphersuites() API and the -ciphersuites option) from the older cipher_list that still governs TLS 1.2 and earlier.

The takeaway

The class of lesson here isn’t really about TLS. Any protocol that crams every cryptographic decision into a single identifier ends up with a combinatorial blowup of options and makes each choice hard to reason about on its own. TLS 1.3’s move was to split the decisions so each one negotiates independently. When you read a 1.3 suite, read it for what it now covers, record encryption and the key-schedule hash, and look to supported_groups and signature_algorithms for everything the old name used to include.

Further reading

Footnotes

  1. The five aren’t frozen forever. The IANA registry has since added TLS_AEGIS_256_SHA512 at 0x1306 and TLS_AEGIS_128L_SHA256 at 0x1307, both currently marked not Recommended. Check the registry rather than trusting any blog post, this one included, for the current list.

← OlderLINDDUN: A Worked Privacy Threat Model and Its Limits