Bluetooth Secure Simple Pairing (SSP)

 

Bluetooth Secure Simple Pairing (SSP) – Bluetooth development in c
How Bluetooth protects your connections — Eavesdropping, MITM attacks, ECDH cryptography, and all four association models explained with code
2.1+EDR
Introduced In
4
Association Models
ECDH
Crypto Algorithm
16-char
Alphanumeric PIN

Keywords:

bluetooth secure simple pairing SSP bluetooth bluetooth pairing methods MITM attack bluetooth bluetooth security ECDH bluetooth bluetooth pairing programming in C numeric comparison bluetooth passkey entry bluetooth just works bluetooth out of band pairing

Why SSP Was Needed

Before Bluetooth 2.1, pairing was based on a 4-digit numeric PIN. That is only 10,000 possible values. Attackers could brute-force this in seconds, and most users never changed the factory default — 0000, 1234, 8888.

Bluetooth 2.1 + EDR introduced Secure Simple Pairing (SSP) with two goals: make pairing easier for users and make it significantly harder to attack. It replaced the weak PIN with a 16-character alphanumeric key backed by real public-key cryptography (ECDH).

Section 3.6 in the Bluetooth Core Spec covers SSP in full detail. This post focuses on the two security goals and the four association models — the exact concepts you need when implementing pairing logic in a Bluetooth stack.

Before SSP vs After SSP

Property Bluetooth <= 2.0 + EDR Bluetooth 2.1 + EDR (SSP)
PIN Type 4-digit numeric only 16-character alphanumeric
Possible values 10,000 ~6 × 1022
Key Exchange Symmetric PIN only ECDH public-key exchange
Eavesdropping Protection Weak Strong
MITM Protection None Yes (model dependent)
User Experience Manual PIN entry on both sides Often zero user interaction needed

3.6 — SSP Security Goals

3.6.1 — Passive Eavesdropping Protection
What Is Passive Eavesdropping?

A passive attacker sits nearby and records all the radio packets flying between two Bluetooth devices. They do not interfere — they just listen. If the key exchange is weak, they can later derive the session key and decrypt everything that was recorded.

SSP fights this with two mechanisms working together:

Strong Link Key (high entropy) ECDH Public Key Cryptography

  ECDH KEY EXCHANGE IN SSP
  ════════════════════════════════════════════════════════════════

  Device A                                           Device B
  ─────────────────                           ─────────────────

  Generate private key: a                     Generate private key: b
  Compute public key:                         Compute public key:
    PKa = a * G  (G = curve base point)         PKb = b * G

                     ──── PKa ────────────►
                     ◄─── PKb ────────────

  Compute shared secret:                      Compute shared secret:
    DHKey = a * PKb                             DHKey = b * PKa
          = a * (b * G)                               = b * (a * G)
          = ab * G  ✓                                 = ab * G  ✓

  Both sides now have the SAME DHKey without ever transmitting it.
  A passive attacker who captured PKa and PKb cannot derive DHKey
  without solving the Elliptic Curve Discrete Logarithm Problem.

  ────────────────────────────────────────────────────────────────
  WHY ECDH OVER CLASSIC DH?
  • Classic DH needs large prime numbers (2048-bit+) for security
  • ECDH achieves equivalent security with a 256-bit key
  • Bluetooth controllers have limited CPU — ECDH fits perfectly
  ────────────────────────────────────────────────────────────────
Figure 3.23 — ECDH key exchange: same shared secret, nothing useful intercepted

3.6.2 — Man-in-the-Middle (MITM) Attack Protection
How an MITM Attack Works

In an MITM attack the attacker is not passive — they actively intercept traffic. Device A thinks it is talking to Device B, and Device B thinks it is talking to Device A. In reality both are connected to the attacker (Device M) in the middle. Device M reads, possibly alters, and then forwards every message.

