2.3 門禁設備與手機藍牙對接協議
1 通訊方式簡介
1.1 拓撲結構
星形拓撲結構:門口機作為主設備,APP 為從設備。主設備管理連接,主設備只能連接一個從設備;一個從設備只能連接一個主設備。
1.2 設備狀態
藍牙門口機作為從設備,共有以下三種狀態:
待機狀態(standy) | 設備沒有傳輸和發送數據,并且沒有連接到任何設備 |
廣播狀態(advertiser) | 周期性廣播狀態,等待被連接 |
從設備(slave) | 作為從設備連接其他設備 |
1.2.1 狀態以及連接過程
藍牙門口機不用連接就可以廣播數據(門口機名稱和其他信息),手機 APP 掃描廣播設備,藍牙門口機接受到掃描后會發送一個掃描回應(掃描回應數據就是廣播數據),APP 接收到掃描回應后發起連接,如果藍牙門口機同意該連接請求,那么門口機和手機都會進入已連接狀態,發起連接的設備手機變為主設備,接受連接請求的設備門口機變為從設備。
1.3 藍牙門口機的連接參數
1.3.1 藍牙門口機的廣播事件
廣播包發送是單向的,不需要任何的連接。廣播包里可以包含特定的數據定義,最大 31 字節。
廣播間隔:兩次廣播事件之間的最小的時間間隔,一般取值范圍在 20ms~10.24s 之間,鏈路層會在每次廣播時間期間產生一個隨機廣播延時時間加在廣播時間里,這樣來避免多設備之間的數據碰撞。
1.3.2 藍牙連接參數
連接參數如下:
參數 | 說明 |
通道映射 | 連接使用的頻道 |
調頻增量 | 一個 5~16 之間的隨機 |
連接間隔 | 1.25ms 的倍數,7.5ms~4s |
監督超時 | 10ms 的倍數,100ms~32s |
從機潛伏 | 0~499 |
1.3.3 BLE 連接事件
所有的通信都發生在兩個設備的連接事件期間,連接事件周期的發生,按照連接參數指定的間隔聯系,每個連接時間期間,主設備先發送,從設備會在 150us 之后做出回應,即使一個連接事件發生,但相互沒有數據發送,兩個設備仍然認為對方存在并保持活躍的連接。
潛伏值:從設備如果沒有數據發送,允許跳過連接時間,潛伏值是允許跳過的最大的連接次數。從機不潛伏,在每個連接事件期間回應一個“空包”,除非有數據發送;從機潛伏使能, 從機可以跳過n 個連接時間,除非有數據發送才被喚醒。
1.3.4 終止連接
Master 和slave 都可以主動斷開連接。
1.4 GATT 的client/service 架構
1.4.1 GATT 層
GATT 是 BLE 協議棧的通用屬性配置文件層,規定了配置文件(profile)的結構。
1.4.2 GATT 的 Profile 層次結構
Profile 通常由一個或者多個服務(service)組成。每個 service 包含一個或多個特征值characteristic 特征值。每個具體的 characteristic 特征值才是 BLE 通信的主體,characteristic 特征值可以理解為標簽,通過這個標簽可以獲取和寫入想要的內容。
1.4.3 characteristic 屬性
characteristic 的屬性有以下幾種:read,constant,write,write_no_response,notify,indicate, authenticated_read,authenticated_write,reliable_write。
2 通訊協議
2.1 手機app 與藍牙門口機的交互過程
一旦建立連接后,門口機不會主動斷開連接,需由 APP 端主動斷開。
2.2 通訊參數設置
BLE 4.0 協議為低功耗藍牙規范,但暫時不考慮功耗問題,為了使藍牙能夠快速響應并處理傳輸數據,將連接間隔事件時間設置為接近最短時間,將掃描和廣播的頻率提高但是連接的兩個設備都會以高能耗運行。
2.2.1 藍牙連接參數
參數 | 說明(后期根據實際測試情況調整) |
通道映射 | 7: Advertise on all channels |
調頻增量 | 默認 |
有連接廣播間隔 | Min: 20ms (0.625ms*0x20) Max: 20ms (0.625ms*0x20) |
無連接廣播間隔 | Min: 100ms (0.625ms*0xa0) Max: 100ms (0.625ms*0xa0) |
掃描間隔 | APP 根據情況自定義 |
掃描窗口 | APP 根據情況自定義 |
連接間隔 | Min: 7.5ms (1.25ms*6) Max: 12.5ms (1.25ms*10) |
監督超時 | 100ms |
從機潛伏 | 0 |
2.2.2 廣播數據格式
藍牙廣播包數據為一串最大長度不超過 31 字節的數據,標準格式如下:
為了APP 能夠找到設備,廣播數據中加入了藍牙設備名稱、2 字節的incomplete ServiceUUID。
具體格式如下(各字段含義見 2.2.3 節廣播數據格式說明):
字段含義 | ASCII 碼值 | 字節含義 | 字節序列索引 |
藍牙廣播包頭 | 0x02 | 長度(字節) | 0 |
0x01 | Flags | 1 | |
0x06 | 廣播標志頭 | 2 | |
藍牙設備名稱 | 0x11 | 長度(字節) | 3 |
0x09 | Complete Local Name | 4 | |
0x53 | ‘S’ | 5 | |
0x52 | ‘R’ | 6 | |
0x45 | ‘E’ | 7 | |
0x31 | ‘1’ | 8 | |
0x30 | ‘0’ | 9 | |
0x30 | ‘0’ | 10 | |
0x31 | ‘1’ | 11 | |
0x30 | ‘0’ | 12 | |
0x30 | ‘0’ | 13 | |
0x30 | ‘0’ | 14 | |
0x31 | ‘1’ | 15 | |
0x30 | ‘0’ | 16 | |
0x30 | ‘0’ | 17 | |
0x30 | ‘0’ | 18 | |
0x30 | ‘0’ | 19 | |
0x31 | ‘1’ | 20 | |
服務ID | 0x03 | 長度(字節) | 21 |
0x02 | Incomplete List of 16-bit Service Class UUIDs | 22 | |
0xff | UUID | 23 | |
0xfa | 24 | ||
自定義數據 | 0x05 | 長度(字節) | 25 |
0xff | Manufacturer Specific Data | 26 | |
.. | 廠商自定義數據: 4 字節隨機數。 每次新的連接前都會更新隨機數。 | 27 | |
.. | 28 | ||
.. | 29 | ||
.. | 30 | ||
廣播包總大小: | 31 字節 |
2.2.3 廣播數據格式說明
1. 具體藍牙相關標志的細節請參考:https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
2. 藍牙設備名稱
規則(一共 16 字節長度):
門口機模式:
SRE+期號(1字節)+樓棟號(3字節)+單元號(4字節)+編號(2字節)+層號(3字節)
編號:主門口機使用 00 表示、從門口機從 01 開始(01,02 加 1 遞增)
層號:分正樓層和負樓層(第一個字符為 0 表示正樓層,為 1 表示負樓層)
例如默認的1 期1 幢1 單元,放置在地上一層的主門口機的廣播名稱為:SRE1001000100001,放置在地下一層則為:SRE1001000100101
圍墻機模式:
SRE+期號(1 字節)+0000000+編號(2 字節)+層號(3 字節)
圍墻機模式下的樓棟號、單元號使用 0000000 代替,剩下的期號、編號、層號規則與門口機模式一致。
3. 服務 ID
廣播中的 ID 是不完整的 16bit service UUID。
4. 自定義數據
廠商自定義數據,此處存放的是由時間加密因子計算出的 4 字節隨機數,用于與雙方約定的 16 字節固定密鑰生成隨機密鑰,每次鏈接斷開后都會更新 4 字節隨機數。
2.2.4 服務和特征值說明
藍牙門口機作為從機(服務器),手機作為主機(客戶端)。藍牙門口機新增一個服務(service),在此服務中添加characteristic 特征值,作用及命名如下。
特征值名稱 | 長度 | 屬性 | 作用 |
發送指令 (send command) | n | write | 手機 APP 將要發送的指令報文分包寫入此特征值, 每包小于等于下文“傳輸協議”中約定的字節數。 |
返回指令 (return command) | n | read | 門口機將返回操作的內容以及狀態報文寫入此特征值,并通過寫的方式發送給手機 APP。 |
2.2.5 設備藍牙的UUID
名稱 | 不完整值 | 完整值 |
Service UUID | 0xFFFA | f6ecfffa-bda1-46ec-a43a-6d86de88561d |
Write Characteristics UUID | 0xFFA7 | af20ffa7-2518-4998-9af7-af42540731b3 |
Read Characteristics UUID | 0xFFA8 | af20ffa8-2518-4998-9af7-af42540731b4 |
注:上表中的 read、write 均是從設備端藍牙芯片來看的。
2.3 傳輸協議
2.3.1 APP->門口機
幀頭 0X24 1 BYTE | 返回結果類型 1 BYTE | 權限有效長度 1 BYTE | 權限內容 n BYTE | 累加和 checksum 1 BYTE |
說明:
1. 返回結果類型:
0x00:表示門口機收到 APP 開門指令后,將會進行數據格式+權限內容校驗,并將校驗之后的結果返回給手機 APP(校驗通過說明藍牙開門成功)。
0x01:表示門口機收到 APP 開門指令后,將只校驗數據格式,并不關心權限內容,如果數據格式正確則返回開門成功消息給手機 APP。
2. 權限有效長度:
加密后的權限內容長度。
3. 權限內容:
標紅色的權限內容字段為 AES 加密目標,用于存放開門卡號等信息。此處 nByte 表示加密后的數據長度。n 取值:0~n,暫定最大 32 字節,如果超過 32 字節則需要雙方重新約定。如果加密前權限長度小于等于 15 字節,則此處加密后的長度為 16 字節;如果是大于 15 字節,小于等于 31 字節,則此處加密后的長度為 32 字節。因此最大的權限長度為 31 字節。
如果 APP 端傳遞的不是開門卡號,則需要另行商定。
4. 累加和:
校驗位采用累加和校驗,從幀頭開始到權限內容最后一個字節的累加和對 256 取余,計算的是加密之后的累積和。
2.3.2 門口機->APP
幀頭 0X24 1 BYTE | 保留 2 BYTE | 開門結果反饋 1 BYTE | 累加和 checksum 1 BYTE |
說明:
返回給 APP 的開門響應數據不會被加密。
開門結果反饋的狀態碼列表如下:
返回碼 | 中文描述 | 英文描述 |
0x01 | 校驗錯誤 | CS_ERROR |
0x02 | 幀格式不正確 | FRAMEFORMAT_ERROR |
0x03 | 認證失敗 | NO_PERMISSION_ERROR |
成功信息 | ||
0x00 | 成功 | OK |
2.4 加密
2.4.1 密鑰說明
為確保安全性,需要保證每個對接項目的 APP 不可相互開門,此次定制的門口機程序,只能和本地門口機程序對應的 APP 通訊開門。
因此將 16 字節密鑰按照如下約定生成:
定制單編號:如:DZP20200117037
長度為 14 字節,后面填 0 擴充至 16 字節:DZP2020011703700
轉換為 ASCII 碼:
N[16]={0x44, 0x5A, 0x50, 0x32, 0x30, 0x32, 0x30, 0x30, 0x31, 0x31, 0x37, 0x30, 0x33, 0x37, 0x30, 0x30};
在開發APP 前需獲取本次對接時的定制單編號!
2.4.2 通信幀加密
采用 128 位密鑰的 AES 加密 CBC 模式(初始化向量:“1234567890abcdef”,填充模式為zeropadding),只對協議格式里面DATA 數據區加密,密鑰的生成如下:
1.設備存儲一個固定密鑰(初始密鑰):
N[16]={0x44, 0x5A, 0x50, 0x32, 0x30, 0x32, 0x30, 0x30, 0x31, 0x31, 0x37, 0x30, 0x33, 0x37, 0x30, 0x30};
2.生成一個 4 字節的隨機數組:
R[4]={0x45,0x18,0x9F,0x5C};
3.如上圖所示,按照間隔 4 的大小,將 1、5、9、13 字節固定密鑰與隨機數組 1 字節進行與操作,得到新的 1、5、9、13 字節動態密鑰;其他字節也按照上圖所示進行加密,最終得到用于實際 AES128 加解密處理的 16 字節動態密鑰。
說明:“加”操作超出 0xff 取余;隨機數在每次斷開連接后會重新生成,所以每次操作的密鑰都不相同。
舉例:
固定密鑰:
N[16]={0x44, 0x5A, 0x50, 0x32, 0x30, 0x32, 0x30, 0x30, 0x31, 0x31, 0x37, 0x30, 0x33, 0x37, 0x30, 0x30};
隨機數:
{0x45,0x18,0x9F,0x5C};
則得到的新的密鑰為:
{0x44, 0x72, 0xDF, 0x6E, 0x00, 0x4A, 0xBF, 0x6C, 0x01, 0x49, 0xBF, 0x6C, 0x01, 0x4F, 0xBF, 0x6C}
轉換代碼 :
for(i=0; i<4; i++) {
szDynamicKey[4*i] = gDefaultAesKey[4*i]&gRandNum[0];
szDynamicKey[4*i+1] = gDefaultAesKey[4*i+1] + gRandNum[1];
szDynamicKey[4*i+2] = gDefaultAesKey[4*i+2] | gRandNum[2];
szDynamicKey[4*i+3] = gDefaultAesKey[4*i+3] ^ gRandNum[3];
}
2.4.3 密鑰一致性
本章節通過舉例方式列出幾種待加密數據的加密結果,供三方 APP 開發時參考,確保雙方使用”相同待加密數據、相同固定密鑰、相同 4 字節隨機數”加密得到的密文一致。
數 據長度 | 待加密數據 | 固定密鑰 | 4 字節隨機數 | 隨機密鑰 | 加密后密文 (16 進制 byte array) |
14 | "12345601010702" | DZP2020011703700 | 0x45, 0x18, 0x9F, 0x5C | '0x44', '0x72', '0xdf', '0x6e', '0x0', '0x4a', '0xbf', '0x6c', '0x1', '0x49', '0xbf', '0x6c', '0x1', '0x4f', '0xbf', '0x6c' | '0xf7', '0x2f', '0x0', '0xed', '0xfc', '0x2a', '0x83', '0xcd', '0xc9', '0x6c', '0x5', '0xbc', '0x95', '0x64', '0xa6', '0x75' |
16 | "1234567812345678" | DZP2020011703700 | 0x45, 0x18, 0x9F, 0x5C | '0x44', '0x72', '0xdf', '0x6e', '0x0', '0x4a', '0xbf', '0x6c', '0x1', '0x49', '0xbf', '0x6c', '0x1', '0x4f', '0xbf', '0x6c' | '0xce', '0x53', '0x38', '0x7f', '0x11', '0x5d', '0xf4', '0xaa', '0xed', '0x9d', '0x1c', '0xe8', '0x74', '0x5d', '0x39', '0xe1', '0xeb', '0xdc', '0x81', '0x62', '0x35', '0x38', '0x78', '0xee', '0x34', '0x11', '0xd0', '0xfa', '0xcd', '0x39', '0x98', '0xa' |
31 | "1234567812345678123456781234567" | DZP2020011703700 | 0x45, 0x18, 0x9F, 0x5C | '0x44', '0x72', '0xdf', '0x6e', '0x0', '0x4a', '0xbf', '0x6c', '0x1', '0x49', '0xbf', '0x6c', '0x1', '0x4f', '0xbf', '0x6c' | '0xce', '0x53', '0x38', '0x7f', '0x11', '0x5d', '0xf4', '0xaa', '0xed', '0x9d', '0x1c', '0xe8', '0x74', '0x5d', '0x39', '0xe1', '0x45', '0x3b', '0x2', '0xc0', '0x5a', '0x71', '0x35', '0x7a', '0xfa', '0x21', '0xf5', '0x14', '0xde', '0x43', '0x6f', '0xf9' |