T-vK / ESP32-BLE-Keyboard

Bluetooth LE Keyboard library for the ESP32 (Arduino IDE compatible)
2.41k stars 404 forks source link

[FR] More secure binding as an option #24

Open SvOlli opened 4 years ago

SvOlli commented 4 years ago

Hello, and first of all thanks for giving me the opportunity to build a C64 based Bluetooth keyboard: https://github.com/SvOlli/VICEboard But for pairing, I would like it behave like another Bluetooth keyboard I have: upon pairing you need to enter a number on the keyboard to prevent someone else from also pairing it. As far as I've read through the API and code, this is only a parameter that needs to be changed, and made available somehow.

T-vK commented 4 years ago

Great project, I love it. I'm not sure what would be required to enable pin authentication. But you might have to set a different authentication mode here: https://github.com/T-vK/ESP32-BLE-Keyboard/blob/master/BleKeyboard.cpp#L142 Maybe it would already work if you can find the correct value to pass.

Or maybe you have to call a different method such as seen here: https://gist.github.com/mitchjs/eabd9ecd63bcca0a8008436b1df5e6cb#file-main-cpp-L74 (I don't think what you're looking for is a static pin so this probably wouldn't help.)

I think what you are looking for would require more code because the library itself has no understanding of your physical keyboard and how it's wired up.

Unfortunately I'm not familiar enough with the BLE library to really help you.

SvOlli commented 4 years ago

Thanks.

Digging through the code, I thought just setting a different option in your first link would trigger that mechanism. But have the second link as an API option would be enough (or even better) for me. Since the keyboard can be configured via the USB serial interface. There I can set a static code, with a random number as default.

My problem is, that I'm totally new to Arduino. I've kept my distance, because I don't like the whole architecture of it with some software going through your code and extract header automatically. But I'm impressed about how fast you can get stuff done. So it's a bit like Visual Basic in the end of the 90s. ;-)

If you can provide my with a development snapshot of your library, then I will create a test implementation in my code and let you know, how it works.

T-vK commented 4 years ago

Just download the latest release and try to change the code as mentioned in my previous post. I currently don't have the time implement this or research how it could be done.

Maybe you can go here and ask for help if you can't get it to work: https://github.com/nkolban/esp32-snippets/issues

SvOlli commented 4 years ago

So after some tinkering, I figured out how authentication works: the computer generates a random 6-digit number and sends it to the keyboard to type in. This number gets requested by a method of an instance of the class BLESecurityCallbacks which was set by BLEDevice::setSecurityCallbacks. But for me there is no straight forward way to read the keyboard outside of the keyevent-submitting loop.

Nevertheless, what got me so far was mostly this implementation: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLETests/Arduino/security/BLE_client/BLE_client_passkey/BLE_client_passkey.ino with some slight modifications.

Edit: it's actually 6 digits on Linux and 8 digits on Windows 10.

nogueira commented 4 years ago

Great project, I love it. I'm not sure what would be required to enable pin authentication. But you might have to set a different authentication mode here: https://github.com/T-vK/ESP32-BLE-Keyboard/blob/master/BleKeyboard.cpp#L142 Maybe it would already work if you can find the correct value to pass.

Or maybe you have to call a different method such as seen here: https://gist.github.com/mitchjs/eabd9ecd63bcca0a8008436b1df5e6cb#file-main-cpp-L74 (I don't think what you're looking for is a static pin so this probably wouldn't help.)

I think what you are looking for would require more code because the library itself has no understanding of your physical keyboard and how it's wired up.

Unfortunately I'm not familiar enough with the BLE library to really help you.

I´m trying with this:

pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND); pSecurity->setStaticPIN(123456);

SvOlli commented 4 years ago

Doesn't work for me: BleKeyboard.cpp: In static member function 'static void BleKeyboard::taskServer(void*)': BleKeyboard.cpp:146:14: error: 'class BLESecurity' has no member named 'setStaticPIN' pSecurity->setStaticPIN(123456);

