BLE Security Passcode
Posted: Fri Apr 27, 2018 5:57 pm
Hi All!
I'm trying to get my BLE Keyboard to properly request a security code from Windows. I do not want a random 6 digit code. Rather, I want to supply a pass code such as 123456. I have overridden the onPassKeyRequest member function so as to orovide the code. At the bottom of this post is the code I've tried. I think the lines causing my problem are as follows:
The desired operation is as follows:
1. Turn on device and scan for it in Windows Bluetooth and Other Devices settings dialog.
2. Attempt to connect device in windows. Windows should request a pass code
3. The ESP32 should NOT provide a random number (as seen in tty log). It should expect 123456.
4. If the passcode is correctly entered, the device should connect and remain connected as long as the client and host are powered.
5. Turn off the ESP32 device, wait a minute for Windows to show it as paired (as opposed to connected), and finally turn the device back on. It should properly connect without the necessity of a pass code.
I'm using a SparkFun ESP32 Thing and also a WRover Devkitc. This code successfully compiles and runs on both, but it always supplies a random pass code.
Thanks!
GJN
I'm trying to get my BLE Keyboard to properly request a security code from Windows. I do not want a random 6 digit code. Rather, I want to supply a pass code such as 123456. I have overridden the onPassKeyRequest member function so as to orovide the code. At the bottom of this post is the code I've tried. I think the lines causing my problem are as follows:
Code: Select all
BLESecurity *pSecurity = new BLESecurity();
pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND);
pSecurity->setCapability(ESP_IO_CAP_OUT);
pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
1. Turn on device and scan for it in Windows Bluetooth and Other Devices settings dialog.
2. Attempt to connect device in windows. Windows should request a pass code
3. The ESP32 should NOT provide a random number (as seen in tty log). It should expect 123456.
4. If the passcode is correctly entered, the device should connect and remain connected as long as the client and host are powered.
5. Turn off the ESP32 device, wait a minute for Windows to show it as paired (as opposed to connected), and finally turn the device back on. It should properly connect without the necessity of a pass code.
I'm using a SparkFun ESP32 Thing and also a WRover Devkitc. This code successfully compiles and runs on both, but it always supplies a random pass code.
Thanks!
GJN
Code: Select all
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLESecurity.h>
#include "freertos/FreeRTOS.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_event_loop.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#include "BLE2902.h"
#include "BLEHIDDevice.h"
#include "HIDKeyboardTypes.h"
#include "HIDTypes.h"
#include <esp_log.h>
#include <string>
#include <Task.h>
#include "sdkconfig.h"
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
esp_err_t event_handler(void *ctx, system_event_t *event)
{
return ESP_OK;
}
extern "C" {
void app_main();
}
/**
* Create a new BLE server.
*/
static char LOG_TAG[] = "SampleHIDDevice";
static BLEHIDDevice* hid;
BLECharacteristic* input;
BLECharacteristic* output;
/*
* This callback is connect with output report. In keyboard output report report special keys changes, like CAPSLOCK, NUMLOCK
* We can add digital pins with LED to show status
* bit 1 - NUM LOCK
* bit 2 - CAPS LOCK
* bit 3 - SCROLL LOCK
*/
class MyOutputCallbacks : public BLECharacteristicCallbacks
{
void onWrite(BLECharacteristic* me)
{
uint8_t* value = (uint8_t*)(me->getValue().c_str());
ESP_LOGI(LOG_TAG, "special keys: %d", *value);
}
};
class MyTask : public Task
{
void run(void*)
{
vTaskDelay(5000 / portTICK_PERIOD_MS); // wait 5 seconds before send first message
char hello[] = "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\n";
char *pstr ;
while (1)
{
pstr = hello ;
while (*pstr)
{
KEYMAP map = keymap[(uint8_t)*pstr];
/*
* simulate keydown, we can send up to 6 keys
*/
uint8_t a[] = { map.modifier, 0x0, map.usage, 0x0,0x0,0x0,0x0,0x0 };
input->setValue(a, sizeof(a));
input->notify();
vTaskDelay(10 / portTICK_PERIOD_MS);
/*
* simulate keyup
*/
uint8_t v[] = { 0x0, 0x0, 0x0, 0x0,0x0,0x0,0x0,0x0 };
input->setValue(v, sizeof(v));
input->notify();
pstr++;
vTaskDelay(10 / portTICK_PERIOD_MS);
}
vTaskDelay(500 / portTICK_PERIOD_MS); // simulate write message every 2 seconds
}
vTaskDelete(NULL);
}
};
MyTask *task;
class MyCallbacks : public BLEServerCallbacks
{
void onConnect(BLEServer* pServer)
{
task->start();
}
void onDisconnect(BLEServer* pServer)
{
task->stop();
}
};
class MySecurity : public BLESecurityCallbacks
{
~MySecurity()
{
}
uint32_t onPassKeyRequest()
{
ESP_LOGI(LOG_TAG, "PassKeyRequest");
return 123456;
}
void onPassKeyNotify(uint32_t pass_key)
{
ESP_LOGI(LOG_TAG, "On passkey Notify number:%d", pass_key);
}
bool onSecurityRequest()
{
ESP_LOGI(LOG_TAG, "On Security Request");
return true;
}
void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl)
{
ESP_LOGI(LOG_TAG, "Starting BLE work!");
if(cmpl.success)
{
uint16_t length;
esp_ble_gap_get_whitelist_size(&length);
ESP_LOGD(LOG_TAG, "size: %d", length);
}
}
bool onConfirmPIN(unsigned int v)
{
ESP_LOGI(LOG_TAG, "On Confirmed Pin Request %d", v);
return true;
}
};
class MainBLEServer: public Task
{
void run(void *data)
{
// Turn on the non volatile storage so that
// replugs will work properly (I hope)
esp_err_t ret;
// Initialize NVS.
ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_LOGD(LOG_TAG, "Starting BLE work!");
task = new MyTask();
BLEDevice::init("EnvisicPedal");
// These are needed to properly add ecnryption to the device...
// See the MySecurity class for the PIN of 123456
BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);
BLEDevice::setSecurityCallbacks(new MySecurity());
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyCallbacks());
/*
* Instantiate hid device
*/
hid = new BLEHIDDevice(pServer);
input = hid->inputReport(1); // <-- input REPORTID from report map
output = hid->outputReport(1); // <-- output REPORTID from report map
output->setCallbacks(new MyOutputCallbacks());
/*
* Set manufacturer name (OPTIONAL)
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.manufacturer_name_string.xml
*/
std::string name = "esp-community";
hid->manufacturer()->setValue(name);
/*
* Set pnp parameters (MANDATORY)
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.pnp_id.xml
*/
hid->pnp(0x02, 0xe502, 0xa111, 0x0210);
/*
* Set hid informations (MANDATORY)
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.hid_information.xml
*/
hid->hidInfo(0x00,0x01);
/*
* Keyboard
*/
const uint8_t reportMap[] = {
USAGE_PAGE(1), 0x01, // Generic Desktop Ctrls
USAGE(1), 0x06, // Keyboard
COLLECTION(1), 0x01, // Application
REPORT_ID(1), 0x01, // REPORTID
USAGE_PAGE(1), 0x07, // Kbrd/Keypad
USAGE_MINIMUM(1), 0xE0,
USAGE_MAXIMUM(1), 0xE7,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
REPORT_SIZE(1), 0x01, // 1 byte (Modifier)
REPORT_COUNT(1), 0x08,
INPUT(1), 0x02, // Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position
REPORT_COUNT(1), 0x01, // 1 byte (Reserved)
REPORT_SIZE(1), 0x08,
INPUT(1), 0x01, // Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position
REPORT_COUNT(1), 0x05, // 5 bits (Num lock, Caps lock, Scroll lock, Compose, Kana)
REPORT_SIZE(1), 0x01,
USAGE_PAGE(1), 0x08, // LEDs
USAGE_MINIMUM(1), 0x01, // Num Lock
USAGE_MAXIMUM(1), 0x05, // Kana
OUTPUT(1), 0x02, // Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
REPORT_COUNT(1), 0x01, // 3 bits (Padding)
REPORT_SIZE(1), 0x03,
OUTPUT(1), 0x01, // Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
REPORT_COUNT(1), 0x06, // 6 bytes (Keys)
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x65, // 101 keys
USAGE_PAGE(1), 0x07, // Kbrd/Keypad
USAGE_MINIMUM(1), 0x00,
USAGE_MAXIMUM(1), 0x65,
INPUT(1), 0x00, // Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position
END_COLLECTION(0)
};
/*
* Set report map (here is initialized device driver on client side) (MANDATORY)
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.report_map.xml
*/
hid->reportMap((uint8_t*)reportMap, sizeof(reportMap));
/*
* We are prepared to start hid device services. Before this point we can change all values and/or set parameters we need.
* Also before we start, if we want to provide battery info, we need to prepare battery service.
* We can setup characteristics authorization
*/
hid->startServices();
/*
* Its good to setup advertising by providing appearance and advertised service. This will let clients find our device by type
*/
BLEAdvertising *pAdvertising = pServer->getAdvertising();
pAdvertising->setAppearance(HID_KEYBOARD);
pAdvertising->addServiceUUID(hid->hidService()->getUUID());
pAdvertising->start();
BLESecurity *pSecurity = new BLESecurity();
pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND);
pSecurity->setCapability(ESP_IO_CAP_OUT);
pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
ESP_LOGD(LOG_TAG, "Advertising started!");
delay(1000000);
}
};
void app_main(void)
{
//esp_log_level_set("*", ESP_LOG_DEBUG);
MainBLEServer* pMainBleServer = new MainBLEServer();
pMainBleServer->setStackSize(20000);
pMainBleServer->start();
} // app_main