The dangerous part: ECDH alone does not stop MITM. If A exchanges a public key with M thinking it is B, and M exchanges a different public key with B thinking it is A, ECDH still completes — but M holds both session keys and can read everything. This is why SSP adds a separate confirmation step on top of ECDH.

  MITM ATTACK — HOW IT LOOKS
  ════════════════════════════════════════════════════════════════

  EXPECTED (what users believe):
  ┌──────────┐                                   ┌──────────┐
  │ Device A │◄────────── Direct Link ───────────►│ Device B │
  └──────────┘                                   └──────────┘

  ACTUAL (with attacker M in the middle):
  ┌──────────┐    ┌───────────────────────┐    ┌──────────┐
  │ Device A │◄──►│   Device M (Attacker) │◄──►│ Device B │
  └──────────┘    └───────────────────────┘    └──────────┘
        A↔M: M pretends to be B       M↔B: M pretends to be A

  What M can do:
  ─────────────
  • Read all messages (confidentiality broken)
  • Inject fake commands or data
  • Silently drop or replay packets
  • Impersonate either device for future sessions

  How SSP detects M:
  ──────────────────
  • Numeric Comparison: both A and B display a 6-digit number.
    If M is in the middle, the numbers will NOT match.
    User sees mismatch → rejects pairing → M is detected.
  • If M's connection drops: A and B lose communication.
    User can infer something is wrong.
Figure 3.22 — MITM attack: Device M intercepts traffic between A and B

3.6.3 — SSP Association Models

SSP does not force one fixed pairing method on every device. Instead, it defines four association models. The model selected during pairing depends on the I/O capabilities of both devices involved — does the device have a screen? Can it accept key input?

The Bluetooth stack on each device advertises its I/O capability during the capability exchange phase, and the two sides negotiate which model to use.

I/O Capability to Association Model Mapping
Device A Capability Device B Capability Model Selected MITM Protection
Display + Yes/No Display + Yes/No Numeric Comparison Yes
Display only Keyboard only Passkey Entry Yes
No display, No input Any Just Works No
NFC enabled NFC enabled Out of Band (OOB) Yes (if OOB channel is secure)

3.6.3.1 — Numeric Comparison
When and How It Works

Both devices must be able to display a 6-digit number and accept a Yes / No response from the user. During pairing, both screens show the same 6-digit code. The user simply checks whether the number matches on both screens and confirms.

This works even on devices that have a small display but no full keyboard — a single confirmation button is enough. The 6-digit number is derived from the ECDH exchange, so if an attacker is in the middle the numbers will differ.

  NUMERIC COMPARISON — PAIRING FLOW
  ════════════════════════════════════════════════════════════════

  Device A (Phone)                            Device B (Laptop)
  ──────────────────                          ─────────────────

  1. Exchange I/O capabilities
     ──── IO_CAP: DisplayYesNo ────────────►
     ◄─── IO_CAP: DisplayYesNo ────────────

  2. ECDH public key exchange
     ──── Public Key PKa ──────────────────►
     ◄─── Public Key PKb ──────────────────

  3. Compute DHKey (shared secret) on both sides

  4. Generate commitment values (Cb, Ca) using nonces + DHKey

  5. Exchange nonces (Na, Nb)

  6. Both sides compute the 6-digit confirmation value V:
     V = f4(PKax, PKbx, Na, 0)   (same formula, same result)

  ┌──────────────────┐           ┌──────────────────────────────┐
  │  Screen shows:   │           │  Screen shows:               │
  │                  │           │                              │
  │    [ 4 8 7 2 3 ] │           │    [ 4 8 7 2 3 ]            │
  │                  │           │                              │
  │  Confirm? YES/NO │           │  Confirm? YES/NO            │
  └──────────────────┘           └──────────────────────────────┘
         ↓ User presses YES              ↓ User presses YES

  7. Pairing succeeds — link key derived from DHKey

  ─── MITM scenario: M replaces PKb with PKm ─────────────────────
  • A computes V using PKm instead of PKb → V_A = 312890
  • B computes V using PKm instead of PKa → V_B = 895123
  • Numbers do NOT match → user rejects → MITM detected ✓
