What the NEA2 Keys Unlock: Deciphering a 5G NR Radio Capture

The companion to the air-interface walkthrough. That article read the control plane of a real 5G NR capture layer by layer; this one takes the decryption lens. The trace is NEA2-ciphered — opaque below PDCP until you supply the UE keys — and the keys happen to be published in the Wireshark issue that the capture came from. Feed them to VisualEther and the radio stack opens all the way down to the IMS session riding on top.

💡 Read the walkthrough and the diagram side by side. Open the interactive diagram (or PDF) in a split-screen window so the captions stay in view as you read. In Edge, Chrome, or Firefox, right-click the link and pick your browser's split-screen option (Edge labels it "Open link in split screen window"). On macOS, prefer Chrome or Firefox — Safari has no in-browser split screen. Otherwise, open the diagram in a new tab and snap the two windows side by side.

Three levels of encryption, one trace

The single most useful idea for reading a 5G capture is that the same packet can pass through several independent encryption levels, each with its own keys and its own scope. This trace stacks three:

LevelBetweenTurned on byProtectsKeys in this trace?
NAS (core)UE ↔ AMFNAS Security Mode Command (5GMM)NAS message bodiesNo — sealed
AS (radio)UE ↔ gNBRRC Security Mode CommandPDCP: RRC + the user planeYes — the published keys
IMS (application)UE ↔ P-CSCFIMS-AKA, during REGISTER / 401 (TS 33.203)SIP signaling, via IPsec ESPNo — derived from IMS-AKA

The first two are 3GPP security contexts — the NAS context negotiated with the core and the Access-Stratum context negotiated with the radio. The third is IMS access security: IPsec ESP set up between the UE and the P-CSCF during registration. Three levels, three key sets — and the Wireshark issue publishes exactly one of them, the AS/PDCP keys. That single fact decides what this article can and cannot show:

So the reveal is bounded on both sides. Deciphering the radio layer exposes what sits between the two levels we cannot open. That is not more NAS signaling — it is the user plane: the actual IP packets the UE was sending, in the clear, for exactly the window before IMS security closes over them.

The three levels in detail

Each level has its own key hierarchy and its own algorithms. Here is what protects what, and where the keys come from — including exactly where the two keys the Wireshark issue hands us sit.

1. NAS security — the core-network conversation

NAS (Non-Access Stratum) security protects the signaling between the UE and the AMF in the core: registration, authentication, and session management. It is switched on by the NAS Security Mode Command (frames 11–16 of the air-interface walkthrough), and its keys descend from the 5G authentication run:

flowchart TD accTitle: NAS security key derivation accDescr: The long-term key K and the 5G-AKA run yield CK and IK, which derive K_AUSF, then K_SEAF, then the anchor key K_AMF at the AMF. K_AMF plus the selected NAS algorithm identities derive the NAS ciphering key K_NASenc and the NAS integrity key K_NASint, used by NEA2 and NIA2 respectively. K["K — long-term key (USIM / UDM)"] --> AKA["5G-AKA → CK, IK"] AKA --> KAUSF["K_AUSF"] --> KSEAF["K_SEAF"] --> KAMF["K_AMF — anchor, held by the AMF"] KAMF -->|"KDF + NAS algo IDs"| NENC["K_NASenc"] KAMF -->|"KDF + NAS algo IDs"| NINT["K_NASint"] NENC --> EA["NEA2 = AES-CTR — ciphers the NAS payload"] NINT --> IA["NIA2 = AES-CMAC — NAS integrity (MAC)"]
NAS key hierarchy (TS 33.501): the AKA run and the K_AMF anchor derive the NAS ciphering and integrity keys.

Ciphering is NEA2 (128-bit AES in counter mode); integrity is NIA2 (128-bit AES-CMAC). K_NASenc is not in the trace, so the ciphered NAS bodies stay ciphertext — six of the twelve messages on the NAS timeline the companion walks, including whatever Registration Accept the network sent. Not every NAS message goes dark, though, and which ones stay legible is not arbitrary: the NAS-5GS companion walks the readable half and shows where the line falls.

Access-Stratum (AS) security protects PDCP over the air between the UE and the gNB, and PDCP carries both the RRC signaling and the user plane. It is switched on by the RRC Security Mode Command (frame 17 of the same walkthrough), and its keys descend from K_gNB, which the AMF derives from K_AMF and hands to the gNB. (What that command actually contains on the wire — and why it contains no key at all — is walked in the NR-RRC companion.)

