## 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](https://developers.google.com/nearby/fast-pair/specifications/service/provider#AdvertisingWhenDiscoverable "Advertising when Discoverable"). It should always return
the following data:

| Octet | Data type | Description | Value |
|---|---|---|---|
| 0 - 2 | `uint24` | Model ID | varies |

### Characteristic: Key-based Pairing

> [!NOTE]
> **Note:** Google recommends implementing the [Cryptographic Test Cases](https://developers.google.com/nearby/fast-pair/specifications/appendix/cryptotestcases "Link to the Cryptographic Test Cases.") to ease verification of these requirements.

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](https://developers.google.com/nearby/fast-pair/specifications/configuration#AccountKeyList "Account Key List").

  - 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](https://developers.google.com/nearby/fast-pair/specifications/service/gatt#procedure "Procedure").

#### Data Format

See [procedure](https://developers.google.com/nearby/fast-pair/specifications/service/gatt#procedure "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 - Bit 0 (MSB): deprecated and ignored by Seeker. - Bit 1: 1 if the Seeker requests that the Provider shall initiate bonding, and this request contains the Seeker's BR/EDR address. 0 otherwise. - Bit 2: 1 if the Seeker requests that the Provider shall notify the existing name. 0 otherwise. - Bit 3: 1 if this is for [Retroactively writing account key](https://developers.google.com/nearby/fast-pair/specifications/extensions/retroactiveacctkey "Retroactively writing account key"). 0 otherwise. - Bits 4 - 7 are reserved for future use, and shall be ignored. | *varies* | Mandatory |
| 2 - 7 | `uint48` | Either: - Provider's current BLE address - Provider's public address | *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](https://developers.google.com/nearby/fast-pair/specifications/characteristics#table1.1).*

| Octet | Data type | Description | Value | Mandatory? |
|---|---|---|---|---|
| 0 | `uint8` | Message type | `0x10` = Action Request | Mandatory |
| 1 | `uint8` | Flags - Bit 0 (MSB): 1 if it is a [Device action](https://developers.google.com/nearby/fast-pair/specifications/extensions/deviceaction#DeviceAction "Message Stream - Device Action"), 0 otherwise. - Bit 1: 1 if it will be followed by [Additional Data characteristic](https://developers.google.com/nearby/fast-pair/specifications/characteristics#AdditionalData), 0 otherwise. - Bit 2 - 7 are reserved for future use, and shall be ignored. | *varies* | Mandatory |
| 2 - 7 | `uint48` | Either: - Provider's current BLE address - Provider's public address | *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: - Bit 0 is set: Additional data length, less than 6 - Bit 1 is set: Data ID | *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](https://developers.google.com/nearby/fast-pair/specifications/characteristics#table1.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](https://developers.google.com/nearby/fast-pair/specifications/characteristics#table1.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](https://developers.google.com/nearby/fast-pair/specifications/characteristics#KeyBasedPairing)
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: - `0x02` = Seeker's Passkey - `0x03` = Provider's Passkey |
| 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](https://developers.google.com/nearby/fast-pair/specifications/characteristics#table2.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:

1. Decrypt the account key using the shared secret generated from step 4 in the [procedure](https://developers.google.com/nearby/fast-pair/specifications/service/gatt#procedure "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.
2. Verify that the decrypted value starts with `0x04` or `0xFF`. If it does not, ignore this write and quit.
   - If value is `0x04`:
     - Check whether the persisted [Account Key list](https://developers.google.com/nearby/fast-pair/specifications/configuration#AccountKeyList "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.
   - If value is `0xFF`:
     - Treat this as a temporary pairing session and perform no operation.
     - This can happen with the [Retroactively writing account key](https://developers.google.com/nearby/fast-pair/specifications/extensions/retroactiveacctkey "Retroactively writing account key") flow.
     - Do not store the key, and do not use it in the [Account Key list](https://developers.google.com/nearby/fast-pair/specifications/configuration#AccountKeyList "Account Key List"), encryption, or [MAC](https://developers.google.com/nearby/fast-pair/specifications/extensions/mac#MacOfMessageStream "MAC") calculations.
     - Bond removal is triggered by a feature-specific event or timeout. For LE Audio Sharing, it is highly recommended to remove the BLE bond and link key 10 minutes after the temporary session disconnects.

Account Keys in the list are used during [Key-based Pairing](https://developers.google.com/nearby/fast-pair/specifications/characteristics#KeyBasedPairing).

### 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:

1. *status-updating*: if the Provider is currently updating to a new firmware.
   Alternatively, the Provider could return the version of the staged firmware.

2. *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](https://developers.google.com/nearby/fast-pair/specifications/characteristics#table1.2.2): - 0x01(personalized name): utf8s |

***Table 3.2:** Raw data. Decrypted from the encrypted data in
[Table 3.1](https://developers.google.com/nearby/fast-pair/specifications/characteristics#table3.1).*

When a notify is requested (e.g. request personalized name via Bit 2 in
[Table 1.2.1](https://developers.google.com/nearby/fast-pair/specifications/characteristics#table1.2.1)), the Fast Pair Provider shall do the following:

1. Generate cryptographically random 8 bytes for Nonce.
2. 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
   1. AES key is the shared secret from step 4 in the [procedure](https://developers.google.com/nearby/fast-pair/specifications/service/gatt#procedure "Procedure").
   2. clearBlock\[i\] is a 16-byte block starting from data\[i \* 16\]. The last block can be less than 16 bytes.
3. Perform concat(encryptedBlock\[0\], encryptedBlock\[1\],...) to create the
   Encrypted Data.

4. Generate HMAC-SHA256 by

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

   where
   1. K is generated by concat(shared_secret, 48-byte ZEROs), the shared_secret is from step 4 in the [procedure](https://developers.google.com/nearby/fast-pair/specifications/service/gatt#procedure "Procedure").
   2. opad is 64 bytes outer padding, consisting of repeated bytes valued `0x5C`.
   3. ipad is 64 bytes inner padding, consisting of repeated bytes valued `0x36`.
5. Take the first 8 bytes from the HMAC-SHA256 as the prefix of the [Data
   packet](https://developers.google.com/nearby/fast-pair/specifications/characteristics#table3.1).

Upon getting a write request, the Fast Pair Provider shall do the following:

1. Verify the integrity of the data by checking the first 8 bytes of HMAC-SHA256.
2. 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
   1. encryptedBlock\[i\] is a 16-byte block start from encrypted_data\[i \* 16\]. The last block can be less than 16 bytes.
   2. AES key is generated or identified from the handshake, e.g.
      1. in [naming flow 1](https://developers.google.com/nearby/fast-pair/specifications/extensions/personalizedname#Namingflow1 "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.
      2. in [naming flow 2](https://developers.google.com/nearby/fast-pair/specifications/extensions/personalizedname#Namingflow2 "Naming Flow 2"), it is the account key.
3. Perform concat(clearBlock\[0\], clearBlock\[1\],...) to create the raw data.