Figure 3.24 — Numeric Comparison: matching 6-digit codes confirm no MITM present

3.6.3.2 — Just Works
Zero User Interaction — At a Cost

Just Works is Numeric Comparison running silently — the 6-digit code is computed and verified internally by the stack but never shown to the user. Pairing completes without the user doing anything.

This is the right model for devices like mono Bluetooth headsets that have no screen and no buttons beyond play/pause. You cannot ask the user to confirm a number they cannot see.

Security trade-off: Because the confirmation number is never shown to the user, there is no way for the user to detect an MITM attack. Just Works provides strong passive eavesdropping protection but no MITM protection. It is still much safer than a pre-SSP 4-digit PIN, but treat it as a best-effort pairing model for constrained devices.

3.6.3.3 — Out of Band (OOB)
Using a Second Channel for Security

OOB pairing exchanges authentication data over a different communication channel — typically NFC. The idea is that an attacker who can intercept Bluetooth radio packets almost certainly cannot also intercept a very short-range NFC tap at the same time.

When the user physically taps two devices together, the NFC channel transfers device addresses and random values. These are then fed into the Bluetooth pairing process in place of the numeric confirmation step.

Security note: OOB security is only as strong as the OOB channel itself. NFC is considered secure because of its physical proximity requirement (~4 cm). If the OOB channel were something like plain QR code display in a public place, the protection would be weaker.
  OUT-OF-BAND PAIRING WITH NFC
  ════════════════════════════════════════════════════════════════

  Bluetooth Channel               NFC Channel (OOB)
  ─────────────────               ─────────────────────────────

                                  User physically taps devices
                                  ┌──────┐      ┌──────┐
                                  │  A   │◄────►│  B   │
                                  └──────┘      └──────┘
                                    NFC range: ~4 cm

                                  Transfers:
                                    • BD_ADDR of A and B
                                    • Random nonce r_A, r_B
                                    • Hash values c_A, c_B

  ──── Confirm OOB data received ──────────────────────────────►
  ◄─── Confirm OOB data received ─────────────────────────────

  Both sides verify hashes:
    A verifies: c_B = f(r_B, PKb, BD_ADDR_B)  ✓
    B verifies: c_A = f(r_A, PKa, BD_ADDR_A)  ✓

  Link key derived → Pairing complete
Figure 3.25 — OOB pairing: NFC transfers authentication data outside the Bluetooth radio

3.6.3.4 — Passkey Entry
One Device Displays, One Device Types

Passkey Entry is designed for the classic keyboard-to-PC pairing scenario. One device has a display (the PC) and shows a 6-digit passkey. The other device has a keyboard (the BT keyboard) and the user types in that code.

This provides MITM protection because a human is actively verifying and transferring a secret value. An attacker in the middle would need to intercept what is being shown on the display and what the user is typing — neither of which travels over the Bluetooth radio.

  PASSKEY ENTRY — PAIRING FLOW
  ════════════════════════════════════════════════════════════════

  PC (Display only)                      BT Keyboard (Input only)
  ─────────────────                      ────────────────────────

  1. I/O capability exchange
     ──── IO_CAP: DisplayOnly ──────────►
     ◄─── IO_CAP: KeyboardOnly ──────────

  2. PC generates random 6-digit passkey (e.g. 483921)

  ┌─────────────────┐
  │  PC Screen:     │
  │                 │
  │   PIN: 483921   │
  │                 │
  └─────────────────┘

  3. User reads passkey from PC screen

  4. User types 4 8 3 9 2 1 on the Bluetooth keyboard

                                         ┌─────────────────────┐
                                         │  User types:        │
                                         │  4 - 8 - 3 - 9 -    │
                                         │  2 - 1 - ENTER      │
                                         └─────────────────────┘

  5. Passkey is used bit-by-bit in 20 rounds of commitment
     exchanges to build the link key — passkey never sent raw
     over the Bluetooth air interface.

  6. Stack verifies both sides used the same passkey
     → Link key generated → Pairing complete
