Skip to content

Commit a429760

Browse files
author
unknownconstant
authored
Merge pull request #17 from unknownconstant/pairing-code
Pairing code & IOCaps set via implementation of callbacks
2 parents 83d11ed + 6b08d21 commit a429760

File tree

10 files changed

+146
-5
lines changed

10 files changed

+146
-5
lines changed

examples/Peripheral/EncryptedBatteryMonitor/EncryptedBatteryMonitor.ino

+26-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#include <ArduinoBLE.h>
1919

2020

21-
#define PAIR_BUTTON D3 // button for pairing
21+
#define PAIR_BUTTON 3 // button for pairing
2222
#define PAIR_LED 24 // LED used to signal pairing
2323
#define PAIR_LED_ON LOW // Blue LED on Nano BLE has inverted logic
2424
#define PAIR_INTERVAL 30000 // interval for pairing after button press in ms
@@ -42,6 +42,7 @@ int oldBatteryLevel = 0; // last battery level reading from analog input
4242
unsigned long previousMillis = 0; // last time the battery level was checked, in ms
4343
unsigned long pairingStarted = 0; // pairing start time when button is pressed
4444
bool wasConnected = 0;
45+
bool acceptOrReject = true;
4546

4647
void setup() {
4748
Serial.begin(9600); // initialize serial communication
@@ -53,6 +54,30 @@ void setup() {
5354

5455

5556
Serial.println("Serial connected");
57+
58+
// Callback function with confirmation code when new device is pairing.
59+
BLE.setDisplayCode([](uint32_t confirmCode){
60+
Serial.println("New device pairing request.");
61+
Serial.print("Confirm code matches pairing device: ");
62+
char code[6];
63+
sprintf(code, "%06d", confirmCode);
64+
Serial.println(code);
65+
});
66+
67+
// Callback to allow accepting or rejecting pairing
68+
BLE.setBinaryConfirmPairing([&acceptOrReject](){
69+
Serial.print("Should we confirm pairing? ");
70+
delay(5000);
71+
if(acceptOrReject){
72+
acceptOrReject = false;
73+
Serial.println("yes");
74+
return true;
75+
}else{
76+
acceptOrReject = true;
77+
Serial.println("no");
78+
return false;
79+
}
80+
});
5681

5782
// IRKs are keys that identify the true owner of a random mac address.
5883
// Add IRKs of devices you are bonded with.

src/local/BLELocalDevice.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,12 @@ void BLELocalDevice::setStoreLTK(int (*storeLTK)(uint8_t*, uint8_t*)){
434434
void BLELocalDevice::setStoreIRK(int (*storeIRK)(uint8_t*, uint8_t*)){
435435
HCI._storeIRK = storeIRK;
436436
}
437+
void BLELocalDevice::setDisplayCode(void (*displayCode)(uint32_t confirmationCode)){
438+
HCI._displayCode = displayCode;
439+
}
440+
void BLELocalDevice::setBinaryConfirmPairing(bool (*binaryConfirmPairing)()){
441+
HCI._binaryConfirmPairing = binaryConfirmPairing;
442+
}
437443

438444
void BLELocalDevice::debug(Stream& stream)
439445
{

src/local/BLELocalDevice.h

+3
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ class BLELocalDevice {
104104
// address - The mac address needing its LTK
105105
// LTK - 16 octet LTK for the mac address
106106
virtual void setGetLTK(int (*getLTK)(uint8_t* address, uint8_t* LTK));
107+
108+
virtual void setDisplayCode(void (*displayCode)(uint32_t confirmationCode));
109+
virtual void setBinaryConfirmPairing(bool (*binaryConfirmPairing)());
107110
uint8_t BDaddress[6];
108111

109112
protected:

src/utility/ATT.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@
8181
#define ATT_ECODE_UNSUPP_GRP_TYPE 0x10
8282
#define ATT_ECODE_INSUFF_RESOURCES 0x11
8383

84+
// #define _BLE_TRACE_
85+
8486
ATTClass::ATTClass() :
8587
_maxMtu(23),
8688
_timeout(5000),

src/utility/HCI.cpp

+14-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#include "bitDescriptions.h"
2727
// #define _BLE_TRACE_
2828

29-
//#define _BLE_TRACE_
3029

3130
#define HCI_COMMAND_PKT 0x01
3231
#define HCI_ACLDATA_PKT 0x02
@@ -1258,6 +1257,7 @@ void HCIClass::handleEventPkt(uint8_t /*plen*/, uint8_t pdata[])
12581257
uint8_t publicKey[64];
12591258
} pairingPublicKey = {CONNECTION_PAIRING_PUBLIC_KEY,0};
12601259
memcpy(pairingPublicKey.publicKey,evtReadLocalP256Complete->localPublicKey,64);
1260+
memcpy(localPublicKeyBuffer, evtReadLocalP256Complete->localPublicKey,64);
12611261

12621262
// Send the local public key to the remote
12631263
uint16_t connectionHandle = ATT.getPeerEncrptingConnectionHandle();
@@ -1456,6 +1456,19 @@ int HCIClass::storeLTK(uint8_t* address, uint8_t* LTK){
14561456
return 0;
14571457
}
14581458
}
1459+
uint8_t HCIClass::localIOCap(){
1460+
if(_displayCode!=0){
1461+
/// We have a display
1462+
if(_binaryConfirmPairing!=0){
1463+
return IOCAP_DISPLAY_YES_NO;
1464+
}else{
1465+
return IOCAP_DISPLAY_ONLY;
1466+
}
1467+
}else{
1468+
// We have no display
1469+
return IOCAP_NO_INPUT_NO_OUTPUT;
1470+
}
1471+
}
14591472

14601473
/// Stub function to generate parameters for local authreq
14611474
AuthReq HCIClass::localAuthreq(){

src/utility/HCI.h

+4
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ class HCIClass {
9797
// Generate a 64 bit random number
9898
virtual int leRand(uint8_t rand[]);
9999
virtual AuthReq localAuthreq();
100+
virtual uint8_t localIOCap();
100101

101102
virtual int saveNewAddress(uint8_t addressType, uint8_t* address, uint8_t* peerIrk, uint8_t* remoteIrk);
102103
virtual int leAddResolvingAddress(uint8_t addressType, uint8_t* address, uint8_t* peerIrk, uint8_t* remoteIrk);
@@ -119,6 +120,7 @@ class HCIClass {
119120
// TODO: Send command be private again & use ATT implementation of send command within ATT.
120121
virtual int sendCommand(uint16_t opcode, uint8_t plen = 0, void* parameters = NULL);
121122
uint8_t remotePublicKeyBuffer[64];
123+
uint8_t localPublicKeyBuffer[64];
122124
uint8_t remoteDHKeyCheckBuffer[16];
123125
uint8_t Na[16];
124126
uint8_t Nb[16];
@@ -132,6 +134,8 @@ class HCIClass {
132134
int (*_getIRKs)(uint8_t* nIRKs,uint8_t** BADDR_type, uint8_t*** BADDRs, uint8_t*** IRKs) = 0;
133135
int (*_storeLTK)(uint8_t*, uint8_t*) = 0;
134136
int (*_getLTK)(uint8_t*, uint8_t*) = 0;
137+
void (*_displayCode)(uint32_t confirmationCode) = 0;
138+
bool (*_binaryConfirmPairing)() = 0;
135139

136140
private:
137141

src/utility/L2CAPSignaling.cpp

+52-2
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ void L2CAPSignalingClass::handleSecurityData(uint16_t connectionHandle, uint8_t
180180
uint8_t maxEncSize;
181181
uint8_t initiatorKeyDistribution;
182182
uint8_t responderKeyDistribution;
183-
} response = { CONNECTION_PAIRING_RESPONSE, LOCAL_IOCAP, 0, HCI.localAuthreq().getOctet(), 0x10, responseKD.getOctet(), responseKD.getOctet()};
183+
} response = { CONNECTION_PAIRING_RESPONSE, HCI.localIOCap(), 0, HCI.localAuthreq().getOctet(), 0x10, responseKD.getOctet(), responseKD.getOctet()};
184184

185185
HCI.sendAclPkt(connectionHandle, SECURITY_CID, sizeof(response), &response);
186186

@@ -209,6 +209,55 @@ void L2CAPSignalingClass::handleSecurityData(uint16_t connectionHandle, uint8_t
209209
for(int i=0; i< 16; i++) response.Nb[15-i] = HCI.Nb[i];
210210

211211
HCI.sendAclPkt(connectionHandle, SECURITY_CID, sizeof(response), &response);
212+
213+
// We now have all needed for compare value
214+
uint8_t g2Result[4];
215+
uint8_t U[32];
216+
uint8_t V[32];
217+
218+
for(int i=0; i<32; i++){
219+
U[31-i] = HCI.remotePublicKeyBuffer[i];
220+
V[31-i] = HCI.localPublicKeyBuffer[i];
221+
}
222+
223+
btct.g2(U,V,HCI.Na,HCI.Nb, g2Result);
224+
uint32_t result = 0;
225+
for(int i=0; i<4; i++) result += g2Result[3-i] << 8*i;
226+
227+
#ifdef _BLE_TRACE_
228+
Serial.print("U : ");
229+
btct.printBytes(U,32);
230+
Serial.print("V : ");
231+
btct.printBytes(V,32);
232+
Serial.print("X : ");
233+
btct.printBytes(X,16);
234+
Serial.print("Y : ");
235+
btct.printBytes(Y,16);
236+
Serial.print("g2res : ");
237+
btct.printBytes(g2Result,4);
238+
Serial.print("Result : ");
239+
Serial.println(result);
240+
#endif
241+
242+
if(HCI._displayCode!=0){
243+
HCI._displayCode(result%1000000);
244+
}
245+
if(HCI._binaryConfirmPairing!=0){
246+
if(!HCI._binaryConfirmPairing()){
247+
#ifdef _BLE_TRACE_
248+
Serial.println("User rejection");
249+
#endif
250+
uint8_t rejection[2];
251+
rejection[0] = CONNECTION_PAIRING_FAILED;
252+
rejection[1] = 0x0C; // Numeric comparison failed
253+
HCI.sendAclPkt(connectionHandle, SECURITY_CID, 2, rejection);
254+
ATT.setPeerEncryption(connectionHandle, PEER_ENCRYPTION::NO_ENCRYPTION);
255+
}else{
256+
#ifdef _BLE_TRACE_
257+
Serial.println("User did confirm");
258+
#endif
259+
}
260+
}
212261
}
213262
else if (code == CONNECTION_PAIRING_RESPONSE)
214263
{
@@ -224,6 +273,7 @@ void L2CAPSignalingClass::handleSecurityData(uint16_t connectionHandle, uint8_t
224273
Serial.print("Pairing failed with code: 0x");
225274
Serial.println(pairingFailed->reason,HEX);
226275
#endif
276+
ATT.setPeerEncryption(connectionHandle, PEER_ENCRYPTION::NO_ENCRYPTION);
227277
}
228278
else if (code == CONNECTION_IDENTITY_INFORMATION){
229279
struct __attribute__ ((packed)) IdentityInformation {
@@ -338,7 +388,7 @@ void L2CAPSignalingClass::smCalculateLTKandConfirm(uint16_t handle, uint8_t expe
338388
uint8_t Eb[16];
339389
uint8_t R[16];
340390
uint8_t MasterIOCap[3];
341-
uint8_t SlaveIOCap[3] = {HCI.localAuthreq().getOctet(), 0x0, LOCAL_IOCAP};
391+
uint8_t SlaveIOCap[3] = {HCI.localAuthreq().getOctet(), 0x0, HCI.localIOCap()};
342392

343393
ATT.getPeerIOCap(handle, MasterIOCap);
344394
for(int i=0; i<16; i++) R[i] = 0;

src/utility/L2CAPSignaling.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949

5050

5151
#define LOCAL_AUTHREQ 0b00101101
52-
#define LOCAL_IOCAP IOCAP_NO_INPUT_NO_OUTPUT // will use JustWorks pairing
52+
// #define LOCAL_IOCAP IOCAP_DISPLAY_ONLY // will use JustWorks pairing
5353

5454
class L2CAPSignalingClass {
5555
public:

src/utility/btct.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,42 @@ void BluetoothCryptoToolbox::testAh()
150150
printBytes(ourResult, 3);
151151
}
152152

153+
int BluetoothCryptoToolbox::g2(uint8_t U[], uint8_t V[], uint8_t X[], uint8_t Y[], uint8_t out[4])
154+
{
155+
struct __attribute__ ((packed)) CmacInput {
156+
uint8_t U[32];
157+
uint8_t V[32];
158+
uint8_t Y[16];
159+
} cmacInput= {0,0,0};
160+
memcpy(cmacInput.U,U,32);
161+
memcpy(cmacInput.V,V,32);
162+
memcpy(cmacInput.Y,Y,16);
163+
uint8_t intermediate[16];
164+
AES_CMAC(X,(uint8_t*)&cmacInput,sizeof(CmacInput),intermediate);
165+
memcpy(out,&intermediate[12],4);
166+
return 1;
167+
}
168+
void BluetoothCryptoToolbox::testg2(){
169+
uint8_t U[32] = {0x20,0xb0,0x03,0xd2,0xf2,0x97,0xbe,0x2c,0x5e,0x2c,0x83,0xa7,0xe9,0xf9,0xa5,0xb9,0xef,0xf4,0x91,0x11,0xac,0xf4,0xfd,0xdb,0xcc,0x03,0x01,0x48,0x0e,0x35,0x9d,0xe6};
170+
uint8_t V[32] = {0x55,0x18,0x8b,0x3d,0x32,0xf6,0xbb,0x9a,0x90,0x0a,0xfc,0xfb,0xee,0xd4,0xe7,0x2a,0x59,0xcb,0x9a,0xc2,0xf1,0x9d,0x7c,0xfb,0x6b,0x4f,0xdd,0x49,0xf4,0x7f,0xc5,0xfd};
171+
uint8_t X[16] = {0xd5,0xcb,0x84,0x54,0xd1,0x77,0x73,0x3e,0xff,0xff,0xb2,0xec,0x71,0x2b,0xae,0xab};
172+
uint8_t Y[16] = {0xa6,0xe8,0xe7,0xcc,0x25,0xa7,0x5f,0x6e,0x21,0x65,0x83,0xf7,0xff,0x3d,0xc4,0xcf};
173+
uint8_t AES[16] = {0x15,0x36,0xd1,0x8d,0xe3,0xd2,0x0d,0xf9,0x9b,0x70,0x44,0xc1,0x2f,0x9e,0xd5,0xba};
174+
uint8_t out[4];
175+
176+
177+
uint32_t expected = 0;
178+
g2(U,V,X,Y,out);
179+
uint32_t result = 0;
180+
for(int i=0; i<4; i++) result += out[i] << 8*i;
181+
182+
Serial.print("Expected : ");
183+
Serial.println(expected);
184+
Serial.print("Result : ");
185+
Serial.println(result);
186+
Serial.println();
187+
188+
}
153189

154190
void BluetoothCryptoToolbox::AES_CMAC ( unsigned char *key, unsigned char *input, int length,
155191
unsigned char *mac )

src/utility/btct.h

+2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ class BluetoothCryptoToolbox{
1313
int f5(uint8_t DHKey[],uint8_t N_master[], uint8_t N_slave[],
1414
uint8_t BD_ADDR_master[], uint8_t BD_ADDR_slave[], uint8_t MacKey[], uint8_t LTK[]);
1515
int f6(uint8_t W[], uint8_t N1[],uint8_t N2[],uint8_t R[], uint8_t IOCap[], uint8_t A1[], uint8_t A2[], uint8_t Ex[]);
16+
int g2(uint8_t U[], uint8_t V[], uint8_t X[], uint8_t Y[], uint8_t out[4]);
1617
int ah(uint8_t k[16], uint8_t r[3], uint8_t result[3]);
1718
void test();
1819
void testF5();
1920
void testF6();
2021
void testAh();
22+
void testg2();
2123
private:
2224
int AES_128(uint8_t key[], uint8_t data_in[], uint8_t data_out[]);
2325
void leftshift_onebit(unsigned char *input,unsigned char *output);

0 commit comments

Comments
 (0)