특성

GATT 서비스의 서비스 및 특성

빠른 페어링 제공업체는 다음과 같은 GATT 서비스를 보유해야 합니다.

서비스 UUID
빠른 페어링 서비스 0xFE2C

이 서비스는 다음과 같은 특성을 지닙니다.

커스텀 특성

빠른 페어링 서비스 특성 암호화됨 권한 UUID
모델 ID 아니요 읽기 FE2C1233-8366-4814-8EB0-01DE32100BEA
키 기반 페어링 아니요 작성 및 알림 FE2C1234-8366-4814-8EB0-01DE32100BEA
패스키 아니요 작성 및 알림 FE2C1235-8366-4814-8EB0-01DE32100BEA
계정 키 아니요 쓰기 FE2C1236-8366-4814-8EB0-01DE32100BEA

표준 특성

이름 암호화됨 권한 UUID
펌웨어 버전 아니요 읽기 0x2A26

특성: 모델 ID

이 특성을 통해 기기가 검색 가능한 모드로 광고되는 경우를 제외하고 시커가 필요에 따라 모델 ID를 읽을 수 있습니다. 항상 다음 데이터를 반환해야 합니다.

옥텟 데이터 유형 설명 가치
0~2 uint24 모델 ID 다양함

특성: 키 기반 페어링

이 특성은 키 기반 페어링 절차를 제어합니다. 이 절차에서는 시커와 제공자가 모두 사전 공유 키를 소유하고 있음을 확인하여 일정 수준의 신뢰를 설정합니다. 키는 사례마다 다릅니다.

  • 사례 1: 사전 공유 키는 스푸핑 방지 공개 키/비공개 키 쌍과 페어링 시도 시 변경되는 시커의 자체 공개 키/비공개 키 쌍을 기반으로 합니다.

    • 제공업체가 페어링 모드입니다.
    • 시커는 제공자가 스푸핑 방지 비공개 키를 소유하고 있는지 확인합니다.

    페어링 모드에서 제공자는 당연히 빠른 페어링의 키 기반 페어링을 지원하지 않는 기기와 페어링하는 것과 같이 일반적인 방식으로 페어링할 수도 있습니다.

  • 사례 2: 사전 공유 키는 계정 키 중 하나입니다.

    • 제공업체는 보통 페어링 모드에 있지 않습니다. (하지만 이것은 요구사항이 아닙니다. 제공자는 페어링 모드에서도 계정 키 사용을 지원해야 합니다.)
    • 시커와 제공자는 서로가 계정 키를 소유하고 있음을 확인합니다.

두 경우 모두 사전 공유 키가 사용되는 경우를 제외하면 매우 유사하므로 절차로 결합됩니다.

데이터 형식

각 형식이 사용되는 방법은 절차를 참조하세요.

옥텟 데이터 유형 설명 가치 필수 여부
0~15 uint128 암호화된 요청 다양함 필수
만 16~79세 공개 키 다양함 선택사항

표 1.1: 시커가 특성에 기록하는 암호화된 요청

옥텟 데이터 유형 설명 가치 필수 여부
0 uint8 메시지 유형 0x00 = 키 기반 페어링 요청 필수
1 uint8 플래그
  • 비트 0 (MSB): 지원 중단되었으며 Seeker에서 무시됩니다.
  • 비트 1: 1, 요청자가 제공자에게 본딩을 시작하도록 요청하고, 이 요청에 시커의 BR/EDR 주소가 포함된 경우. 그렇지 않으면 0입니다.
  • 비트 2: 1, 시커가 제공자에게 기존 이름을 알리도록 요청하는 경우. 그렇지 않으면 0입니다.
  • 비트 3: 계정 키 소급 작성용인 경우 1 그렇지 않으면 0입니다.
  • 비트 4~7은 나중에 사용하기 위해 예약되므로 무시됩니다.
경우에 따라 다름 필수
2~7명 uint48 다음 중 하나를 선택합니다.
  • 제공업체의 현재 BLE 주소
  • 제공업체의 공개 주소
경우에 따라 다름 필수
8~13 uint48 신청자의 BR/EDR 주소 경우에 따라 다름 플래그 비트 1 또는 3이 설정된 경우에만 있음
n ~ 15 임의 값 (솔트) 경우에 따라 다름 필수

표 1.2.1: 원시 요청 (유형 0x00). 표 1.1의 암호화된 요청에서 복호화

옥텟 데이터 유형 설명 가치 필수 여부
0 uint8 메시지 유형 0x10 = 작업 요청 필수
1 uint8 플래그
  • 비트 0 (MSB): 기기 작업인 경우 1, 그렇지 않은 경우 0
  • 비트 1: 추가 데이터 특성이 뒤에 오면 1, 그렇지 않으면 0
  • 비트 2~7은 나중에 사용하기 위해 예약되므로 무시됩니다.