Figure 3.26 — Passkey Entry: human verifies the secret, protects against MITM

Association Model — Side-by-Side Comparison

  MODEL            DISPLAY NEEDED   INPUT NEEDED   PASSIVE EVE   MITM
  ──────────────   ──────────────   ────────────   ───────────   ────
  Numeric Comp.        YES              YES/NO         Yes         Yes
  Just Works            NO               NO            Yes          No
  Out of Band      Optional         Optional           Yes         Yes *
  Passkey Entry        YES              YES            Yes         Yes

  * OOB MITM protection depends on the OOB channel being secure.

  REAL-WORLD DEVICE EXAMPLES:
  ──────────────────────────────────────────────────────────────────
  Model               Typical Device Pair
  ──────────────────  ─────────────────────────────────────────────
  Numeric Comparison  Phone + Laptop, Phone + Car infotainment
  Just Works          Phone + Mono headset, Phone + BT speaker
  Out of Band         Phone + Smart tag (NFC tap to pair)
  Passkey Entry       Laptop + BT keyboard, Laptop + BT mouse
Figure 3.27 — Association model comparison at a glance

Bluetooth SSP Programming in C

I/O Capability Constants and Structures
📄 ssp_io_capabilities.h
#ifndef SSP_IO_CAPABILITIES_H
#define SSP_IO_CAPABILITIES_H

#include <stdint.h>

/*
 * HCI I/O Capability values (Bluetooth Core Spec Vol 2, Part C, 5.2.1)
 * Used in HCI_IO_Capability_Request_Reply command.
 */
#define IO_CAP_DISPLAY_ONLY       0x00  /* e.g. BT speaker with LED display */
#define IO_CAP_DISPLAY_YES_NO     0x01  /* e.g. Phone, Laptop               */
#define IO_CAP_KEYBOARD_ONLY      0x02  /* e.g. BT keyboard (no screen)     */
#define IO_CAP_NO_INPUT_NO_OUTPUT 0x03  /* e.g. Mono headset                */
#define IO_CAP_KEYBOARD_DISPLAY   0x04  /* e.g. Full smartphone             */

/*
 * OOB Data Present field
 */
#define OOB_DATA_NOT_PRESENT  0x00
#define OOB_DATA_FROM_REMOTE  0x01

/*
 * Authentication Requirements
 * Bit 2 = MITM protection required (1 = yes)
 * Bit 0 = Dedicated bonding (vs general bonding)
 */
#define AUTH_REQ_NO_BONDING_NO_MITM   0x00
#define AUTH_REQ_BONDING_NO_MITM      0x02
#define AUTH_REQ_NO_BONDING_MITM      0x04
#define AUTH_REQ_BONDING_MITM         0x05

/*
 * Association model selected based on I/O capability negotiation.
 * Use ssp_select_model() to determine this at runtime.
 */
typedef enum {
    SSP_MODEL_NUMERIC_COMPARISON = 0,
    SSP_MODEL_JUST_WORKS,
    SSP_MODEL_OUT_OF_BAND,
    SSP_MODEL_PASSKEY_ENTRY,
    SSP_MODEL_UNKNOWN
} ssp_model_t;

typedef struct {
    uint8_t io_capability;   /* One of IO_CAP_* above            */
    uint8_t oob_present;     /* OOB_DATA_NOT_PRESENT or _PRESENT  */
    uint8_t auth_req;        /* AUTH_REQ_* flags                  */
} ssp_io_cap_t;

