iT邦幫忙

2025 iThome 鐵人賽

0
Software Development

以MicroPython在ESP32上實作Insulin Delivery Service系列 第 31

Day 31 - 不要一直重複要求配對阿!

  • 分享至 

  • xImage
  •  

咱們已經完成了 IDS Server,可是 GATT Client 不須配對即可對它進行讀寫,這表示讀寫的資料都沒有經過加密,是裸露在外,任人觀看,這實在是蠻危險的。

1. 保護 Characteristic 資料

為了解決這問題,咱們來稍微改變一下每個 Characteristic 的讀寫屬性。

class IddFeatures(ble.mixin.ReadMixin, ble.stack.Characteristic):
    def __init__(self, config: config.Config):
        ble.stack.Characteristic.__init__(self, 0x2B23, read=True, read_enc=True)

class BaseCP(ble.mixin.WriteMixin, ble.mixin.IndicateMixin, ble.stack.Characteristic):
    def __init__(self, uuid: int | str):
        ble.stack.Characteristic.__init__(
            self, uuid, write=True, write_enc=True, indicate=True
        )
  • 對於 Read 屬性,加上 read_enc;而具備 Write 屬性的,則加上 write_enc
  • 對於 read_encwrite_enc 的作用,請參考第 6 天的 封裝 BLE 相關功能 所附的原始碼。

MicroPython bluetooth 支援以下屬性:

_FLAG_BROADCAST = const(0x0001)
_FLAG_READ = const(0x0002)
_FLAG_WRITE_NO_RESPONSE = const(0x0004)
_FLAG_WRITE = const(0x0008)
_FLAG_NOTIFY = const(0x0010)
_FLAG_INDICATE = const(0x0020)
_FLAG_AUTHENTICATED_SIGNED_WRITE = const(0x0040)

_FLAG_AUX_WRITE = const(0x0100)
_FLAG_READ_ENCRYPTED = const(0x0200)
_FLAG_READ_AUTHENTICATED = const(0x0400)
_FLAG_READ_AUTHORIZED = const(0x0800)
_FLAG_WRITE_ENCRYPTED = const(0x1000)
_FLAG_WRITE_AUTHENTICATED = const(0x2000)
_FLAG_WRITE_AUTHORIZED = const(0x4000)

不過 MicroPython 目前還沒完整支援所有功能,比如 Authorized 便還不能正常運作。所以如果要讓 Characteristic 使用前必須配對,須使用 Encrypted 或 Authenticated。

2. 讓人困擾的重新配對

咱們為每個 Characteristic 加上配對要求了,但卻出現一個問題,那就是每當 IDS Server 與 GATT Client 斷線、重新連線後,要讀寫 Characteristics 前,須要再進行一次配對!!!

為什麼會這樣呢?這是因為咱們並沒有處理兩個事件:

_IRQ_GET_SECRET = const(29)
_IRQ_SET_SECRET = const(30)

在 MicroPython bluetooth 的流程裡,當 Characteristic 具有 EncryptedAuthenticatedAuthorized 屬性時:

  1. GATT Client 存取此 Characteristic
  2. 系統將檢查相關安全資訊是否存在,因此系統會送出 _IRQ_GET_SECRET 給 GATT Server 來取得先前的配對資訊
  3. 若 GATT Server 沒有給予,會重新配對,然後送出 _IRQ_SET_SECRET 來通知 GATT Server,GATT Server 可以儲存此資訊。這樣當下一次需要時,GATT Server 可以在中斷事件 _IRQ_GET_SECRET 中,將其傳回給系統。

3. 儲存配對資訊

為了儲存配對資訊,咱們在 ble/stack.py 增加以下變數:

_BLE_STORE_OBJ_TYPE_OUR_SEC = micropython.const(1)

_our_sec = bytearray(88)
_has_our_sec = False

然後處理中斷事件 _IRQ_GET_SECRET 來取得配對資訊:

def _on_get_secret(sec_type: int, index: int, key: bytes) -> bytes | None:
    if index != 0:
        return None

    if sec_type == _BLE_STORE_OBJ_TYPE_OUR_SEC:
        if _has_our_sec:
            return _our_sec

    return None
  • 咱們只儲存一筆配對資料,亦即只會儲存 index0 時的配對資料,所以當 index 不為 0 時,即返回 None,表示沒有此配對資訊。
  • 咱們只會儲存 _BLE_STORE_OBJ_TYPE_OUR_SEC 型態的配對資料,所以其餘的配對資訊都回覆 None

接下來是儲存配對資訊:

def _on_set_secret(sec_type: int, key: bytes, value: bytes):
    if sec_type == _BLE_STORE_OBJ_TYPE_OUR_SEC:
        global _has_our_sec

        if value:
            _our_sec[:] = value
            _has_our_sec = True
        else:
            _has_our_sec = False

    return True

如此,便不用每次斷線都必須重新配對了。


上一篇
Day 30 - 取回 History Data (2) - IDD RACP & IDD History Data
系列文
以MicroPython在ESP32上實作Insulin Delivery Service31
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言