11.13. การจับคู่และการผูกพัน

ทุกอย่างที่กล่าวถึงมาจนถึงตอนนี้จะส่งข้อมูลผ่านคลื่นวิทยุแบบเปิดเผย ผู้ใดก็ตามที่มีแล็ปท็อปที่รองรับ BLE อยู่ในห้องเดียวกันสามารถดักฟังบนช่องโฆษณา ติดตามลำดับการกระโดดของการเชื่อมต่อแบบเปิด และอ่านทุกการอ่าน การเขียน และการแจ้งเตือนที่ผ่านไปได้ สำหรับข้อมูล sensor สาธารณะส่วนใหญ่ (ระดับแบตเตอรี่ อุณหภูมิแวดล้อม) นั่นก็ไม่เป็นปัญหา แต่สำหรับสิ่งที่ทั้งสองฝ่ายต้องการเก็บเป็นความลับ -- รีจิสเตอร์ควบคุมที่เปิดใช้รีเลย์ รหัสผ่าน ข้อมูลที่ไม่ควรเผยแพร่อย่างกว้างขวาง -- ลิงก์จำเป็นต้องเข้ารหัส และในอุดมคติกล้องต้องรู้ว่ากำลังคุยกับ ใคร

BLE รองรับทั้งสองอย่างผ่าน การจับคู่ และ การผูกพัน

11.13.1. การจับคู่ การผูกพัน การเข้ารหัส

สามแนวคิดที่เกี่ยวข้องกันอย่างใกล้ชิด:

  • การเข้ารหัส คือเป้าหมายหลัก เมื่อลิงก์ถูกเข้ารหัสแล้ว ทุกแพ็กเก็ตบนช่องข้อมูลจะสามารถถอดรหัสได้เฉพาะโดยทั้งสองฝ่าย ผู้ดักฟังจะเห็นแต่สัญญาณรบกวน

  • การจับคู่ คือขั้นตอนที่ทั้งสองฝ่ายดำเนินการ เพื่อตกลงกันเกี่ยวกับคีย์ ที่ใช้ในการเข้ารหัส มันเป็นการแลกเปลี่ยนครั้งเดียวที่ผลิตวัสดุคีย์ที่ใช้ร่วมกันซึ่งเลเยอร์ลิงก์นำไปใส่ในเครื่องมือเข้ารหัส

  • การผูกพัน คือการเลือกที่จะ จัดเก็บ คีย์ไปยังหน่วยเก็บข้อมูลที่ไม่ลบเลือนหลังจากการจับคู่เสร็จสิ้น เพื่อให้การเชื่อมต่อครั้งถัดไประหว่างอุปกรณ์สองเครื่องเดิมสามารถข้ามการจับคู่และไปสู่การเข้ารหัสได้โดยตรง

ภาษาง่ายๆ: การจับคู่คือ "แนะนำตัวเอง"; การผูกพันคือ "จดจำการแนะนำนี้"; การเข้ารหัสคือ "พูดคุยกันอย่างเป็นความลับตั้งแต่นี้เป็นต้นไป"

Two columns labelled "Central" and "Peripheral". A dashed line near the top labelled "BLE connection open (unencrypted)". Below it, three arrows: "pairing request" from central to peripheral, "key exchange" both directions, "pairing complete" forward. A second dashed line below labelled "link encrypted". Two thick bidirectional arrows carry "encrypted GATT traffic". An optional "store keys to flash" box on the side, labelled "bonding".

ขั้นตอนการจับคู่บนการเชื่อมต่อ BLE แบบเปิด เมื่อการแลกเปลี่ยนคีย์เสร็จสมบูรณ์ เลเยอร์ลิงก์จะเข้ารหัสทุกแพ็กเก็ตที่ตามมา การผูกพันเป็นขั้นตอนเพิ่มเติมในการเขียนคีย์ไปยังแฟลช

11.13.2. LE Secure Connections

การแลกเปลี่ยนคีย์สมัยใหม่ที่ใช้โดย BLE คือ LE Secure Connections ซึ่งสร้างบน Elliptic Curve Diffie-Hellman ทั้งสองฝ่ายสร้างคู่คีย์ชั่วคราว แลกเปลี่ยนครึ่งส่วนสาธารณะ และรวมผลลัพธ์กับคีย์ส่วนตัวของตนเองเพื่อได้มาซึ่งความลับร่วมกัน -- ความลับที่ผู้ดักฟังไม่สามารถคำนวณได้แม้จะมีบันทึกการแลกเปลี่ยนทั้งหมด

วิธี LE Legacy แบบเก่าปลอดภัยน้อยกว่า (ผู้ดักฟังที่มีการแลกเปลี่ยนทั้งหมดมักจะกู้คืนคีย์ได้) และมีอยู่เพียงเพื่อความเข้ากันได้กับอุปกรณ์ต่อพ่วงเก่า ค่าเริ่มต้นของ aioble คือวิธีสมัยใหม่ (le_secure=True); ให้เก็บไว้อย่างนั้น