flowchart TD accTitle: Access-Stratum security key derivation accDescr: K_AMF plus the uplink NAS COUNT derive K_gNB, which is sent to the gNB. K_gNB plus the AS algorithm identities derive four keys: the RRC ciphering key K_RRCenc and RRC integrity key K_RRCint, and the user-plane ciphering key K_UPenc and integrity key K_UPint. The two ciphering keys are the ones published in the Wireshark issue. KAMF["K_AMF"] -->|"KDF + uplink NAS COUNT"| KGNB["K_gNB — sent to the gNB"] KGNB -->|"KDF + AS algo IDs"| RRCE["K_RRCenc = 95F2…FDDD (published)"] KGNB --> RRCI["K_RRCint"] KGNB --> UPE["K_UPenc = 4CB1…BC5B (published)"] KGNB --> UPI["K_UPint"] RRCE --> C1["NEA2 ciphers PDCP on the SRBs (RRC)"] UPE --> C2["NEA2 ciphers PDCP on the DRB (user plane)"] RRCI --> I1["NIA2 → PDCP MAC-I"]
AS key hierarchy: K_gNB fans out into four keys; the issue publishes the two ciphering keys, which is why PDCP deciphers.

K_gNB produces four keys, but only the two ciphering keys are needed to read the traffic — and those are exactly what the issue publishes: K_RRCenc = 95F2…FDDD and K_UPenc = 4CB1…BC5B. The integrity keys (K_RRCint / K_UPint) would only let you verify each PDU's MAC-I, not decrypt it, so their absence costs us nothing. This is the one level of the three we can open — and opening it is what turns the rest of this capture from ciphertext into the flow below.

3. IMS access security — the SIP session

The third level is not a 3GPP access-security context at all; it belongs to the IMS application. During registration, IMS-AKA (TS 33.203) sets up IPsec ESP security associations between the UE and the P-CSCF, and all SIP after the challenge rides inside them:

flowchart TD accTitle: IMS access security key setup accDescr: The ISIM or USIM and the IMS long-term key drive an IMS-AKA run whose challenge is carried in the 401 and whose response returns in the next REGISTER. It yields IMS CK and IK, which key the IPsec ESP security associations between UE and P-CSCF, identified by the SPIs seen in the trace. CK provides ESP confidentiality, and IK provides ESP integrity. ISIM["ISIM / USIM + IMS key"] --> IAKA["IMS-AKA — challenge in the 401, response in the next REGISTER"] IAKA --> CKIK["IMS CK, IK"] CKIK --> SA["IPsec ESP SAs · UE ↔ P-CSCF (SPIs 0x100 / 0xfbeb / 0xfbec)"] SA --> ENC["ESP confidentiality — keyed by CK"] SA --> INT["ESP integrity — keyed by IK"]
IMS access security (TS 33.203): the IMS-AKA run derives the keys for a pair of IPsec ESP security associations between the UE and the P-CSCF.

The 401 (frame 62 below) is the IMS-AKA challenge; the UE's ISIM turns it into the CK / IK that key the ESP security associations whose SPIs (0x100, 0xfbeb, 0xfbec) surface a few frames later. Those keys never appear in the trace, so once SIP moves into ESP it is opaque again — the same situation as the NAS level, one level up.

The recipe

Everything below comes from handing Wireshark (via VisualEther) four things: the L2-over-UDP heuristics that unwrap the srsRAN-style framing, the instruction to decipher the user plane, the RLC→PDCP bearer mapping, and the UE key table. The keys are UEId 1, published in the issue:

--enable-heuristic mac_nr_udp --enable-heuristic rlc_nr_udp --enable-heuristic pdcp_nr_udp
-o pdcp-nr.decipher_userplane:TRUE
-o rlc-nr.call_pdcp_for_ul_drb:"18-bit SN"
-o rlc-nr.call_pdcp_for_dl_drb:"18-bit SN"
-o uat:pdcp_nr_ue_keys:"1","95F23667A60D91689B31772783E6FDDD","4CB12A7FB40AE866AE59FC9529E0BC5B","",""

The two 128-bit hex values are the RRC ciphering key and the user-plane ciphering key. The two rlc-nr.call_pdcp_for_*_drb lines matter almost as much: PDCP can only decipher a whole SDU, so RLC has to reassemble its segments and hand them up with the right sequence-number length before there is anything to decrypt at all. RLC-NR Acknowledged Mode follows that layer PDU by PDU on both bearers — the segmentation, the polls, and the status reports this recipe quietly depends on. One caveat worth stating plainly: do not also force nas-5gs.null_decipher on this capture. The NAS traffic is genuinely ciphered, and telling the dissector to treat it as null would make it fabricate 5GMM fields out of NAS ciphertext — worse than leaving it sealed.

Before and after

The keys change what a single frame is. Two examples from the air-interface walkthrough:

FrameWithout the keysWith the keys
38An opaque PDCP block on SRB1An RRC Reconfiguration building SRB2 + the SDAP DRB 1 (QFI 2)
41–114UL SDAP -> QFI 2 and little moreA full inner IPv6 conversation — TCP, SIP, IPsec ESP

The rest of this article walks that second row: the inner IPv6 user plane on DRB 1, the part the air-interface walkthrough could only see the SDAP wrapper of.