#endif /* SSP_IO_CAPABILITIES_H */
Association Model Selection Logic
📄 ssp_model_select.c
#include <stdio.h>
#include "ssp_io_capabilities.h"

/*
 * ssp_select_model()
 *
 * Implements the SSP association model selection table from
 * Bluetooth Core Spec Vol 2, Part C, Section 5.2.2.6.
 *
 * Returns the association model to use based on the combined
 * I/O capabilities of both devices.
 */
ssp_model_t ssp_select_model(const ssp_io_cap_t *local,
                              const ssp_io_cap_t *remote)
{
    /* OOB takes priority if both sides have OOB data */
    if (local->oob_present  == OOB_DATA_FROM_REMOTE ||
        remote->oob_present == OOB_DATA_FROM_REMOTE) {
        return SSP_MODEL_OUT_OF_BAND;
    }

    /*
     * If neither side requires MITM, Just Works is used
     * when the combined capability would normally give Numeric
     * Comparison or Passkey Entry — saves user effort.
     */
    uint8_t mitm_required = (local->auth_req  & 0x04) ||
                            (remote->auth_req & 0x04);

    uint8_t l = local->io_capability;
    uint8_t r = remote->io_capability;

    /*
     * Table lookup: rows = local IO cap, columns = remote IO cap
     * Values: N=NumericComparison, J=JustWorks, P=Passkey
     *
     *                   Remote
     *              DOnly  DYN  KOnly  NINO  KD
     * Local DOnly:   J     N     P     J    P
     * Local DYN  :   N     N     P     J    N
     * Local KOnly:   P     P     P     J    P
     * Local NINO :   J     J     J     J    J
     * Local KD   :   P     N     P     J    N
     */

    /* NINO (no input, no output) always gives Just Works */
    if (l == IO_CAP_NO_INPUT_NO_OUTPUT ||
        r == IO_CAP_NO_INPUT_NO_OUTPUT) {
        return SSP_MODEL_JUST_WORKS;
    }

    /* Determine if Passkey Entry applies */
    int local_has_display = (l == IO_CAP_DISPLAY_ONLY     ||
                              l == IO_CAP_DISPLAY_YES_NO   ||
                              l == IO_CAP_KEYBOARD_DISPLAY);

    int remote_has_input  = (r == IO_CAP_KEYBOARD_ONLY    ||
                              r == IO_CAP_KEYBOARD_DISPLAY);

    int remote_has_display = (r == IO_CAP_DISPLAY_ONLY    ||
                               r == IO_CAP_DISPLAY_YES_NO  ||
                               r == IO_CAP_KEYBOARD_DISPLAY);

    int local_has_input   = (l == IO_CAP_KEYBOARD_ONLY    ||
                              l == IO_CAP_KEYBOARD_DISPLAY);

    /* Numeric Comparison: both sides have display + yes/no capability */
    if ((l == IO_CAP_DISPLAY_YES_NO || l == IO_CAP_KEYBOARD_DISPLAY) &&
        (r == IO_CAP_DISPLAY_YES_NO || r == IO_CAP_KEYBOARD_DISPLAY)) {
        return SSP_MODEL_NUMERIC_COMPARISON;
    }

    /* Passkey Entry: one side has display, other has keyboard */
    if ((local_has_display && remote_has_input) ||
        (local_has_input   && remote_has_display)) {
        return SSP_MODEL_PASSKEY_ENTRY;
    }

    /*
     * If MITM is not required, fall back to Just Works even if
     * Numeric Comparison capability exists.
     */
    if (!mitm_required) {
        return SSP_MODEL_JUST_WORKS;
    }

    return SSP_MODEL_JUST_WORKS; /* fallback */
}

const char *ssp_model_name(ssp_model_t model)
{
    switch (model) {
    case SSP_MODEL_NUMERIC_COMPARISON: return "Numeric Comparison";
    case SSP_MODEL_JUST_WORKS:         return "Just Works";
    case SSP_MODEL_OUT_OF_BAND:        return "Out of Band (OOB)";
    case SSP_MODEL_PASSKEY_ENTRY:      return "Passkey Entry";
    default:                           return "Unknown";
    }
}