nogueira commented 4 years ago

Sorry, it didn´t work for Keyboard, only for Mouse and Gamepad. This error: 'class BLESecurity' has no member named 'setStaticPIN' can be solved with this:

Looks like arduino library has not been updated with this feature. You can copy/paste files from this library: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/BLESecurity.cpp https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/BLESecurity.h

SvOlli commented 4 years ago

@nogueira : Thank you, awesome tip! I managed to migrated that change into the code into BleKeyboard.cpp, as an optional parameter for begin(). So just running begin() will work as before, running begin(123456) will start with the PIN set to 123456. A merge request has been filed.

nogueira commented 4 years ago

@SvOlli the problem with this, as far as I know, is that you would have to type the password on the keyboard, not on the cell phone, as in BleMouse and BleGamepad. Did you see this?

SvOlli commented 4 years ago

@nogueira : Yes. The VICEboard is not intended as a sole keyboard, but as an additional one. It simply lacks most of the functions needed for standard operation, like the ALT-keys, or the backslash/pipe key. You can think of it as a special controller just mimicking a keyboard.

So since you must have another keyboard for proper operation, you can type in the PIN there. Interestingly it also works (at least on Linux) when you enter the code after the timeout. On a second try the PIN is then used. So it covers the requirements of my project. A different project might not work with this configuration, but when the need arises we might have already something better by then.

vcchm commented 4 years ago

Interesting discussion. I did the same on a different problem - connecting an ESP32 as a HID to either a Windows PC or an Android phone. The suggested modification only works with the PC : unless you remove the pincode, it never pairs with the Android Phone (Android 9, Samsung Galaxy note 9). Any idea what goes wrong ?

nogueira commented 4 years ago

It doesn´t work on Android Phone because it expected you to press the pincode on the ESP32. It does work with BleMouse and BleGamepad.

vcchm commented 4 years ago

No. the same code runs with my PC by entering the code on the PC, and not the ESP.

nogueira commented 4 years ago

I´m testing on Android and iPhone only and I can not enter the code.

vcchm commented 4 years ago

Not sure we are talking about the same thing. I copied my code hereafter. When running the code on ESP32, I can connect the device (and need to enter the code from my PC). When I try to connect from an Android, it fails...

pSecurity->setCapability(ESP_IO_CAP_NONE) says that my ESP has non keyboard nor screen and should not be asked anything. This is what the PC does, and so it connects perfectly. But with an Android (trying Galaxy Note or a Motorola phone) it fails.

BLESecurity pSecurity = new BLESecurity(); pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK); pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND);
pSecurity->setCapability(ESP_IO_CAP_NONE); if ((bleKeyboardInstance->hid_pinpoint!=NULL)&&(
bleKeyboardInstance->hid_pinpoint)) pSecurity->setStaticPIN(bleKeyboardInstance->hid_pinpoint); bleKeyboardInstance->hid->reportMap((uint8_t)_hidReportDescriptor, sizeof(_hidReportDescriptor)); bleKeyboardInstance->hid->startServices();

nogueira commented 4 years ago

I understand what you mean, I wasn´t able to make it work, this is why I changed to BleGamepad. For my application BleGamepad works.

vcchm commented 4 years ago

It was working perfectly without a pincode. But i never could make it work with a pincode : what i see is the android phone asking for a pincode, bit when i enter it the pairing fails. On the PC if I do the same the esp32 pairs perfectly.

In the CAP_NONE mode the device should not be waiting for anything. It should do what it does when i connect a bluetooth speaker - then the Android just pairs after you enter (on the android).the static code of the device...

GabbaGundolf commented 4 years ago

Since the change of the pin code does not seem to work so well, would it be easier to implement, just allow a new pairing for X seconds when starting the ESP32? Or only when calling a function. Then you could later implement that the function is only executed when a button is pressed. However, I don't find an approach right now. That would be the standard that many Bluetooth devices currently use. Or is that already possible and just don't understand it? Sorry for my bad google translator english.