11.13.3. การเริ่มต้นการจับคู่

central จับคู่โดยการเรียก aioble.DeviceConnection.pair() บนการเชื่อมต่อที่เปิดอยู่แล้ว:

async with await device.connect() as connection:
    await connection.pair(bond=True, le_secure=True, mitm=False)
    # ... GATT work, now over an encrypted link ...

หลังจาก pair คืนค่า แอตทริบิวต์ encrypted, authenticated, bonded และ key_size บนการเชื่อมต่อจะสะท้อนสิ่งที่ได้เจรจา

อาร์กิวเมนต์คีย์เวิร์ดที่มีประโยชน์ที่สุดสี่ประการ:

  • bond=True -- บันทึกคีย์ที่ได้ไปยังแฟลชเพื่อให้การเชื่อมต่อครั้งถัดไประหว่างอุปกรณ์สองเครื่องเดิมข้ามขั้นตอนการจับคู่ ค่าเริ่มต้นคือ True

  • le_secure=True -- ใช้ LE Secure Connections ค่าเริ่มต้นคือ True อย่าเปลี่ยน

  • mitm=False -- ว่าจะต้องการการป้องกัน man-in-the-middle หรือไม่ สิ่งนี้ต้องการช่องทางนอกแบนด์ (รหัสตัวเลขที่แสดงด้านหนึ่งและยืนยันด้านอื่น รหัสผ่านที่พิมพ์เข้า ...) เพื่อให้ผู้ใช้สามารถยืนยันว่าอุปกรณ์สองเครื่องในขั้นตอนการจับคู่เป็นเครื่องที่พวกเขาคิดจริงๆ ค่าเริ่มต้นคือ False (ไม่มีการป้องกัน MITM -- ผู้ดักฟังเฉยๆ ไม่สามารถอ่านลิงก์ได้ แต่ผู้โจมตีที่เปลี่ยนเส้นทางการเชื่อมต่ออย่างแข็งขันอาจจับคู่ตัวเองเข้ามาได้) ตั้งค่าเป็น True สำหรับสิ่งที่ละเอียดอ่อน แต่โปรดทราบว่ามันต้องการให้อุปกรณ์ต่อพ่วงรองรับความสามารถ IO จริงๆ

  • io=3 -- ความสามารถ IO ที่อุปกรณ์อ้างสิทธิ์ ข้อกำหนด Bluetooth กำหนดห้าแบบ: 0 แสดงผลเท่านั้น, 1 แสดงผล + ใช่/ไม่ใช่, 2 คีย์บอร์ดเท่านั้น, 3 ไม่มีอินพุตไม่มีเอาต์พุต, 4 คีย์บอร์ด + แสดงผล กล้องที่ไม่มี UI มักรายงาน 3; ถ้ากล้องเองมีจอแสดงผล แอปพลิเคชันสามารถแสดงการยืนยันตัวเลขและใช้ 1 การรวมความสามารถ IO ของทั้งสองฝ่ายจะตัดสินว่าการป้องกัน MITM จริงๆ ทำได้หรือไม่

อุปกรณ์ต่อพ่วงไม่ได้เรียก pair เอง -- พวกเขาตอบสนองต่อสิ่งที่ central เริ่มต้น ว่าจะต้องการการเข้ารหัสสำหรับ characteristic ที่กำหนดนั้นเป็นคุณสมบัติของวิธีที่มันถูกประกาศในฐานข้อมูล GATT; บิตการเข้าถึงที่ต้องการการเข้ารหัสเป็นส่วนหนึ่งของ bluetooth API ระดับต่ำและปัจจุบันยังไม่ได้เปิดเผยผ่านตัวสร้าง characteristic ของ aioble

11.13.4. การผูกพัน -- และที่อยู่ของคีย์

เมื่อ bond=True, aioble จะเขียนคีย์ไปยังไฟล์ JSON บนระบบไฟล์ในเครื่อง ชื่อไฟล์เริ่มต้นคือ ble_secrets.json เขียนสัมพันธ์กับไดเร็กทอรีการทำงานปัจจุบัน บนกล้องที่เพิ่งบูต _boot.py ได้เลือกไดเร็กทอรีนั้นแล้ว: /sdcard เมื่อมีการ์ดติดตั้ง, /flash เมื่อไม่มี -- ดังนั้นไฟล์จะอยู่ที่ /sdcard/ble_secrets.json หรือ /flash/ble_secrets.json ไฟล์นี้เก็บรายการที่จำเป็นสำหรับการเข้ารหัสลิงก์ใหม่ในครั้งถัดไปที่เพียร์ที่ผูกพันเชื่อมต่อใหม่ รวมถึงที่อยู่ identity ของเพียร์