경우에 따라 다름 필수
2~7명 uint48 다음 중 하나를 선택합니다.
  • 제공업체의 현재 BLE 주소
  • 제공업체의 공개 주소
경우에 따라 다름 필수
8 uint8 메시지 그룹 경우에 따라 다름 플래그 비트 0이 설정된 경우 필수
9 uint8 메시지 코드 경우에 따라 다름 플래그 비트 0이 설정된 경우 필수
10 uint8 플래그에 따라 다름:
  • 비트 0이 설정됨: 추가 데이터 길이, 6 미만
  • 비트 1 설정됨: 데이터 ID
경우에 따라 다름 플래그 비트 0 또는 1이 설정된 경우 필수입니다.
11 - n 추가 데이터 경우에 따라 다름 선택사항
n ~ 15 임의 값 (솔트) 경우에 따라 다름 필수

표 1.2.2: 원시 요청 (유형 0x10). 표 1.1의 암호화된 요청에서 복호화

옥텟 데이터 유형 설명 가치
0 uint8 메시지 유형 0x01 = 키 기반 페어링 응답
1~6 uint48 제공업체의 공개 (BR/EDR) 주소 경우에 따라 다름
7~15명 임의 값 (솔트) 경우에 따라 다름

표 1.3: 원시 응답 표 1.4의 암호화된 응답을 생성하기 위해 암호화됨

옥텟 데이터 유형 설명 가치
0~15 uint128 암호화된 응답 경우에 따라 다름

표 1.4: 제공자가 알림을 통해 탐색자에게 전송하는 암호화된 응답

특성: 패스키

이 특성은 키 기반 페어링 절차 중에 사용됩니다.

옥텟 데이터 유형 설명 가치
0~15 uint128 암호화된 패스키 블록 경우에 따라 다름

표 2.1: 암호화된 패스키 블록 사용법은 키 기반 페어링 절차를 참조하세요.

옥텟 데이터 유형 설명 가치
0 uint8 메시지 유형 다음 중 하나:
  • 0x02 = 시커의 패스키
  • 0x03 = 제공자의 패스키
1~3 unit32 6자리 패스키 경우에 따라 다름
4~15명 임의 값 (솔트) 경우에 따라 다름

표 2.2: 원시 패스키 블록 표 2.1의 복호화된 버전

특성: 계정 키

페어링이 끝나면 빠른 페어링 탐색자가 빠른 페어링 제공업체에 계정 키를 작성합니다.

옥텟 데이터 유형 설명 가치
0~15 uint128 계정 키 (암호화됨) 경우에 따라 다름

빠른 페어링 제공자는 쓰기 요청을 받으면 다음 작업을 수행해야 합니다.

  1. 절차의 4단계에서 생성된 공유 비밀번호를 사용하여 계정 키를 복호화합니다.
    1. 복호화하기 전에 12단계의 패스키 요청을 복호화하는 데 공유 비밀번호가 사용되었는지 확인합니다. 이 단계를 통과하지 못한 경우 이 보안 비밀을 사용하여 이 쓰기를 무시하고 종료합니다.
    2. 이 시점에서 공유 비밀번호 (절차 중 K)는 이 페어링에 다시 사용되지 않습니다. 절차를 다시 시작하지 않고 이 키로 암호화된 상태로 들어오는 요청은 거부되어야 합니다.
  2. 복호화된 값이 0x04로 시작하는지 확인합니다. 그렇지 않으면 쓰기를 무시하고 종료합니다.
  3. 유지되는 계정 키 목록에 새 값을 위한 공간이 있는지 확인합니다.
  4. 그렇지 않은 경우 목록에서 가장 오래전에 사용된 값을 삭제합니다.
  5. 목록에 새 값을 추가합니다.

목록의 계정 키는 키 기반 페어링에 사용됩니다.

특성: 펌웨어 버전

이 특성을 통해 시커는 필요에 따라 제공업체의 펌웨어 버전을 읽을 수 있습니다. 항상 다음 데이터를 반환해야 합니다.

옥텟 데이터 유형 설명 가치
0 - var utf8s 펌웨어 버전 코드 경우에 따라 다름

제공자에 둘 이상의 펌웨어가 있더라도 (예: 왼쪽 이어폰, 오른쪽 이어폰, 케이스에 3개의 펌웨어가 있음) 단일 utf8 문자열로 캡슐화해야 합니다. 제공자는 특수한 경우에 대해 특정 문자열을 반환할 수도 있습니다.

  1. 상태 업데이트: 제공업체가 현재 새 펌웨어로 업데이트 중인 경우 또는 제공자가 스테이징 펌웨어의 버전을 반환할 수 있습니다.

  2. status-abnormal: 제공업체가 비정상 상태인 경우 예를 들어 펌웨어 업데이트에 실패하여 오작동했습니다. 이 값을 통해 Seeker는 사용자에게 지금 업데이트해야 한다고 알리는 메시지를 표시합니다.

