• 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.net.wifi.aware;
18 
19 import static android.net.wifi.aware.Characteristics.WIFI_AWARE_CIPHER_SUITE_NCS_PK_128;
20 import static android.net.wifi.aware.Characteristics.WIFI_AWARE_CIPHER_SUITE_NCS_PK_256;
21 import static android.net.wifi.aware.Characteristics.WIFI_AWARE_CIPHER_SUITE_NCS_SK_128;
22 import static android.net.wifi.aware.Characteristics.WIFI_AWARE_CIPHER_SUITE_NCS_SK_256;
23 
24 import android.annotation.Nullable;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 import android.text.TextUtils;
28 
29 import androidx.annotation.NonNull;
30 
31 import java.util.Arrays;
32 import java.util.Objects;
33 
34 /**
35  * Wi-Fi Aware data-path security config. The config is used with
36  * {@link WifiAwareNetworkSpecifier.Builder#setDataPathSecurityConfig(WifiAwareDataPathSecurityConfig)}
37  * to request a secure data-path.
38  */
39 public final class WifiAwareDataPathSecurityConfig implements Parcelable {
40     private final byte[] mPmk;
41     private final String mPassphrase;
42     private final byte[] mPmkId;
43     private final int mCipherSuite;
44 
45     /**
46      * Generate a security config with necessary parameters. Use {@link #isValid()} to check before
47      * calling
48      * {@link WifiAwareNetworkSpecifier.Builder#setDataPathSecurityConfig(WifiAwareDataPathSecurityConfig)}
49      * @param passphrase The passphrase to be used to encrypt the link.
50      *                      See {@link Builder#setPskPassphrase(String)}
51      * @param cipherSuite The cipher suite to be used to encrypt the link.
52      *                    See {@link Builder#setCipherSuite(int)}
53      * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
54      *            encrypting the data-path. See {@link Builder#setPmk(byte[])}
55      * @param pmkId A PMKID (pairwise master key associated identifier, see IEEE 802.11) is
56      *              generated by Diffie-Hellman key exchange together with a Pairwise Master Key
57      *              (PMK), specifying the identifier associated to the key to use for encrypting
58      *              the data-path. See {@link Builder#setPmkId(byte[])}
59      * @hide
60      */
WifiAwareDataPathSecurityConfig(@haracteristics.WifiAwareCipherSuites int cipherSuite, @Nullable byte[] pmk, @Nullable byte[] pmkId, @Nullable String passphrase)61     public WifiAwareDataPathSecurityConfig(@Characteristics.WifiAwareCipherSuites int cipherSuite,
62             @Nullable byte[] pmk, @Nullable byte[] pmkId, @Nullable String passphrase) {
63         mCipherSuite = cipherSuite;
64         mPassphrase = passphrase;
65         mPmk = pmk;
66         mPmkId = pmkId;
67     }
68 
WifiAwareDataPathSecurityConfig(Parcel in)69     private WifiAwareDataPathSecurityConfig(Parcel in) {
70         mPmk = in.createByteArray();
71         mPassphrase = in.readString();
72         mPmkId = in.createByteArray();
73         mCipherSuite = in.readInt();
74     }
75 
76     public static final @NonNull Creator<WifiAwareDataPathSecurityConfig> CREATOR =
77             new Creator<WifiAwareDataPathSecurityConfig>() {
78                 @Override
79                 public WifiAwareDataPathSecurityConfig createFromParcel(Parcel in) {
80                     return new WifiAwareDataPathSecurityConfig(in);
81                 }
82 
83                 @Override
84                 public WifiAwareDataPathSecurityConfig[] newArray(int size) {
85                     return new WifiAwareDataPathSecurityConfig[size];
86                 }
87             };
88 
89     @Override
describeContents()90     public int describeContents() {
91         return 0;
92     }
93 
94     @Override
writeToParcel(@onNull Parcel dest, int flags)95     public void writeToParcel(@NonNull Parcel dest, int flags) {
96         dest.writeByteArray(mPmk);
97         dest.writeString(mPassphrase);
98         dest.writeByteArray(mPmkId);
99         dest.writeInt(mCipherSuite);
100     }
101 
102     @Override
equals(Object obj)103     public boolean equals(Object obj) {
104         if (this == obj) {
105             return true;
106         }
107         if (!(obj instanceof WifiAwareDataPathSecurityConfig)) {
108             return false;
109         }
110 
111         WifiAwareDataPathSecurityConfig lhs = (WifiAwareDataPathSecurityConfig) obj;
112         return mCipherSuite == lhs.mCipherSuite
113                 && Arrays.equals(mPmk, lhs.mPmk)
114                 && Objects.equals(mPassphrase, lhs.mPassphrase)
115                 && Arrays.equals(mPmkId, lhs.mPmkId);
116     }
117 
118     @Override
hashCode()119     public int hashCode() {
120         return Objects.hash(Arrays.hashCode(mPmk), mPassphrase, Arrays.hashCode(mPmkId),
121                 mCipherSuite);
122     }
123 
124     @Override
toString()125     public String toString() {
126         StringBuilder sb = new StringBuilder("WifiAwareDataPathSecurityConfig [");
127         sb.append("cipherSuite=").append(mCipherSuite)
128                 .append(", passphrase=")
129                 .append((TextUtils.isEmpty(mPassphrase)) ? "<null>" : "<non-null>")
130                 .append(", PMK=")
131                 .append((mPmk == null) ? "<null>" : "<non-null>")
132                 .append(", PMKID=")
133                 .append((mPmkId == null) ? "<null>" : "<non-null>")
134                 .append("]");
135         return sb.toString();
136     }
137 
138     /**
139      * Check if the security config is valid.
140      * @see Builder#Builder(int)
141      * @return True if it is valid, false otherwise.
142      * @hide
143      */
isValid()144     public boolean isValid() {
145         if (mCipherSuite == WIFI_AWARE_CIPHER_SUITE_NCS_SK_128
146                 || mCipherSuite == WIFI_AWARE_CIPHER_SUITE_NCS_SK_256) {
147             if (TextUtils.isEmpty(mPassphrase) && mPmk == null) {
148                 return false;
149             }
150             if (!TextUtils.isEmpty(mPassphrase) && mPmk != null) {
151                 return false;
152             }
153             if (mPmkId != null) {
154                 return false;
155             }
156             if (WifiAwareUtils.validatePassphrase(mPassphrase) && mPmk == null) {
157                 return true;
158             }
159             return TextUtils.isEmpty(mPassphrase) && WifiAwareUtils.validatePmk(mPmk);
160         } else if (mCipherSuite == WIFI_AWARE_CIPHER_SUITE_NCS_PK_128
161                 || mCipherSuite == WIFI_AWARE_CIPHER_SUITE_NCS_PK_256) {
162             if (!WifiAwareUtils.validatePmk(mPmk) || !WifiAwareUtils.validatePmkId(mPmkId)) {
163                 return false;
164             }
165             return TextUtils.isEmpty(mPassphrase);
166         }
167         return false;
168     }
169 
170     /**
171      * Get the cipher suite specified in this config
172      * @return one of {@code Characteristics#WIFI_AWARE_CIPHER_SUITE_*"}
173      */
174     @Characteristics.WifiAwareCipherSuites
getCipherSuite()175     public int getCipherSuite() {
176         return mCipherSuite;
177     }
178 
179     /**
180      * Get the specified PMK in this config.
181      * @see Builder#setPmk(byte[])
182      * @return A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
183      * encrypting the data-path.
184      */
getPmk()185     public @Nullable byte[] getPmk() {
186         return mPmk;
187     }
188 
189     /**
190      * Get the specified PMKID in this config.
191      * @return A PMKID (pairwise master key associated identifier, see IEEE 802.11) is generated
192      * by Diffie-Hellman key exchange together with a Pairwise Master Key.
193      */
getPmkId()194     public @Nullable byte[] getPmkId() {
195         return mPmkId;
196     }
197 
198     /**
199      * Get the specified passphrase in this config.
200      * @return The passphrase to be used to encrypt the link.
201      */
getPskPassphrase()202     public @Nullable String getPskPassphrase() {
203         return mPassphrase;
204     }
205 
206     /**
207      * A builder class for a Wi-Fi Aware data-path security config to encrypt an Aware connection.
208      */
209     public static final class Builder {
210         private  byte[] mPmk;
211         private  String mPassphrase;
212         private  byte[] mPmkId;
213         private  int mCipherSuite;
214 
215         /**
216          * Create a builder for a Wi-Fi Aware data-path security config to encrypt the link with
217          * specified cipher suite. Use {@link Characteristics#getSupportedCipherSuites()} to get the
218          * supported capabilities of the device.
219          * <ul>
220          * <li>For shared key cipher suite
221          * {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_128} and
222          * {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_256}, either passphrase or PMK must
223          * be set.</li>
224          * <li>For public key cipher suite
225          * {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_128} and
226          * {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_256}. Both PMK and PMKID must be
227          * set.</li>
228          * </ul>
229          * @see WifiAwareNetworkSpecifier.Builder#setDataPathSecurityConfig(WifiAwareDataPathSecurityConfig)
230          * @param cipherSuite The cipher suite to be used to encrypt the link. One of the
231          *                    {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_128},
232          *                    {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_256},
233          *                    {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_128} and
234          *                    {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_256}.
235          */
Builder(@haracteristics.WifiAwareCipherSuites int cipherSuite)236         public Builder(@Characteristics.WifiAwareCipherSuites int cipherSuite) {
237             if (cipherSuite != WIFI_AWARE_CIPHER_SUITE_NCS_SK_128
238                     && cipherSuite != WIFI_AWARE_CIPHER_SUITE_NCS_SK_256
239                     && cipherSuite != WIFI_AWARE_CIPHER_SUITE_NCS_PK_128
240                     && cipherSuite != WIFI_AWARE_CIPHER_SUITE_NCS_PK_256) {
241                 throw new IllegalArgumentException("Invalid cipher suite");
242             }
243             mCipherSuite = cipherSuite;
244         }
245 
246         /**
247          * Configure the PSK Passphrase for the Wi-Fi Aware connection being requested. For shared
248          * key cipher suite {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_128} and
249          * {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_256}, either passphrase or PMK must
250          * be set.
251          *
252          * @param pskPassphrase The passphrase to be used to encrypt the link. Alternatively, use
253          *                      the {@link #setPmk(byte[])} to specify a PMK for shared key cipher
254          *                      suite.
255          * @return the current {@link Builder} builder, enabling chaining of builder methods.
256          */
setPskPassphrase(@onNull String pskPassphrase)257         public @NonNull Builder setPskPassphrase(@NonNull String pskPassphrase) {
258             if (!WifiAwareUtils.validatePassphrase(pskPassphrase)) {
259                 throw new IllegalArgumentException("Passphrase must meet length requirements");
260             }
261             mPassphrase = pskPassphrase;
262             return this;
263         }
264 
265         /**
266          * Configure the PMK for the Wi-Fi Aware connection being requested. For shared key cipher
267          * suite {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_128} and
268          * {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_256}, either passphrase or PMK must
269          * be set.
270          * For public key cipher suite {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_128}
271          * and {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_256}. Both PMK and PMKID must
272          * be set.
273          *
274          * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
275          *            encrypting the data-path. Alternatively, use the
276          *            {@link #setPskPassphrase(String)} to specify a Passphrase instead for shared
277          *            key cipher suite. Use the {@link #setPmkId(byte[])} together for public key
278          *            cipher suite.
279          * @return the current {@link Builder} builder, enabling chaining of builder
280          *         methods.
281          */
setPmk(@onNull byte[] pmk)282         public @NonNull Builder setPmk(@NonNull byte[] pmk) {
283             if (!WifiAwareUtils.validatePmk(pmk)) {
284                 throw new IllegalArgumentException("PMK must 32 bytes");
285             }
286             mPmk = pmk;
287             return this;
288         }
289 
290         /**
291          * Configure the PMKID for the Wi-Fi Aware connection being requested. For public key cipher
292          * suite {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_128} and
293          * {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_256}. both PMK and PMKID must set
294          * {@link #setPmk(byte[])}
295          *
296          * @param pmkId A PMKID (pairwise master key associated identifier, see IEEE 802.11) is
297          *              generated by Diffie-Hellman key exchange together with a Pairwise Master Key
298          *              (PMK), specifying the identifier associated to the key to use for encrypting
299          *              the data-path. Use the  {@link #setPmk(byte[])} together for public key
300          *              cipher suite.
301          * @return the current {@link Builder} builder, enabling chaining of builder
302          *         methods.
303          */
setPmkId(@onNull byte[] pmkId)304         public @NonNull Builder setPmkId(@NonNull byte[] pmkId) {
305             if (!WifiAwareUtils.validatePmkId(pmkId)) {
306                 throw new IllegalArgumentException("PMKID must 16 bytes");
307             }
308             mPmkId = pmkId;
309             return this;
310         }
311 
312         /**
313          * Create a {@link WifiAwareDataPathSecurityConfig} to set in
314          * {@link WifiAwareNetworkSpecifier.Builder#setDataPathSecurityConfig(WifiAwareDataPathSecurityConfig)} to encrypt the link.
315          * @return A {@link WifiAwareDataPathSecurityConfig} to be used for encrypting the Wi-Fi
316          * Aware data-path.
317          */
build()318         public @NonNull WifiAwareDataPathSecurityConfig build() {
319             if (mPassphrase != null && mPmk != null) {
320                 throw new IllegalStateException(
321                         "Can only specify a Passphrase or a PMK - not both!");
322             }
323             if (mCipherSuite == WIFI_AWARE_CIPHER_SUITE_NCS_SK_128
324                     || mCipherSuite == WIFI_AWARE_CIPHER_SUITE_NCS_SK_256) {
325                 if (TextUtils.isEmpty(mPassphrase) && mPmk == null) {
326                     throw new IllegalStateException("Must set either PMK or Passphrase for "
327                             + "shared key cipher suite");
328                 }
329                 if (mPmkId != null) {
330                     throw new IllegalStateException("PMKID should not set for "
331                             + "shared key cipher suite");
332                 }
333             } else {
334                 if (mPmk == null || mPmkId == null) {
335                     throw new IllegalStateException("Must set both PMK and PMKID for "
336                             + "public key cipher suite");
337                 }
338                 if (!TextUtils.isEmpty(mPassphrase)) {
339                     throw new IllegalStateException("Passphrase is not support for public "
340                             + "key cipher suite");
341                 }
342             }
343 
344             return new WifiAwareDataPathSecurityConfig(mCipherSuite, mPmk, mPmkId, mPassphrase);
345         }
346     }
347 }
348