/* -------------------------------------------------------
 * Handle an incoming HCI_IO_Capability_Request event.
 * The host must reply with local I/O capabilities.
 * ------------------------------------------------------- */
void handle_io_cap_request(int hci_fd, const uint8_t *bd_addr)
{
    /*
     * HCI_IO_Capability_Request_Reply command
     *   OGF  = 0x01 (Link Control)
     *   OCF  = 0x002B
     *
     * Parameters:
     *   BD_ADDR       [6 bytes]
     *   IO_Capability [1 byte]  — advertise our capability
     *   OOB_Data_Present [1 byte]
     *   Authentication_Requirements [1 byte]
     */
    printf("[SSP] IO_Capability_Request received\n");
    printf("[SSP] Replying with: DisplayYesNo, NoOOB, MITM required\n");

    /*
     * In a real BlueZ-based implementation you would call:
     *   hci_send_cmd(hci_fd, OGF_LINK_CTL, 0x002B, params_len, params)
     *
     * Here we just show the parameter values for illustration.
     */
    uint8_t params[9];
    memcpy(params, bd_addr, 6);
    params[6] = IO_CAP_DISPLAY_YES_NO;    /* local I/O capability  */
    params[7] = OOB_DATA_NOT_PRESENT;     /* no NFC OOB data       */
    params[8] = AUTH_REQ_BONDING_MITM;    /* require MITM + bond   */

    printf("[SSP] Params: IO_CAP=0x%02X OOB=0x%02X AUTH=0x%02X\n",
           params[6], params[7], params[8]);
}

/* -------------------------------------------------------
 * Handle Numeric Comparison: compare and auto-confirm.
 * In a real product this would drive a UI prompt.
 * ------------------------------------------------------- */
void handle_user_confirmation_request(const uint8_t *bd_addr,
                                      uint32_t numeric_value)
{
    printf("[SSP] User Confirmation Request\n");
    printf("[SSP] Remote BD_ADDR: %02X:%02X:%02X:%02X:%02X:%02X\n",
           bd_addr[5], bd_addr[4], bd_addr[3],
           bd_addr[2], bd_addr[1], bd_addr[0]);
    printf("[SSP] Numeric Value on both screens: %06u\n", numeric_value);
    printf("[SSP] → Show this to user; send Positive Reply if they confirm\n");

    /*
     * HCI_User_Confirmation_Request_Positive_Reply (OCF=0x002C)
     * or HCI_User_Confirmation_Request_Negative_Reply (OCF=0x002D)
     * depending on user input.
     */
}

/* -------------------------------------------------------
 * Handle Passkey Request: display passkey to user.
 * ------------------------------------------------------- */
void handle_passkey_display(const uint8_t *bd_addr, uint32_t passkey)
{
    printf("[SSP] Passkey Notification\n");
    printf("[SSP] Display this code to user: %06u\n", passkey);
    printf("[SSP] User must type this on the remote device keyboard\n");
}

