Skip to content

Commit 44a98b6

Browse files
committed
enhance pairing to work with numberic comparison
1 parent 61beff2 commit 44a98b6

File tree

4 files changed

+91
-51
lines changed

4 files changed

+91
-51
lines changed

libraries/Bluefruit52Lib/examples/Central/central_bleuart/central_bleuart.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ BLEClientUart clientUart; // bleuart client
2525
void setup()
2626
{
2727
Serial.begin(115200);
28-
while ( !Serial ) delay(10); // for nrf52840 with native usb
28+
// while ( !Serial ) delay(10); // for nrf52840 with native usb
2929

3030
Serial.println("Bluefruit52 Central BLEUART Example");
3131
Serial.println("-----------------------------------\n");

libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@
2222
/* This sketch demonstrates Pairing process using dynamic Passkey.
2323
* This sketch is essentially the same as bleuart.ino except the BLE Uart
2424
* service requires Security Mode with Man-In-The-Middle protection i.e
25+
*
26+
* BLE Pairing procedure is complicated, it is advisable for users to go through
27+
* these articles to get familiar with the procedure and terminology
28+
* - https://www.bluetooth.com/blog/bluetooth-pairing-part-1-pairing-feature-exchange/
29+
* - https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/
30+
* - https://www.bluetooth.com/blog/bluetooth-pairing-passkey-entry/
31+
* - https://www.bluetooth.com/blog/bluetooth-pairing-part-4/
2532
*/
2633

2734
/* This sketch demonstrates the "Image Upload" feature of Bluefruit Mobile App.
@@ -125,6 +132,9 @@ void setup()
125132

126133
#endif // TFT
127134

135+
pinMode(PIN_BUTTON1, INPUT_PULLUP);
136+
pinMode(PIN_BUTTON2, INPUT_PULLUP);
137+
128138
// Setup the BLE LED to be enabled on CONNECT
129139
// Note: This is actually the default behavior, but provided
130140
// here in case you want to control this LED manually via PIN 19
@@ -142,7 +152,9 @@ void setup()
142152
// To use dynamic PassKey for pairing, we need to have
143153
// - IO capacities at least DISPPLAY
144154
// - Register callback to display/print dynamic passkey for central
145-
Bluefruit.Pairing.setIOCaps(true, false, false);
155+
// For complete mapping of the IO Capabilities to Key Generation Method, check out this article
156+
// https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/
157+
Bluefruit.Pairing.setIOCaps(true, true, false); // display = true, yes/no = true, keyboard = false
146158
Bluefruit.Pairing.setPasskeyCallback(pairing_passkey_callback);
147159

148160
// Set complete callback to print the pairing result
@@ -223,20 +235,67 @@ void loop()
223235
}
224236
}
225237

226-
void pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6])
238+
// callback invoked when pairing passkey is generated
239+
// - passkey: 6 keys (without null terminator) for displaying
240+
// - match_request: true when authentication method is Numberic Comparison.
241+
// Then this callback's return value is used to accept (true) or
242+
// reject (false) the pairing process. Otherwise, return value has no effect
243+
bool pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool match_request)
227244
{
228-
Serial.println("Enter this code on your phone to pair with Bluefruit:");
245+
Serial.println("Pairing Passkey");
229246
Serial.printf(" %.3s %.3s\n", passkey, passkey+3);
230247

231248
#if TFT_IN_USE != TFT_NO_DISPLAY
232-
tft.printf("Enter this code on your phone to pair with Bluefruit:\n\n");
249+
tft.fillScreen(COLOR_BLACK);
250+
tft.println("Pairing Passkey\n");
233251
tft.setTextColor(COLOR_YELLOW);
234252
tft.setTextSize(4);
235-
tft.printf(" %.3s %.3s\n", passkey, passkey+3);
253+
tft.printf(" %.3s %.3s\n", passkey, passkey+3);
236254

237255
tft.setTextColor(COLOR_WHITE);
238256
tft.setTextSize(2);
239257
#endif
258+
259+
260+
if (match_request)
261+
{
262+
Serial.println("Do you want to pair");
263+
Serial.println("Press Button A to accept, Button B to reject");
264+
265+
#if TFT_IN_USE != TFT_NO_DISPLAY
266+
tft.println("\nDo you accept ?\n\n");
267+
268+
tft.setTextSize(3);
269+
tft.setTextColor(COLOR_GREEN);
270+
tft.print("<< Yes");
271+
tft.setTextColor(COLOR_RED);
272+
tft.println(" No >>");
273+
274+
tft.setTextColor(COLOR_WHITE);
275+
tft.setTextSize(2);
276+
#endif
277+
278+
// wait until either button is pressed
279+
while( digitalRead(PIN_BUTTON1) && digitalRead(PIN_BUTTON2) ) { }
280+
281+
// wait until either button is pressed
282+
uint32_t start_time = millis();
283+
while( digitalRead(PIN_BUTTON1) && digitalRead(PIN_BUTTON2) )
284+
{
285+
// 30 seconds timeout
286+
if ( millis() > start_time + 30000 ) break;
287+
}
288+
289+
// A = accept
290+
if ( 0 == digitalRead(PIN_BUTTON1) ) return true;
291+
292+
// B = reject
293+
if ( 0 == digitalRead(PIN_BUTTON2) ) return false;
294+
295+
return false;
296+
}
297+
298+
return true;
240299
}
241300

242301
void pairing_complete_callback(uint16_t conn_handle, uint8_t auth_status)

libraries/Bluefruit52Lib/src/BLEPairing.cpp

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ bool BLEPairing::begin(void)
102102
return true;
103103
}
104104

105-
void BLEPairing::setIOCaps(bool display, bool keyboard, bool yes_no)
105+
void BLEPairing::setIOCaps(bool display, bool yes_no, bool keyboard)
106106
{
107107
uint8_t io_caps = BLE_GAP_IO_CAPS_NONE;
108108

@@ -125,9 +125,6 @@ void BLEPairing::setIOCaps(bool display, bool keyboard, bool yes_no)
125125
}
126126

127127
_sec_param.io_caps = io_caps;
128-
129-
// also set Man in the middle protection if we have some IO caps
130-
if (io_caps != BLE_GAP_IO_CAPS_NONE) _sec_param.mitm = 1;
131128
}
132129

133130
void BLEPairing::setMITM(bool enabled)
@@ -171,27 +168,19 @@ bool BLEPairing::resolveAddress(ble_gap_addr_t const * p_addr, ble_gap_irk_t con
171168
// Use Legacy SC static Passkey
172169
bool BLEPairing::setPIN(const char* pin)
173170
{
174-
if (pin == NULL)
175-
{
176-
// back to default mode
177-
_sec_param = _sec_param_default;
178-
}else
179-
{
180-
VERIFY(strlen(pin) == BLE_GAP_PASSKEY_LEN);
181-
182-
// Static Passkey requires using
183-
// - Legacy SC
184-
// - IO cap: Display
185-
// - MITM is on
186-
_sec_param.bond = 1;
187-
_sec_param.mitm = 1;
188-
_sec_param.lesc = 0;
189-
_sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY;
190-
191-
ble_opt_t opt;
192-
opt.gap_opt.passkey.p_passkey = (const uint8_t*) pin;
193-
VERIFY_STATUS(sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false);
194-
}
171+
VERIFY(pin && strlen(pin) == BLE_GAP_PASSKEY_LEN);
172+
173+
// Static Passkey requires using
174+
// - Legacy SC
175+
// - IO cap: Display
176+
// - MITM is on
177+
_sec_param.mitm = 1;
178+
_sec_param.lesc = 0;
179+
_sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY;
180+
181+
ble_opt_t opt;
182+
opt.gap_opt.passkey.p_passkey = (const uint8_t*) pin;
183+
VERIFY_STATUS(sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false);
195184

196185
return true;
197186
}
@@ -201,17 +190,8 @@ bool BLEPairing::setPasskeyCallback(pair_passkey_cb_t fp)
201190
{
202191
_passkey_cb = fp;
203192

204-
if ( fp == NULL )
205-
{
206-
// back to default mode
207-
_sec_param = _sec_param_default;
208-
}else
209-
{
210-
_sec_param.bond = 1;
211-
_sec_param.mitm = 1;
212-
_sec_param.lesc = LESC_SUPPORTED;
213-
_sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY;
214-
}
193+
// mitm is required to trigger passkey generation
194+
_sec_param.mitm = 1;
215195

216196
return true;
217197
}
@@ -304,12 +284,15 @@ void BLEPairing::_eventHandler(ble_evt_t* evt)
304284
LOG_LV2("PAIR", "Passkey = %.6s, match request = %d", passkey_display->passkey, passkey_display->match_request);
305285

306286
// Invoke display callback
307-
if ( _passkey_cb ) ada_callback(passkey_display->passkey, 6, _passkey_cb, conn_hdl, passkey_display->passkey);
308-
309-
if (passkey_display->match_request)
287+
if ( _passkey_cb )
310288
{
311-
// Match request require to report the match
312-
// sd_ble_gap_auth_key_reply();
289+
bool matched = _passkey_cb(conn_hdl, passkey_display->passkey, passkey_display->match_request);
290+
291+
if (passkey_display->match_request)
292+
{
293+
// Match request require to report the match (numberic comparison)
294+
sd_ble_gap_auth_key_reply(conn_hdl, matched ? BLE_GAP_AUTH_KEY_TYPE_PASSKEY : BLE_GAP_AUTH_KEY_TYPE_NONE, NULL);
295+
}
313296
}
314297
}
315298
break;

libraries/Bluefruit52Lib/src/BLEPairing.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
class BLEPairing
3636
{
3737
public:
38-
typedef void (*pair_passkey_cb_t ) (uint16_t conn_hdl, uint8_t const passkey[6]);
38+
typedef bool (*pair_passkey_cb_t ) (uint16_t conn_hdl, uint8_t const passkey[6], bool match_request);
3939
typedef void (*pair_complete_cb_t) (uint16_t conn_hdl, uint8_t auth_status);
4040

4141
BLEPairing(void);
@@ -46,7 +46,7 @@ class BLEPairing
4646
bool setPIN(const char* pin);
4747

4848
// Set IO capacities
49-
void setIOCaps(bool display, bool keyboard, bool yes_no);
49+
void setIOCaps(bool display, bool yes_no, bool keyboard);
5050

5151
// Enable/Disable Man in the middle protection
5252
void setMITM(bool enabled);
@@ -58,8 +58,6 @@ class BLEPairing
5858
bool setPasskeyCallback(pair_passkey_cb_t fp);
5959
void setCompleteCallback(pair_complete_cb_t fp);
6060

61-
62-
6361
/*------------------------------------------------------------------*/
6462
/* INTERNAL USAGE ONLY
6563
* Although declare as public, it is meant to be invoked by internal

0 commit comments

Comments
 (0)