특성: 추가 데이터

이 서비스는 다음과 같은 특성을 지닙니다.

빠른 페어링 서비스 특성 암호화됨 권한 UUID
데이터 아니요 작성 및 알림 FE2C1237-8366-4814-8EB0-01DE32100BEA
이전 빠른 페어링 서비스 특성 (2021년 1월 1일에 지원 중단 예정) 암호화됨 권한 UUID
데이터 아니요 작성 및 알림 0x1237

이 특성에 쓰거나 알림을 보내기 전에 공유 보안 비밀을 가지려면 특성 FE2C1234-8366-4814-8EB0-01DE32100BEA를 통해 핸드셰이크가 있어야 합니다. AES-CTR은 이 특성을 통해 전달되는 데이터를 암호화하는 데 사용되며, 알고리즘은 아래에 정의되어 있습니다. 이 모드는 단일 16바이트 블록을 초과하는 데이터에 대해 더 안전합니다. HMAC-SHA256은 아래에도 정의된 데이터 무결성을 보장하는 데 사용됩니다.

옥텟 설명 가치
0 - 7 HMAC-SHA256의 처음 8바이트 경우에 따라 다름
8~15명 nonce: AES-CTR 암호화에 사용됩니다. 경우에 따라 다름
16 - var 암호화된 데이터, 경우에 따라 다름

표 3.1: 제공자가 알림을 통해 탐색자에게 전송하거나, 쓰기를 통해 탐색자가 제공자에게 전송하는 데이터 패킷

옥텟 데이터 유형 설명 가치
0 - var byte array 데이터 경우에 따라 표 1.2.2의 데이터 ID에 따라 디코딩합니다.
  • 0x01(맞춤설정된 이름): utf8s

표 3.2: 원시 데이터. 표 3.1의 암호화된 데이터에서 복호화됨

알림이 요청되면 (예: 표 1.2.1의 비트 2를 통해 맞춤설정된 이름 요청) 빠른 페어링 제공자는 다음을 실행해야 합니다.

  1. Nonce에 사용할 암호화 방식의 임의 8바이트를 생성합니다.
  2. AES-CTR을 사용하여 데이터를 암호화. 각 16바이트 블록은 다음을 사용하여 생성됩니다.

    encryptedBlock[i] = clearBlock[i] ^ AES(key, concat((uint8) i, 0x00000000000000, nonce))
    

    어디서

    1. AES 키는 절차의 4단계에서 가져온 공유 비밀번호입니다.
    2. clearBlock[i] 은 데이터[i * 16]에서 시작하는 16바이트 블록입니다. 마지막 블록은 16바이트 미만일 수 있습니다.
  3. concat(encryptedBlock[0], encryptedBlock[1],...)을 수행하여 암호화된 데이터를 만듭니다.

  4. 다음과 같이 HMAC-SHA256을 생성합니다.

    sha256(concat((K ^ opad), sha256(concat((K ^ ipad), concat(nonce, encrypted_data)))))
    

    어디서

    1. K는 concat(shared_secret, 48바이트 ZEROs)에 의해 생성되며, shared_secret은 프로시저의 4단계에서 가져옵니다.
    2. opad는 0x5C 값의 반복 바이트로 구성된 64바이트 외부 패딩입니다.
    3. ipad는 0x36 값의 반복 바이트로 구성된 64바이트의 내부 패딩입니다.
  5. HMAC-SHA256의 처음 8바이트를 데이터 패킷의 프리픽스로 가져옵니다.

빠른 페어링 제공자는 쓰기 요청을 받으면 다음 작업을 수행해야 합니다.

  1. HMAC-SHA256의 처음 8바이트를 확인하여 데이터의 무결성을 확인합니다.
  2. AES-CTR을 사용하여 암호화된 데이터를 복호화합니다. 이때 각 블록은

    clearBlock[i] = encryptedBlock[i] ^ AES(key, concat((uint8) i, 0x00000000000000, nonce))
    

    어디서

    1. 암호화된Block[i] 은encrypted_data[i * 16]의 16바이트 블록 시작입니다. 마지막 블록은 16바이트 미만일 수 있습니다.
    2. AES 키는 핸드셰이크에서 생성되거나 식별됩니다(예:
      1. 이름 지정 흐름 1에서 이는 ECDH에서 발생하며, 이 페어링에 다시 사용되지 않습니다. 절차를 다시 시작하지 않고 이 키로 암호화된 상태로 들어오는 요청은 거부됩니다.
      2. 이름 지정 흐름 2에서 계정 키입니다.
  3. concat(clearBlock[0], clearBlock[1],...)을 실행하여 원시 데이터를 만듭니다.