int main(void)
{
    printf("=== SSP Association Model Selection Demo ===\n\n");

    /* Scenario 1: Phone (DisplayYesNo) + Laptop (DisplayYesNo) */
    ssp_io_cap_t phone  = { IO_CAP_DISPLAY_YES_NO, OOB_DATA_NOT_PRESENT, AUTH_REQ_BONDING_MITM };
    ssp_io_cap_t laptop = { IO_CAP_DISPLAY_YES_NO, OOB_DATA_NOT_PRESENT, AUTH_REQ_BONDING_MITM };
    printf("Phone + Laptop   → %s\n",
           ssp_model_name(ssp_select_model(&phone, &laptop)));

    /* Scenario 2: Phone (DisplayYesNo) + Headset (NINO) */
    ssp_io_cap_t headset = { IO_CAP_NO_INPUT_NO_OUTPUT, OOB_DATA_NOT_PRESENT, AUTH_REQ_NO_BONDING_NO_MITM };
    printf("Phone + Headset  → %s\n",
           ssp_model_name(ssp_select_model(&phone, &headset)));

    /* Scenario 3: Laptop (DisplayOnly) + BT Keyboard (KeyboardOnly) */
    ssp_io_cap_t pc       = { IO_CAP_DISPLAY_ONLY,   OOB_DATA_NOT_PRESENT, AUTH_REQ_BONDING_MITM };
    ssp_io_cap_t keyboard = { IO_CAP_KEYBOARD_ONLY,  OOB_DATA_NOT_PRESENT, AUTH_REQ_BONDING_MITM };
    printf("Laptop + Keyboard → %s\n",
           ssp_model_name(ssp_select_model(&pc, &keyboard)));

    /* Scenario 4: Both NFC-enabled devices */
    ssp_io_cap_t nfc_a = { IO_CAP_DISPLAY_YES_NO, OOB_DATA_FROM_REMOTE, AUTH_REQ_BONDING_MITM };
    ssp_io_cap_t nfc_b = { IO_CAP_DISPLAY_YES_NO, OOB_DATA_FROM_REMOTE, AUTH_REQ_BONDING_MITM };
    printf("NFC device + NFC device → %s\n",
           ssp_model_name(ssp_select_model(&nfc_a, &nfc_b)));

    return 0;
}
💻 Compile and run
gcc -o ssp_demo ssp_model_select.c
./ssp_demo

# Output:
# Phone + Laptop    → Numeric Comparison
# Phone + Headset   → Just Works
# Laptop + Keyboard → Passkey Entry
# NFC device + NFC  → Out of Band (OOB)

Quick Reference

  SECURE SIMPLE PAIRING — QUICK REFERENCE
  ════════════════════════════════════════════════════════════════

  Introduced in : Bluetooth 2.1 + EDR
  Goals         : Passive eavesdropping protection + MITM protection

  Security Mechanisms
  ───────────────────
  • Strong Link Key : 16-char alphanumeric PIN (vs 4-digit before)
  • ECDH crypto     : Shared secret without transmitting it
                      Computationally lighter than classic DH

  I/O Capability Constants (HCI values)
  ──────────────────────────────────────
  0x00  IO_CAP_DISPLAY_ONLY        BT speaker, simple display
  0x01  IO_CAP_DISPLAY_YES_NO      Phone, laptop
  0x02  IO_CAP_KEYBOARD_ONLY       BT keyboard (no screen)
  0x03  IO_CAP_NO_INPUT_NO_OUTPUT  Mono headset, BT audio tag
  0x04  IO_CAP_KEYBOARD_DISPLAY    Full smartphone

  Association Models
  ──────────────────
  Numeric Comparison  Both display 6-digit code   MITM: YES
  Just Works          Silent, no user action       MITM: NO
  Out of Band (OOB)   NFC tap or similar           MITM: YES*
  Passkey Entry       One shows, one types 6 digits MITM: YES

  HCI Events During SSP
  ─────────────────────
  0x31  IO_Capability_Request          → reply with our caps
  0x32  IO_Capability_Response         ← remote caps received
  0x33  User_Confirmation_Request      → user sees 6-digit code
  0x34  User_Passkey_Request           → user types passkey
  0x35  Remote_OOB_Data_Request        → provide OOB data
  0x36  Simple_Pairing_Complete        ← result (success/fail)

Master Bluetooth Security

Continue with BLE Security — LE Pairing, SMP protocol, and key distribution at EmbeddedPathashala — completely free for embedded developers.

Visit EmbeddedPathashala Bluetooth Course

Leave a Reply

Your email address will not be published. Required fields are marked *