Your nRF Sniffer Captures Encrypted BLE Packets You Can't Read — Here's How to Decrypt Them

Decrypting encrypted BLE packets from an nRF sniffer using the LTK in Wireshark

Your capture looks perfect. The connection event is right there, the central and peripheral are talking, and then every packet after pairing turns into noise. You didn’t break anything. The encryption is working exactly as designed, and the sniffer recorded it faithfully.

The catch: to read your own device’s traffic again, you need the session key, and a lot of engineers don’t realize where it comes from or why their first decryption attempt quietly does nothing.

This is a debugging workflow for hardware you own and develop. We’re not covering key extraction from third-party devices, and you won’t need to. With LE Secure Connections, you don’t type a key at all. You capture the moment it’s negotiated.

Here’s the reliable way to do BLE packet decryption in Wireshark with the nRF Sniffer, and more usefully, how to figure out why it silently fails.

What you actually need to decrypt

Encryption on a BLE link kicks in after pairing. Once the Security Manager finishes its handshake, both sides derive a Long Term Key (LTK), and the link encrypts every subsequent packet with a session key built from it.

The nRF Sniffer can decrypt that traffic on one condition: it has to watch the key exchange happen live. When the handshake is inside your capture, the plugin derives the material it needs and hands it to Wireshark. You never paste an LTK in the common LE Secure Connections flow.

That’s the whole trick. Capture the handshake, and the rest decrypts. Miss it, and nothing you do afterward helps.

How that handshake works depends on the pairing method:

                  LE Secure Connections      Legacy Pairing
Key agreement     ECDH (P-256)               TK + STK exchange
Sniffer needs     Capture full pairing       Capture pairing OR
                  from connection start      provide LTK manually
Decrypt in WS     Yes, if handshake seen     Yes, key entry often req'd
This guide        PRIMARY FOCUS              Brief mention only

LE Secure Connections uses ECDH over the P-256 curve, so the actual secret never crosses the air. The sniffer still derives what it needs by observing the full exchange, which is why “start capturing before pairing” is the rule everything else hangs on.

One caveat worth knowing: passkey entry and OOB association models change some of the derivation inputs. For everyday Just Works debugging, the working rule holds: handshake captured means link decryptable. For the full picture of how the two sides agree on keys, see the Bluetooth pairing and bonding flow.

Versions, so you can sanity-check your setup: this is written against nRF Sniffer for Bluetooth LE 4.x and Wireshark 4.x. Menu strings below have been stable across recent releases.

Step 1: Capture the connection from the very start

Start the sniffer and lock onto your device before the central connects and pairs.

The pairing handshake happens once, early, in the first moments after the connection forms. There’s no second chance in the same session. If your sniffer joins after pairing, you’ve captured a fully encrypted link with no key material in sight, and the capture is undecryptable no matter what you configure later.

[Sniffer ON]──>[Device advertising]──>[CONNECT]──>[PAIRING]──>[encrypted data]
     |                                                 |
  must already        the ONE window you cannot miss ──┘
  be capturing

In the nRF Sniffer plugin, select your device from the device list while it’s advertising. That tells the sniffer which connection to follow when the central connects, so it tracks the channel hops instead of sitting on one advertising channel.

The practical move that saves most sessions: force a fresh pairing. If your central has already bonded with the peripheral, no new handshake will happen on the next connection. It’ll just reuse the stored LTK off-air. Clear the bond first.

On nRF Connect for Desktop or your phone’s nRF Connect app, use “forget device” or delete the bond, then reconnect. Now pairing re-runs, on-air, while you’re capturing. For a refresher on how connections walk across BLE advertising and data channels, that explains the hop-following behavior.

Step 2: Configure Wireshark to decrypt

Decryption lives in Wireshark, not the sniffer plugin. The plugin captures and passes encryption material; Wireshark applies it.

Go to Edit → Preferences → Protocols. The two you care about are NORDIC_BLE (the sniffer’s transport layer) and BTLE (the Bluetooth link layer).

When the handshake is in your capture, the nRF plugin feeds the derived key through automatically. For a clean LE Secure Connections capture, that’s all you need. There’s no LTK field to fill in.

