0
votes

I am trying to connect 2 or more Raspberry Pi 3 boards over bluetooth. I am looking for options to set security while pairing. I am using Raspian-stretch(Latest one available). Bluez version available on RPI-3 is 5.23(as shown from bluetoothd -v command).

I am using headless version. I want the pairing to be secured(meaing there should be some kind of authentication i can set like PIN(4 digits) or Passkey(6 digits)) without the user logged into it. So if i have to connect my phone to the RPI, i dont have to login to RPI inorder to enter the PIN/Passkey. Then i would like to set up bluetooth PAN network so that i can communicate to between devices connected to PAN network.

I want pair the device/s using a PIN which is available in a file in the system or somewhere i can point it to. Say for example, pin.txt file in /temp/ directory or by running an agent to set the PIN. I read from other posts that bluez5.x got rid of the bluetooth-agent which was used in earlier version of bluez to do the things i could acomplish.

Agents in bluetoothctl such as DisplayOnly, KeyboardDisplay,NoInputNoOutput, DisplayYesNo,KeyboardOnly,on either sets a dynamic passkey which has to be entered manually or confirmation the passkey or just lets any device to pair and connect without any authntication in case of NoInputNoOutput.

Here is the link which i found of this forum stating that the agent is no longer available: https://www.raspberrypi.org/forums/viewtopic.php?t=133961 I also refers to some examples that shows pairing of devices but doesnt address what i am looking for.

There is no info available on manpage too. https://manpages.debian.org/stretch/bluez/bluetoothctl.1.en.html

Here is something i found about the commands but still not what i am looking for. https://wiki.archlinux.org/index.php/Bluetooth

I have also posted this Raspberry Pi forum. Here is the link: https://www.raspberrypi.org/forums/viewtopic.php?f=29&t=195090

Any help or suggestion to get around this or links to documnets i could refer to is appreciated.

Thanks in advance.

3

3 Answers

2
votes

After few days fiddling with BlueZ 5 this is what I've got. Using BlueZ 5.50 & Raspbian Stretch (Pi Zero W):

Start bluetoothd with --compat:

append to ExecStart line in /etc/systemd/system/dbus-org.bluez.service

or

in rc.local: sudo bluetoothd --compat &


The next steps are handled by code posted below but to clarify, hciconfig needs to be set to:

sudo hciconfig hci0 sspmode 0

Note #1: With 'sspmode 1' when pairing from Android you will get a prompt for PIN but afterwards Pi autogenerates 6-digit passkey and pairing failes.

Note #2: hciconfig hci0 can't be set with auth or encrypt those will actually register agent DisplayOnly (we will be creating agent in next step) as KeyboardDisplay (sudo btmon to verify) and pairing won't use predefined PIN. Not sure if there is a reason why DisplayOnly can't use auth, encrypt (might have something to do with them setting security mode 3).

Afterwards we will use bluetoothctl:

pi@raspberrypi:~ $ bluetoothctl
Agent registered
[bluetooth]# agent off
Agent unregistered
[bluetooth]# agent DisplayOnly
Agent registered
[bluetooth]# default-agent
Default agent request successful
[bluetooth]# discoverable on
Changing discoverable on succeeded
[CHG] Controller 11:22:33:44:55:66 Discoverable: yes
[bluetooth]# pairable on
Changing pairable on succeeded
[CHG] Controller 11:22:33:44:55:66 Pairable: yes

// Initiate pairing on remote device //

[NEW] Device AA:BB:CC:DD:EE:FF Android_phone

// Enter any PIN on Device AA:BB:CC:DD:EE:FF

Request PIN code

// retype your PIN below (on Pi)
[agent] Enter PIN code: <your PIN> 
[CHG] Device AA:BB:CC:DD:EE:FF Class: 0x005a020c
...
[CHG] Device AA:BB:CC:DD:EE:FF Paired: yes
[bluetooth]# quit

Note #3: Registering agent using pexpect (just a note if you try to run the code posted below) with BlueZ 5.43 (default version in Stretch) is hit and miss


Below is a Python 2.7 code that sets sspmode and handles pairing with pregenerated PIN:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function   # import print from python3: end=""
import time   
import re
import pexpect    # sudo apt-get install python-pexpect
import subprocess
import random
# !!! make sure bluetoothd runs in --compat mode before executing this script !!!
def pair_with_pin(start_time, pin, time_limit=60):  # int(time.time()), pin - \d{4}, time_limit - approximate pairing window time in seconds, it might take up to 2x (nested timeout conditions)
    "exectutes pairing with entered PIN on bluetooth adapter side"
    pairing_status = False
    try:
        subprocess.call(['sudo','hciconfig','hci0','sspmode', '0'])
        
        # bluetoothctl 
        child = pexpect.spawn('bluetoothctl')
        child.expect("#")
        child.sendline('agent off') # might be unnecessary
        child.expect("unregistered")
        
        child.sendline('agent DisplayOnly')
        child.expect("Agent registered")
        child.sendline('pairable on')
        child.expect("pairable on succeeded")
        child.sendline('discoverable on')
        child.expect("discoverable on succeeded")
        child.sendline('default-agent')
        print ('Please input PIN: ' + pin)              
        
        # waiting for Phone to send a pairing request... 
        child.expect('Enter PIN code:', timeout = time_limit )   # timeout <= PAIRING_TIME_LIMIT to keep some kind of logic
        while int(time.time()) < start_time + time_limit:   # allow multiple pairing attempts during pairing window            
            child.sendline(pin)
            i = child.expect(['Paired: yes', 'Enter PIN code:'], timeout = time_limit)
            if i == 0: # found 'Paired: yes' == successful pairing
                trust_mac = 'trust ' + re.search(r'(?:[0-9a-fA-F]:?){12}.+$', child.before).group(0)    # extract MAC from last line, one with 'Paired: Yes'
                child.sendline(trust_mac)   # optionally add device to trusted
                child.expect('trust succeeded', timeout = 10)                
                pairing_status = True
                break
            #else: # i == 1
                # print('wrong PIN, retrying if time will allow') 
    except pexpect.EOF:
        print ('!!!!!!!! EOF')
    except pexpect.TIMEOUT:
        print ('!!!!!!!! TIMEOUT')
        
    # hide Pi's bluetooth for security reasons
    child.sendline('pairable off')
    child.expect("pairable off succeeded")
    child.sendline('discoverable off')
    child.expect("discoverable off succeeded")    
    child.close()
    
    return pairing_status

#main program body
PAIRING_TIME_LIMIT = 60
BT_PIN = random.randint(1000,10000)    # generate random 4-digit PIN 1000..9999

status = pair_with_pin(int(time.time()), str(BT_PIN), PAIRING_TIME_LIMIT)
if status == True:
    print('Pairing successful')

Final note: After successful pairing it might be posibble to turn encryption on, try:

hciconfig hci0 encrypt

or

hcitool enc $BDADD

1
votes

I was able to get this working with the test scripts.

For anyone who is interested to know the details, please refer to my post on Raspberry Pi forum. Below is the link.

https://www.raspberrypi.org/forums/viewtopic.php?f=29&t=195090&p=1221455#p1221455

-1
votes

First you have to configurate sspmode 0, for pin request: hciconfig hci0 sspmode 0

And using bt-agent aplicattion (you can run as deamon too):

bt-agent -c NoInputNoOutput -p /root/bluethooth.cfg

Edit the file configuration, you can put tha mac address and the pin: For example: XX:XX:XX:XX:XX:XX 1234

Or if you want a pin to all the device the same pin code, for example 1234, edit the file like this: * 1234

This work for me!