Step 3: Setup up GATT service

Procedure

Instead of immediately invoking any of the normal BR/EDR or BLE bonding procedures, the Seeker first enables Notifications on the Key-based Pairing characteristic, and then writes the data in Table 1.1 to it.

When handling a write request from a Fast Pair Seeker, the Fast Pair Provider shall do the following:

  1. If the optional Public Key field is present:
    1. If the device is not in pairing mode, ignore the write and exit.
    2. Otherwise:
      1. Use the received Public Key (a 64-byte point on the secp256r1 elliptic curve), the pre-installed Anti-Spoofing Private Key - also secp256r1, and the Elliptic-Curve Diffie-Hellman algorithm to generate a 256-bit AES key.
      2. Use SHA-256 to hash the 256-bit AES key.
      3. Take the first 128 bits of the result. This is the Anti-Spoofing AES Key, used in the next step.
  2. Using AES-128, attempt to decrypt the value. Since the value is a single 16-byte AES block, no IV or multi-block cipher mode is necessary.

    1. Which key to use:
      1. If an Anti-Spoofing AES Key was generated in step 1, use that key.
      2. Otherwise, try each key in the persisted Account Key List.
    2. If a key successfully decrypts the value, break, and continue to the next step.
    3. The value is decrypted successfully if the output matches the format in Table 1.2.1 or Table 1.2.2 - (that is, if it contains either the Fast Pair Provider’s current BLE address, or the Fast Pair Provider’s public address).

      NOTE: At the end of the packet there is a salt attached. When possible, these salts should be tracked, and if the Provider receives a request containing an already used salt, the request should be ignored to prevent replay attacks.

    4. As an alternative to tracking salts, if the write includes the Provider’s private address, another way to prevent replay attacks is to bring forward the time of the next resolvable private address rotation so that the rotation occurs before the next Key-based Pairing write will be accepted.

  3. If no key could successfully decrypt the value, ignore the write and exit.

    1. Keep a count of these failures. When the failure count hits 10, fail all new requests immediately. Reset the failure count after 5 minutes, after power on, or after a success.
  4. Otherwise, save the successful key as K. Mark this K as usable for decrypting Passkey and Personalized name writes received on this LE link, but not other writes nor any writes on any other link. Start a timer to discard K after 10 seconds if pairing has not been started. Also discard K if this LE link disconnects.

  5. Produce the 16-byte Raw Response shown in Table 1.3, by concatenating the type and the Provider’s BR/EDR address, and then filling the remainder of the packet with a block of random bytes (that is, a salt).

  6. Encrypt the Raw Response with K to produce the 16-byte Encrypted Response shown in Table 1.4. Send this via a notify on the Key-based Pairing characteristic.

  7. Read the request flag:

    1. If the Request’s Flags byte has bit 2 set to 1, notify Additional Data characteristic with personalized name.
    2. If the Request’s Flags byte has bit 1 set to 1:
      1. This indicates that the Seeker is requesting the Provider to initiate bonding to the Seeker’s BR/EDR address, which is present in bytes 8-13.
      2. Send a pairing request to the Seeker’s BR/EDR address. The pairing request must be as described below (“During pairing” step).
      3. Reason this is needed: Having the Provider initiate works around an issue on some devices.
    3. If the Request’s Flags byte has bit 1 set to 0:
      1. Wait up to 10 seconds for a pairing request. If none is received, exit.
      2. Note that this might be a BR/EDR request, from a different address (the Seeker’s public address, instead of its resolvable private address). We will re-verify during pairing that the requesting device is in possession of K.
  8. During pairing:

    1. When a pairing request/response packet is received from the Seeker: If the Device Capabilities in the request are NoInput/NoOutput, end pairing, to avoid using the Just Works pairing method.
    2. For the pairing request/response packet sent by the Provider: Set the Device Capabilities field to Display/YesNo and set Authentication Requirements to MITM Protection Required. This triggers the Numeric Comparison pairing method (also known as Passkey Confirmation on Android). We rely on this to confirm that the requesting device is in fact the Fast Pair Seeker, and that there is no man-in-the-middle. See examples.
    3. Reason this is needed: The Out-of-Band pairing method would be a better fit, but the platform does not expose it on all desired versions of Android.
  9. When confirmation of the passkey is needed, wait up to 10 seconds for a write to the Passkey characteristic.

    1. Normally, with this pairing method, the user would confirm that the passkeys displayed on each device’s screen are identical. Instead, only for this pairing, we transfer them over BLE, encrypted with the trusted pre-shared key.
    2. Note that this approach should not be taken for devices that have a screen or a keyboard as it makes a slight compromise on MITM protection. Fast Pair currently does not support those device types yet because of this.
    3. If the 10 second timer expires without a passkey being written, then discard K.
  10. When a value is written to the Passkey characteristic, this is the Encrypted Passkey Block. Decrypt it with K to yield a Raw Passkey Block, with format shown in Characteristic: Passkey > Table 2.2 - (type = Seeker’s Passkey).

  11. If decryption fails, ignore the write and discard K.

  12. Otherwise, the Raw Passkey Block contains a 6-digit passkey PSeeker, which is the passkey that the Seeker expects.

  13. Compare PSeeker with our own expected passkey, PProvider.

    1. If the values are equal, reply “yes” to the confirmation.
    2. Otherwise, reply “no” to the confirmation, causing pairing to fail.
  14. Regardless of whether pairing failed, produce another Raw Passkey Block, with format shown in Characteristic: Passkey > Table 2.2, containing our own expected passkey, PProvider.

    1. Ensure the block has the correct type (Provider’s Passkey; see table). NOTE: Do not reuse the salt from the Passkey Block received from the Seeker. Generate a new random value.
  15. Encrypt the Raw Passkey Block with K, and send the resulting Encrypted Passkey Block via a notify on the Passkey characteristic.

  16. If the Seeker receives and decrypts the correct passkey P, the Seeker will also reply “yes” to the confirmation, and pairing will succeed.

    1. If the pairing succeeds, then mark K as usable for decrypting Account Key writes on this LE link, but not for any subsequent Passkey writes nor any writes on any other link. Start a timer to discard K after 10 seconds. Also discard K following any attempt to write an Account Key and, as per step 4, if the LE link disconnects.
    2. If the pairing fails, discard K.
  17. Switch the device capabilities field back to NoInput/NoOutput and Authentication Requirements to MITM Protection Not Required so that new pairings continue as expected.

Examples
Example 1: Successful pairing attempt (no man-in-the-middle).
Example 2: Failed pairing attempt, with a man-in-the-middle.