For Legacy pairing or any case where you’re supplying a key by hand, the LTK field is under the BTLE protocol preferences. It expects raw hex, no spaces, no colons, no 0x prefix. Note this spot now, because it’s where two of the three common failures show up. We’ll get to the byte-order trap below.

After changing preferences, reload the capture so Wireshark re-dissects with the new settings.

Step 3: Verify decryption worked

Success looks like readable ATT and GATT traffic appearing after the encryption start point.

Scroll past the LL_ENC_REQ / LL_START_ENC_RSP exchange. If decryption took, the packets that follow show up as proper ATT operations: Read Request, Write Request, Handle Value Notification, with handles and values you recognize from your GATT table.

A quick filter confirms it. Type btatt into the display filter. If you get readable application-layer rows after the encrypted region, you’re done. If that region stays blank or shows only Encrypted Packet entries, decryption didn’t apply, and you head to troubleshooting.

Troubleshooting: the three reasons it’s still encrypted

This is where most of the frustration lives, and where the official docs tend to stop. Work the symptoms in order.

Still encrypted? Diagnose:
  No pairing frames in capture? ──> Missed the handshake (A)
  Pairing present, manual LTK?  ──> Check format/byte order (B)
  Decrypts then breaks/gaps?    ──> Channel/hop tracking (C)

A. You missed the pairing event

Symptom: the connection is clearly visible, but the post-encryption packets stay unreadable and you can’t find any pairing frames.

Diagnose it with a filter. Try btsmp for Security Manager packets, and look for LL_ENC_REQ and LL_START_ENC_RSP in the link layer. If none of those appear, the key exchange never entered your capture. The sniffer had nothing to derive from.

This is the most common cause by a wide margin, and it almost always means the devices were already bonded, so no on-air pairing happened.

Fix: clear the bond on the central, start the sniffer, select the device while advertising, then reconnect. Confirm you now see btsmp frames before the encrypted region. If they’re there, Wireshark should decrypt on reload.

B. Wrong key format or byte order

Symptom: you can see the handshake (or you’re entering an LTK manually for a Legacy capture), and it’s still garbage.

This one is almost always a formatting mistake in the LTK field. Two specifics catch people:

Endianness. The LTK as displayed in one tool may be the byte-reversed version of what Wireshark expects. If your key looks plausible but decrypts nothing, reverse the byte order and try again. Reversed-byte LTKs are the single most common “I entered the key and it didn’t work” cause.

Stray characters. The BTLE field wants raw hex only. Strip every space, colon, and 0x. A key copied from a log with separators won’t match.

Fix: paste the LTK as a continuous hex string, test it, and if that fails, flip the byte order and test again. One of the two is almost always right.

C. Wrong channel or lost the connection mid-stream

Symptom: decryption works for a stretch, then you hit gaps, dropped packets, or the sniffer falls silent shortly after the connection forms.

This is a capture-quality problem, not a key problem. Either the sniffer didn’t follow the channel hop after connection, or it was parked on an advertising channel the central never used to initiate.

Diagnose by checking continuity. A healthy followed connection shows steady connection events across the hop sequence. Big gaps mean the sniffer lost the link.

Fix: make sure you selected the specific device in the plugin so the sniffer follows the connection rather than camping on one channel. Then handle the physical layer: get the sniffer antenna close to your devices, and reduce interference. Weak signal during the hop is a frequent cause of mid-stream dropout. Re-running the capture with the sniffer within a meter of the peripheral fixes more of these than any setting change.

Building this into your debugging routine

Capture the pairing handshake first, every time. Start the sniffer, select the advertising device, clear the bond so pairing re-runs on-air, then let the central connect. Configure decryption in Wireshark’s BTLE and NORDIC_BLE protocol preferences, reload, and verify with a btatt filter.

When it’s still encrypted, run the three checks in order: no pairing frames means you missed the handshake, a present handshake with a manual key means check format and byte order, and decryption that breaks up means the sniffer lost the channel hop.

For deeper work on what’s moving across your link once you can read it, the device encryption concepts docs cover how BLE security maps onto the rest of your stack.


Hubble Network lets you decrypt and inspect BLE traffic across your fleet without rebuilding your capture setup for every device. See how it works →