Characteristics
Fast Pair Service
The Fast Pair Provider shall have the following GATT service.
Service | UUID |
---|---|
Fast Pair Service | 0xFE2C |
This service shall have the following characteristics.
Fast Pair Service characteristic | Encrypted | Permissions | UUID |
---|---|---|---|
Model ID | No | Read | FE2C1233-8366-4814-8EB0-01DE32100BEA |
Key-based Pairing | No | Write and notify | FE2C1234-8366-4814-8EB0-01DE32100BEA |
Passkey | No | Write and notify | FE2C1235-8366-4814-8EB0-01DE32100BEA |
Account Key | No | Write | FE2C1236-8366-4814-8EB0-01DE32100BEA |
Device Information Service
The Fast Pair Provider should also support Device Information Service.
Service | UUID |
---|---|
Device Information Service | 0x180A |
Fast Pair Seeker uses the following characteristics.
Name | Encrypted | Permissions | UUID |
---|---|---|---|
Firmware Revision | No | Read | 0x2A26 |
Characteristic: Model ID
This characteristic allows the Seeker to read the model ID as needed, outside of when the device is advertising in discoverable mode. It should always return the following data:
Octet | Data type | Description | Value |
---|---|---|---|
0 - 2 | uint24 |
Model ID | varies |
Characteristic: Key-based Pairing
This characteristic controls the Key-based Pairing procedure. In this procedure, a certain level of trust is established by verifying that the Seeker and Provider are both in possession of a pre-shared key. The key is different in each case:
Case 1: The pre-shared key is based on the anti-spoofing public/private key pair, and the Seeker's own public/private key pair which will change for each pairing attempt.
- The Provider is in pairing mode.
- The Seeker verifies that the Provider is in possession of the anti-spoofing private key.
Note that when in pairing mode, the Provider may also of course pair in the usual way, for example, to pair with a device that does not support Fast Pair's Key-based Pairing.
Case 2: The pre-shared key is one of the account keys.
- The Provider is usually not in pairing mode. (But this is not a requirement—The Provider should support using an account key even when in pairing mode.)
- The Seeker and Provider each verify that the other is in possession of the account key.
Since both cases are extremely similar, except for which pre-shared key is used, they are combined in procedure.
Data Format
See procedure for how each format is used.
Octet | Data type | Description | Value | Mandatory? |
---|---|---|---|---|
0 - 15 | uint128 |
Encrypted Request | varies | Mandatory |
16 - 79 | Public Key | varies | Optional |
Table 1.1: Encrypted Request, written to the characteristic by the Seeker.
Octet | Data type | Description | Value | Mandatory? |
---|---|---|---|---|
0 | uint8 |
Message type | 0x00 = Key-based Pairing Request |
Mandatory |
1 | uint8 |
Flags
|
varies | Mandatory |
2 - 7 | uint48 |
Either:
|
varies | Mandatory |
8 - 13 | uint48 |
Seeker's BR/EDR Address | varies | Present only if Flags Bit 1 or 3 is set |
n - 15 | Random value (salt) | varies | Mandatory |
Table 1.2.1: Raw Request (type 0x00). Decrypted from the Encrypted Request in Table 1.1.
Octet | Data type | Description | Value | Mandatory? |
---|---|---|---|---|
0 | uint8 |
Message type | 0x10 = Action Request |
Mandatory |
1 | uint8 |
Flags
|
varies | Mandatory |
2 - 7 | uint48 |
Either:
|
varies | Mandatory |
8 | uint8 |
Message group | varies | Mandatory if Flags Bit 0 is set |
9 | uint8 |
Message code | varies | Mandatory if Flags Bit 0 is set |
10 | uint8 |
Depends on Flags:
|
varies | Mandatory if Flags Bit 0 or 1 is set |
11 - n | Additional data | varies | Optional | |
n - 15 | Random value (salt) | varies | Mandatory |
Table 1.2.2: Raw Request (type 0x10). Decrypted from the Encrypted Request in Table 1.1.
Octet | Data type | Description | Value |
---|---|---|---|
0 | uint8 |
Message type | 0x01 = Key-based Pairing Response |
1 - 6 | uint48 |
Provider's public (BR/EDR) address | varies |
7 - 15 | Random value (salt) | varies |
Table 1.3: Raw Response. Encrypted to produce the Encrypted Response in Table 1.4.
Octet | Data type | Description | Value |
---|---|---|---|
0 -15 | uint128 |
Encrypted Response | varies |
Table 1.4: Encrypted Response, sent by the Provider to the Seeker via a notify.
Characteristic: Passkey
This characteristic is used during the Key-based Pairing procedure.
Octet | Data type | Description | Value |
---|---|---|---|
0 - 15 | uint128 |
Encrypted passkey block | varies |
Table 2.1: Encrypted Passkey Block. See Key-based Pairing procedure for usage.
Octet | Data type | Description | Value |
---|---|---|---|
0 | uint8 |
Message type | One of:
|
1 - 3 | unit32 |
6-digit passkey | varies |
4 - 15 | Random value (salt) | varies |
Table 2.2: Raw Passkey Block. Decrypted version of Table 2.1.
Characteristic: Account Key
After pairing, the Fast Pair Seeker will write an Account Key to the Fast Pair Provider.
Octet | Data type | Description | Value |
---|---|---|---|
0 - 15 | uint128 |
Account key (encrypted) | varies |
Upon getting a write request, the Fast Pair Provider shall do the following:
- Decrypt the account key using the shared secret generated from step 4 in the
procedure.
- For Providers that require bonding (common):
- Before decrypting, verify that the shared secret was used to decrypt the passkey request from step 12. If this step has not passed using this secret, ignore this write and quit.
- At this point, the shared secret (K in the procedure) won't be used again for this pairing. Any requests which come in encrypted with this key without restarting the procedure should be rejected.
- For Providers that require bonding (common):
- Verify that the decrypted value starts with
0x04
. If it does not, ignore this write and quit. - Check whether the persisted Account Key list has space for the new value.
- If not, delete the least recently used value from the list.
- Add the new value to the list.
Account Keys in the list are used during Key-based Pairing.
Characteristic: Firmware Revision
This characteristic allows the Seeker to read the firmware revision of the Provider as needed. It should always return the following data:
Octet | Data type | Description | Value |
---|---|---|---|
0 - var | utf8s |
Firmware revision code | varies |
It should be encapsulated to a single utf8 string even if there is more than one firmware (e.g. 3 firmwares for left bud, right bud and case.) on the Provider. The Provider can also return the specific strings for special cases:
status-updating: if the Provider is currently updating to a new firmware. Alternatively, the Provider could return the version of the staged firmware.
status-abnormal: if the Provider is in an abnormal state. For example, it has malfunctioned because the firmware update failed. This value will cause the Seeker to show a message to let user know it has to be updated now.
The Provider should limit access to the Firmware Revision characteristic to prevent device tracking. Suggested restrictions:
- bonded devices should have access at any time
- any device should have access when the Provider is discoverable
Characteristic: Additional Data
This service shall have the following characteristic.
Fast Pair Service characteristic | Encrypted | Permissions | UUID |
---|---|---|---|
Data | No | Write and notify | FE2C1237-8366-4814-8EB0-01DE32100BEA |
Old Fast Pair Service characteristic (target to be deprecated on 2021/1/1) | Encrypted | Permissions | UUID |
---|---|---|---|
Data | No | Write and notify | 0x1237 |
Before writing or notifying to this characteristic, there must be a
handshake through characteristic FE2C1234-8366-4814-8EB0-01DE32100BEA
to have
a shared secret. AES-CTR will be used to encrypt data flowing through this
characteristic, the algorithm of which is defined below. This mode is more
secure across data that extends beyond a single 16-byte block. HMAC-SHA256 will
be used to ensure data integrity, which is also defined below.
Octet | Description | Value |
---|---|---|
0 - 7 | The first 8 bytes of HMAC-SHA256. | varies |
8 - 15 | Nonce, used by AES-CTR encryption. | varies |
16 - var | Encrypted data. | varies |
Table 3.1: Data Packet, sent by the Provider to the Seeker via a notify or sent by the Seeker to the Provider via a write.
Octet | Data type | Description | Value |
---|---|---|---|
0 - var | byte array |
Data | varies, decode it according to the Data ID of Table 1.2.2:
|
Table 3.2: Raw data. Decrypted from the encrypted data in Table 3.1.
When a notify is requested (e.g. request personalized name via Bit 2 in Table 1.2.1), the Fast Pair Provider shall do the following:
- Generate cryptographically random 8 bytes for Nonce.
Encrypt the data using AES-CTR, where each 16-byte block is generated using
encryptedBlock[i] = clearBlock[i] ^ AES(key, concat((uint8) i, 0x00000000000000, nonce))
where
- AES key is the shared secret from step 4 in the procedure.
- clearBlock[i] is a 16-byte block starting from data[i * 16]. The last block can be less than 16 bytes.
Perform concat(encryptedBlock[0], encryptedBlock[1],...) to create the Encrypted Data.
Generate HMAC-SHA256 by
sha256(concat((K ^ opad), sha256(concat((K ^ ipad), concat(nonce, encrypted_data)))))
where
- K is generated by concat(shared_secret, 48-byte ZEROs), the shared_secret is from step 4 in the procedure.
- opad is 64 bytes outer padding, consisting of repeated bytes valued
0x5C
. - ipad is 64 bytes inner padding, consisting of repeated bytes valued
0x36
.
Take the first 8 bytes from the HMAC-SHA256 as the prefix of the Data packet.
Upon getting a write request, the Fast Pair Provider shall do the following:
- Verify the integrity of the data by checking the first 8 bytes of HMAC-SHA256.
Decrypt the encrypted Data using AES-CTR, where each block is generated using
clearBlock[i] = encryptedBlock[i] ^ AES(key, concat((uint8) i, 0x00000000000000, nonce))
where
- encryptedBlock[i] is a 16-byte block start from encrypted_data[i * 16]. The last block can be less than 16 bytes.
- AES key is generated or identified from the handshake, e.g.
- in naming flow 1, it is from ECDH, and it will not be used again for this pairing. Any requests which come in encrypted with this key without restarting the procedure should be rejected.
- in naming flow 2, it is the account key.
Perform concat(clearBlock[0], clearBlock[1],...) to create the raw data.