• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.nearby.fastpair.provider;
18 
19 import static com.android.server.nearby.common.bluetooth.fastpair.AesEcbSingleBlockEncryption.decrypt;
20 import static com.android.server.nearby.common.bluetooth.fastpair.Constants.BLUETOOTH_ADDRESS_LENGTH;
21 import static com.android.server.nearby.common.bluetooth.fastpair.Constants.FastPairService.KeyBasedPairingCharacteristic.ActionOverBleFlag.ADDITIONAL_DATA_CHARACTERISTIC;
22 import static com.android.server.nearby.common.bluetooth.fastpair.Constants.FastPairService.KeyBasedPairingCharacteristic.ActionOverBleFlag.DEVICE_ACTION;
23 import static com.android.server.nearby.common.bluetooth.fastpair.Constants.FastPairService.KeyBasedPairingCharacteristic.KeyBasedPairingRequestFlag.PROVIDER_INITIATES_BONDING;
24 import static com.android.server.nearby.common.bluetooth.fastpair.Constants.FastPairService.KeyBasedPairingCharacteristic.KeyBasedPairingRequestFlag.REQUEST_DEVICE_NAME;
25 import static com.android.server.nearby.common.bluetooth.fastpair.Constants.FastPairService.KeyBasedPairingCharacteristic.KeyBasedPairingRequestFlag.REQUEST_DISCOVERABLE;
26 import static com.android.server.nearby.common.bluetooth.fastpair.Constants.FastPairService.KeyBasedPairingCharacteristic.KeyBasedPairingRequestFlag.REQUEST_RETROACTIVE_PAIR;
27 import static com.android.server.nearby.common.bluetooth.fastpair.Constants.FastPairService.KeyBasedPairingCharacteristic.Request.ADDITIONAL_DATA_TYPE_INDEX;
28 
29 import com.android.server.nearby.common.bluetooth.fastpair.Constants.FastPairService.AdditionalDataCharacteristic.AdditionalDataType;
30 import com.android.server.nearby.common.bluetooth.fastpair.Constants.FastPairService.KeyBasedPairingCharacteristic.Request;
31 
32 import java.security.GeneralSecurityException;
33 import java.util.Arrays;
34 
35 /**
36  * A wrapper for Fast Pair Provider to access decoded handshake request from the Seeker.
37  *
38  * @see {go/fast-pair-early-spec-handshake}
39  */
40 public class HandshakeRequest {
41 
42     /**
43      * 16 bytes data: 1-byte for type, 1-byte for flags, 6-bytes for provider's BLE address, 8 bytes
44      * optional data.
45      *
46      * @see {go/fast-pair-spec-handshake-message1}
47      */
48     private final byte[] mDecryptedMessage;
49 
50     /** Enumerates the handshake message types. */
51     public enum Type {
52         KEY_BASED_PAIRING_REQUEST(Request.TYPE_KEY_BASED_PAIRING_REQUEST),
53         ACTION_OVER_BLE(Request.TYPE_ACTION_OVER_BLE),
54         UNKNOWN((byte) 0xFF);
55 
56         private final byte mValue;
57 
Type(byte type)58         Type(byte type) {
59             mValue = type;
60         }
61 
getValue()62         public byte getValue() {
63             return mValue;
64         }
65 
valueOf(byte value)66         public static Type valueOf(byte value) {
67             for (Type type : Type.values()) {
68                 if (type.getValue() == value) {
69                     return type;
70                 }
71             }
72             return UNKNOWN;
73         }
74     }
75 
HandshakeRequest(byte[] key, byte[] encryptedPairingRequest)76     public HandshakeRequest(byte[] key, byte[] encryptedPairingRequest)
77             throws GeneralSecurityException {
78         mDecryptedMessage = decrypt(key, encryptedPairingRequest);
79     }
80 
81     /**
82      * Gets the type of this handshake request. Currently, we have 2 types: 0x00 for Key-based
83      * Pairing Request and 0x10 for Action Request.
84      */
getType()85     public Type getType() {
86         return Type.valueOf(mDecryptedMessage[Request.TYPE_INDEX]);
87     }
88 
89     /**
90      * Gets verification data of this handshake request.
91      * Currently, we use Provider's BLE address.
92      */
getVerificationData()93     public byte[] getVerificationData() {
94         return Arrays.copyOfRange(
95                 mDecryptedMessage,
96                 Request.VERIFICATION_DATA_INDEX,
97                 Request.VERIFICATION_DATA_INDEX + Request.VERIFICATION_DATA_LENGTH);
98     }
99 
100     /** Gets Seeker's public address of the handshake request. */
getSeekerPublicAddress()101     public byte[] getSeekerPublicAddress() {
102         return Arrays.copyOfRange(
103                 mDecryptedMessage,
104                 Request.SEEKER_PUBLIC_ADDRESS_INDEX,
105                 Request.SEEKER_PUBLIC_ADDRESS_INDEX + BLUETOOTH_ADDRESS_LENGTH);
106     }
107 
108     /** Checks whether the Seeker request discoverability from flags byte. */
requestDiscoverable()109     public boolean requestDiscoverable() {
110         return (getFlags() & REQUEST_DISCOVERABLE) != 0;
111     }
112 
113     /**
114      * Checks whether the Seeker requests that the Provider shall initiate bonding from flags byte.
115      */
requestProviderInitialBonding()116     public boolean requestProviderInitialBonding() {
117         return (getFlags() & PROVIDER_INITIATES_BONDING) != 0;
118     }
119 
120     /** Checks whether the Seeker requests that the Provider shall notify the existing name. */
requestDeviceName()121     public boolean requestDeviceName() {
122         return (getFlags() & REQUEST_DEVICE_NAME) != 0;
123     }
124 
125     /** Checks whether this is for retroactively writing account key. */
requestRetroactivePair()126     public boolean requestRetroactivePair() {
127         return (getFlags() & REQUEST_RETROACTIVE_PAIR) != 0;
128     }
129 
130     /** Gets the flags of this handshake request. */
getFlags()131     private byte getFlags() {
132         return mDecryptedMessage[Request.FLAGS_INDEX];
133     }
134 
135     /** Checks whether the Seeker requests a device action. */
requestDeviceAction()136     public boolean requestDeviceAction() {
137         return (getFlags() & DEVICE_ACTION) != 0;
138     }
139 
140     /**
141      * Checks whether the Seeker requests an action which will be followed by an additional data
142      * .
143      */
requestFollowedByAdditionalData()144     public boolean requestFollowedByAdditionalData() {
145         return (getFlags() & ADDITIONAL_DATA_CHARACTERISTIC) != 0;
146     }
147 
148     /** Gets the {@link AdditionalDataType} of this handshake request. */
149     @AdditionalDataType
getAdditionalDataType()150     public int getAdditionalDataType() {
151         if (!requestFollowedByAdditionalData()
152                 || mDecryptedMessage.length <= ADDITIONAL_DATA_TYPE_INDEX) {
153             return AdditionalDataType.UNKNOWN;
154         }
155         return mDecryptedMessage[ADDITIONAL_DATA_TYPE_INDEX];
156     }
157 }
158