Bluetooth LE: pair & encrypt
Two ESP32-C6 boards secure a real LE link end-to-end: one advertises connectably, the other connects as central and calls gap_pair. The SMP Just-Works handshake runs over the link (watch the SMP frames in the Sniffer), the controllers derive the key and run the LL encryption-start procedure, and BOTH boards report _IRQ_ENCRYPTION_UPDATE with a 16-byte key; the peripheral’s report rides the emulator’s post-encryption receive path through the controller’s own buffer allocator. One script on both boards; roles derive from each board’s MAC.

How it works
Where BLE security starts: after the scan-connect sequence, the client calls gap_pair() and the boards run the real SMP Just-Works pairing protocol over the air: pairing request and response, key generation, and an encryption start that both sides confirm. The script's IRQ handler prints the payoff on each board: 'encrypted, key size 16'. That 16-byte key is the real thing, negotiated by the same state machine a phone and an earbud use.
What's on the bench
- 2× Battery
- 2× ESP32-C6
How it's wired
- Battery · pos→ESP32-C6 · vin
- Battery · neg→ESP32-C6 · gnd
- Battery · pos→ESP32-C6 · vin
- Battery · neg→ESP32-C6 · gnd
The code
This MicroPython script runs on the emulated board every boot; edit it in the Code tab.
import bluetooth, time b = bluetooth.BLE() b.active(1) b.config(bond=False, mitm=False, le_secure=False) S = {} server = b.config('mac')[1][-1] % 2 == 0 tag = 'SRV' if server else 'CLI' tgt = [] cn = [] def cb(e, d): if e == 29: t, i, k = d return None if k is None else S.get((t, bytes(k)), None) if e == 30: t, k, v = d k = (t, bytes(k)) if v is None: S.pop(k, None) else: S[k] = bytes(v) return True if e == 28: print(tag + ' encrypted, key size ' + str(d[4])) elif e == 5 and not tgt: tgt.append((d[0], bytes(d[1]))) print('CLI found advertiser') elif e == 7: cn.append(d[0]) print('CLI connected, pairing soon') elif e == 1: print('SRV central connected') b.irq(cb) if server: b.gap_advertise(50000, b'\x02\x01\x06\x05\xffCAFE', connectable=True) print('SRV advertising, ready to pair') else: b.gap_scan(0, 30000, 30000) while not tgt: time.sleep_ms(50) b.gap_scan(None) time.sleep_ms(50) b.gap_connect(tgt[0][0], tgt[0][1]) while not cn: time.sleep_ms(50) time.sleep_ms(2000) b.gap_pair(cn[0]) print('CLI pairing...')
Try this
- Wait for BOTH serial tabs to print 'encrypted, key size 16': the link is now confidential.
- Open the 📡 Sniffer and find the SMP exchange between connect and encrypt.
- Click a board's BLE tab: the padlock appears once the link encrypts.
- Note bond=False in the script: keys die with the connection. The next example fixes that.