The reveal: an IMS registration underneath SDAP

Once PDCP is deciphered, the SDAP payload on DRB 1 turns out to be an ordinary IPv6 host talking to the IMS network. (First, invisibly on this diagram, the UE autoconfigures its address: an ICMPv6 Router Solicitation draws a Router Advertisement carrying the SLAAC prefix 3000:0:0:2::, from which the UE forms 3000:0:0:2::2.) The one-byte SDAP header those packets ride under has its own walkthrough — SDAP: QoS flows, the QFI, and the data radio bearer — and it stops exactly where this section starts. Then:

sequenceDiagram accTitle: The decrypted IMS user-plane exchange accDescr: Over the deciphered DRB, the UE opens a TCP connection to the P-CSCF on port 5060, sends a SIP REGISTER, receives a 401 IMS-AKA challenge, and then all further traffic moves inside IPsec ESP security associations in both directions. participant UE participant P as P-CSCF (IMS) UE->>P: TCP SYN -> port 5060 P->>UE: SYN, ACK UE->>P: ACK (connection up) UE->>P: SIP REGISTER (sip:test.3gpp.com) P->>UE: 401 Unauthorized (IMS-AKA challenge) Note over UE,P: IMS-AKA brings up IPsec ESP SAs UE->>P: ESP · SPI 0x00000100 P->>UE: ESP · SPI 0x0000fbeb / 0x0000fbec
The decrypted user-plane reveal on DRB 1: a TCP connection to the P-CSCF, the IMS-AKA REGISTER / 401 exchange, and the IPsec ESP that protects everything after.

TCP to the P-CSCF (frames 47–50). The UE opens a normal TCP three-way handshake from port 33939 to the IMS edge (the P-CSCF) on the SIP port 5060. Perfectly readable now — ciphertext a moment ago.

SIP REGISTER → 401 (frames 53, 62). The UE sends its first IMS REGISTER to sip:test.3gpp.com. The IMS core answers with a 401 Unauthorized carrying an authentication challenge (WWW-Authenticate, IMS-AKA per TS 33.203). This is the normal opening of IMS registration, not a failure: the UE derives keys from the challenge and will re-register under protection.

IPsec ESP takes over (frames 72 onward). Right after the 401, IMS-AKA establishes IPsec ESP security associations between the UE and the P-CSCF, and all further SIP moves inside ESP. This is the third level from the table coming up — IMS access security (TS 33.203) — and its keys are not in the trace. There is a nice irony here: having just deciphered the radio layer to read the SIP, we watch the application re-encrypt itself at the IP layer. Each ESP packet names the receiver's Security Association by its SPI, and the per-SA sequence climbs monotonically:

The inner SIP is now opaque again — we would need the IPsec SA keys, which are derived from the AKA run and not in the trace. And that is the honest end of the reveal: the radio decryption got us from ciphered PDCP down to the IMS registration, and IMS security then draws its own curtain.

For the fuller IMS-AKA and IPsec story — including the media (RTP) that follows a completed registration — see the companion VoNR reconstruction, which recovers a complete voice call from a different (F1-U) capture.

A note on PDCP security

On each bearer, PDCP maintains a COUNT (a hyper frame number plus the per-PDU sequence number); ciphering (NEA2) is AES in counter mode keyed by that COUNT, and integrity (NIA2) produces the 32-bit MAC-I tag you see on signaling PDUs. Ciphering and integrity are separate functions with separate keys — which is why a capture can be integrity-protected but unciphered, or, as here, both. That frame-by-frame walk now exists: PDCP-NR: sequence numbers, COUNT, and where ciphering happens traces the SN and COUNT on both bearers, shows the MAC-I turning from all zeros into a real digest at frame 17, and pins the exact frame where ciphering starts — including on the second connection, for which this trace holds no keys at all. This article stays at the level of "the keys open PDCP, and here is what was inside."

Takeaways

  1. A packet can sit inside several encryption levels. Here there are three — NAS (core), AS (radio), and IMS/IPsec (application) — and the published keys open only the AS one. Know which keys you hold, and you know exactly which level you can read.
  2. The reveal is the user plane. Below the SDAP QoS-flow wrapper sits a real IPv6 host — here mid-IMS-registration.
  3. IMS re-secures itself above the radio. A REGISTER401 IMS-AKA exchange, then IPsec ESP — the third level — so even a fully deciphered radio trace ends at an encrypted IMS payload.
  4. SPIs and sequence numbers read the IPsec SAs. Each ESP packet's SPI names the receiver's SA; monotonic sequences mean one clean SA with no replay or rekey.

Try it on your own capture

The decryption, the dissection, and every caption on the diagram came from VisualEther driving Wireshark from a raw PCAP — keys in, readable flow out. Point it at your own ciphered 5G capture and do the same.