BLE Security Passcode

gnorkus
Posts: 35
Joined: Thu Mar 22, 2018 12:41 pm

BLE Security Passcode

Postby gnorkus » 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:

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);
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

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

chegewara
Posts: 591
Joined: Wed Jun 14, 2017 9:00 pm

Re: BLE Security Passcode

Postby chegewara » Fri Apr 27, 2018 6:15 pm

Hi,
first of all at the moment its not possible to use own passcode, its been requested on github and maybe will be added. So you can only use random 6-digit code at the moment.
In your code you have set ESP_LE_AUTH_REQ_SC_BOND which means that esp32 will be bonded and after reconnecting esp32 should connect with windows or any other bonded device without need to re-enter passcode, authentication procedure is not required with bonded device.
Also this flag is properly set ESP_IO_CAP_OUT if you want to display passcode on esp32, if esp32 is going to be keyboard then passcode will be displayed on laptop and you need to use ESP_IO_CAP_IN in this case.

chegewara
Posts: 591
Joined: Wed Jun 14, 2017 9:00 pm

Re: BLE Security Passcode

Postby chegewara » Sat Sep 15, 2018 1:49 am

gnorkus wrote: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:
It is implemented now in esp-idf.

Kenya Suzuki
Posts: 2
Joined: Wed Sep 19, 2018 5:57 am

Re: BLE Security Passcode

Postby Kenya Suzuki » Wed Sep 19, 2018 9:35 am

Hi,

I'm facing almost same problem too.

In my case, I want to implement pairing between ESP32 and iPhone(ios11)
and I don't need any passcode.

The ideal behavior is that once one iPhone connected to ESP32,
any other central devices can't scan the ESP32 until the pairing is broken.

In the present, I can scan ESP32 from iPhone and can connect it with pairing alert(just yes/no).
But once disconnect, other iPhones also can search ESP32.

Code is below.

```
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>


#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

class MySecurity : public BLESecurityCallbacks {

uint32_t onPassKeyRequest(){
Serial.println("PassKeyRequest!");
ESP_LOGI(LOG_TAG, "PassKeyRequest");
return 123456;
}

void onPassKeyNotify(uint32_t pass_key){
Serial.println("On passkey Notify!");
ESP_LOGI(LOG_TAG, "On passkey Notify number:%d", pass_key);
}

bool onSecurityRequest(){
Serial.println("On Security Request!");
ESP_LOGI(LOG_TAG, "On Security Request");
return true;
}

void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl){
if(cmpl.success){
Serial.println("onAuthenticationComplete!");
uint16_t length;
esp_ble_gap_get_whitelist_size(&length);
ESP_LOGD(LOG_TAG, "size: %d", length);
} else {
Serial.println("onAuthentication not Complete!");
}
}

bool onConfirmPIN(uint32_t pin){
Serial.println("onConfirmPIN!");
return true;
}
};
void setup() {
Serial.begin(115200);
Serial.println("Starting BLE work!");

BLEDevice::init("ESP32");
BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);
/*
* Required in authentication process to provide displaying and/or input passkey or yes/no butttons confirmation
*/
BLEDevice::setSecurityCallbacks(new MySecurity());
BLEServer *pServer = BLEDevice::createServer();
BLEService *pService = pServer->createService(SERVICE_UUID);
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);

pCharacteristic->setValue("Hello World says Neil");
pService->start();
BLEAdvertising *pAdvertising = pServer->getAdvertising();
pAdvertising->setScanFilter(1,0);
pAdvertising->addServiceUUID(SERVICE_UUID);
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);
Serial.println("Characteristic defined! Now you can read it in your phone!");
}

void loop() {
// put your main code here, to run repeatedly:
delay(2000);
}
```

Are there any problem?

Thanks in advance.

Who is online

Users browsing this forum: Baidu [Spider] and 17 guests