ความไม่สมมาตรหนึ่งที่ควรจำ: การบันทึก เกิดขึ้นโดยอัตโนมัติเมื่อคีย์เปลี่ยน แต่ การโหลด ไฟล์เมื่อบูตครั้งถัดไปไม่เกิดขึ้นเอง เรียก aioble.security.load_secrets() ครั้งหนึ่งเมื่อเริ่มต้น (ก่อนการจับคู่หรือการโฆษณาใดๆ) เพื่อให้เพียร์ที่ผูกพันก่อนหน้านี้ได้รับการรู้จัก:

import aioble
aioble.security.load_secrets()        # default path: ble_secrets.json

หลังจากนั้น ครั้งถัดไปที่เพียร์ที่ผูกพันปรากฏขึ้น aioble จะนำคีย์ที่เก็บไว้มาใช้ใหม่และลิงก์จะถูกเข้ารหัสโดยไม่ต้องมีขั้นตอนการสื่อสารเพิ่มเติม

ผลที่ตามมาในทางปฏิบัติสองประการของการเก็บคีย์บนแฟลช:

  • การลืมอุปกรณ์ ลบ ble_secrets.json (หรือลบรายการที่เกี่ยวข้อง) เพื่อลืมเพียร์ที่ผูกพันทั้งหมด จากนั้นจับคู่ใหม่ตั้งแต่ต้น

  • การเข้าถึงทางกายภาพทำให้คีย์รั่วไหล ผู้ใดก็ตามที่มีสิทธิ์เข้าถึงระบบไฟล์ของกล้องสามารถอ่าน JSON ได้ นี่คือข้อจำกัดประเภทเดียวกับที่เกิดขึ้นในส่วนของระบบเครือข่ายด้วยคีย์ TLS (การดำเนินการ: คีย์ การหมดอายุ และการแก้ปัญหา): ใช้คีย์เฉพาะอุปกรณ์ ถือว่าคีย์ที่เก็บไว้ใดๆ สามารถกู้คืนได้ และอาศัยความสามารถในการเพิกถอน (ที่นี่คือการลบการผูกพันจากฝั่ง central) มากกว่าการที่คีย์ยังคงเป็นความลับ

11.13.5. สิ่งที่การเข้ารหัสรับประกัน -- และสิ่งที่ไม่รับประกัน

ลิงก์แบบจับคู่แล้วเข้ารหัสให้ตามลำดับความแข็งแกร่ง:

  • การรักษาความลับ ตลอดเวลา ผู้ดักฟังไม่สามารถอ่านไบต์ได้

  • ความสมบูรณ์ ตลอดเวลา แพ็กเก็ตที่ถูกแก้ไขจะล้มเหลวในการตรวจสอบ authenticated-encryption ของเลเยอร์ลิงก์และถูกทิ้ง

  • การพิสูจน์ตัวตน เฉพาะกับ mitm=True และ IO ที่มีความสามารถ หากไม่มี man-in-the-middle ที่ดักจับการแลกเปลี่ยนการจับคู่ ครั้งแรก อาจแทรกตัวเองเข้ามาได้; หากไม่มีการป้องกัน MITM ทั้งสองฝ่ายไม่มีทางรู้ได้

สำหรับกรณีการใช้กล้องส่วนใหญ่ -- โทรศัพท์จับคู่กับกล้องครั้งหนึ่ง แล้วเชื่อมต่อใหม่ในภายหลัง -- mitm=False มักเพียงพอ เพราะการจับคู่ครั้งแรกเกิดขึ้นในสภาพแวดล้อมที่ควบคุม (ผู้ใช้ถืออุปกรณ์ทั้งสองในห้องเดียวกัน) สำหรับแอปพลิเคชันที่อุปกรณ์ที่จับคู่อาจพบกล้องครั้งแรกในระยะไกลหรือผ่านตัวกลางที่ไม่น่าเชื่อถือ MITM คือการตั้งค่าที่ถูกต้อง

11.13.6. เมื่อการจับคู่เป็นคำตอบที่ไม่ถูกต้อง

การจับคู่มีต้นทุนจริง: การแลกเปลี่ยนสักไม่กี่วินาทีเมื่อเชื่อมต่อครั้งแรก การใช้แฟลชถาวรสำหรับทุกอุปกรณ์ที่ผูกพัน และเรื่องการกู้คืนของ "ลืมการผูกพัน" หากมีสิ่งผิดพลาด สำหรับข้อมูลสาธารณะจริงๆ -- การอ่านค่า sensor แวดล้อมที่เผยแพร่เป็น beacon ป้ายที่แสดงชื่อ สิ่งใดก็ตามที่ไม่เปลี่ยนแปลงโลกด้วยการอ่านหรือเขียน -- คำตอบที่ถูกต้องคือ ไม่ เข้ารหัสเลย และปล่อยให้เครื่องสแกนใกล้เคียงอ่านค่าได้

สำหรับสิ่งอื่นๆ ทั้งหมด connection.pair(bond=True) บน central คือการเพิ่มหนึ่งบรรทัดที่เปลี่ยนลิงก์จากช่องสาธารณะเป็นช่องส่วนตัว