349 lines
15 KiB
Java
349 lines
15 KiB
Java
/*
|
|
* Copyright (C) 2022 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.net.wifi.aware;
|
|
|
|
import static android.net.wifi.aware.Characteristics.WIFI_AWARE_CIPHER_SUITE_NCS_PK_128;
|
|
import static android.net.wifi.aware.Characteristics.WIFI_AWARE_CIPHER_SUITE_NCS_PK_256;
|
|
import static android.net.wifi.aware.Characteristics.WIFI_AWARE_CIPHER_SUITE_NCS_SK_128;
|
|
import static android.net.wifi.aware.Characteristics.WIFI_AWARE_CIPHER_SUITE_NCS_SK_256;
|
|
|
|
import android.annotation.Nullable;
|
|
import android.os.Parcel;
|
|
import android.os.Parcelable;
|
|
import android.text.TextUtils;
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.Objects;
|
|
|
|
/**
|
|
* Wi-Fi Aware data-path security config. The config is used with
|
|
* {@link WifiAwareNetworkSpecifier.Builder#setDataPathSecurityConfig(WifiAwareDataPathSecurityConfig)}
|
|
* to request a secure data-path.
|
|
*/
|
|
public final class WifiAwareDataPathSecurityConfig implements Parcelable {
|
|
private final byte[] mPmk;
|
|
private final String mPassphrase;
|
|
private final byte[] mPmkId;
|
|
private final int mCipherSuite;
|
|
|
|
/**
|
|
* Generate a security config with necessary parameters. Use {@link #isValid()} to check before
|
|
* calling
|
|
* {@link WifiAwareNetworkSpecifier.Builder#setDataPathSecurityConfig(WifiAwareDataPathSecurityConfig)}
|
|
* @param passphrase The passphrase to be used to encrypt the link.
|
|
* See {@link Builder#setPskPassphrase(String)}
|
|
* @param cipherSuite The cipher suite to be used to encrypt the link.
|
|
* See {@link Builder#setCipherSuite(int)}
|
|
* @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
|
|
* encrypting the data-path. See {@link Builder#setPmk(byte[])}
|
|
* @param pmkId A PMKID (pairwise master key associated identifier, see IEEE 802.11) is
|
|
* generated by Diffie-Hellman key exchange together with a Pairwise Master Key
|
|
* (PMK), specifying the identifier associated to the key to use for encrypting
|
|
* the data-path. See {@link Builder#setPmkId(byte[])}
|
|
* @hide
|
|
*/
|
|
public WifiAwareDataPathSecurityConfig(
|
|
@Characteristics.WifiAwareDataPathCipherSuites int cipherSuite,
|
|
@Nullable byte[] pmk, @Nullable byte[] pmkId, @Nullable String passphrase) {
|
|
mCipherSuite = cipherSuite;
|
|
mPassphrase = passphrase;
|
|
mPmk = pmk;
|
|
mPmkId = pmkId;
|
|
}
|
|
|
|
private WifiAwareDataPathSecurityConfig(Parcel in) {
|
|
mPmk = in.createByteArray();
|
|
mPassphrase = in.readString();
|
|
mPmkId = in.createByteArray();
|
|
mCipherSuite = in.readInt();
|
|
}
|
|
|
|
public static final @NonNull Creator<WifiAwareDataPathSecurityConfig> CREATOR =
|
|
new Creator<WifiAwareDataPathSecurityConfig>() {
|
|
@Override
|
|
public WifiAwareDataPathSecurityConfig createFromParcel(Parcel in) {
|
|
return new WifiAwareDataPathSecurityConfig(in);
|
|
}
|
|
|
|
@Override
|
|
public WifiAwareDataPathSecurityConfig[] newArray(int size) {
|
|
return new WifiAwareDataPathSecurityConfig[size];
|
|
}
|
|
};
|
|
|
|
@Override
|
|
public int describeContents() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
|
dest.writeByteArray(mPmk);
|
|
dest.writeString(mPassphrase);
|
|
dest.writeByteArray(mPmkId);
|
|
dest.writeInt(mCipherSuite);
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if (this == obj) {
|
|
return true;
|
|
}
|
|
if (!(obj instanceof WifiAwareDataPathSecurityConfig)) {
|
|
return false;
|
|
}
|
|
|
|
WifiAwareDataPathSecurityConfig lhs = (WifiAwareDataPathSecurityConfig) obj;
|
|
return mCipherSuite == lhs.mCipherSuite
|
|
&& Arrays.equals(mPmk, lhs.mPmk)
|
|
&& Objects.equals(mPassphrase, lhs.mPassphrase)
|
|
&& Arrays.equals(mPmkId, lhs.mPmkId);
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return Objects.hash(Arrays.hashCode(mPmk), mPassphrase, Arrays.hashCode(mPmkId),
|
|
mCipherSuite);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
StringBuilder sb = new StringBuilder("WifiAwareDataPathSecurityConfig [");
|
|
sb.append("cipherSuite=").append(mCipherSuite)
|
|
.append(", passphrase=")
|
|
.append((TextUtils.isEmpty(mPassphrase)) ? "<null>" : "<non-null>")
|
|
.append(", PMK=")
|
|
.append((mPmk == null) ? "<null>" : "<non-null>")
|
|
.append(", PMKID=")
|
|
.append((mPmkId == null) ? "<null>" : "<non-null>")
|
|
.append("]");
|
|
return sb.toString();
|
|
}
|
|
|
|
/**
|
|
* Check if the security config is valid.
|
|
* @see Builder#Builder(int)
|
|
* @return True if it is valid, false otherwise.
|
|
* @hide
|
|
*/
|
|
public boolean isValid() {
|
|
if (mCipherSuite == WIFI_AWARE_CIPHER_SUITE_NCS_SK_128
|
|
|| mCipherSuite == WIFI_AWARE_CIPHER_SUITE_NCS_SK_256) {
|
|
if (TextUtils.isEmpty(mPassphrase) && mPmk == null) {
|
|
return false;
|
|
}
|
|
if (!TextUtils.isEmpty(mPassphrase) && mPmk != null) {
|
|
return false;
|
|
}
|
|
if (mPmkId != null) {
|
|
return false;
|
|
}
|
|
if (WifiAwareUtils.validatePassphrase(mPassphrase) && mPmk == null) {
|
|
return true;
|
|
}
|
|
return TextUtils.isEmpty(mPassphrase) && WifiAwareUtils.validatePmk(mPmk);
|
|
} else if (mCipherSuite == WIFI_AWARE_CIPHER_SUITE_NCS_PK_128
|
|
|| mCipherSuite == WIFI_AWARE_CIPHER_SUITE_NCS_PK_256) {
|
|
if (!WifiAwareUtils.validatePmk(mPmk) || !WifiAwareUtils.validatePmkId(mPmkId)) {
|
|
return false;
|
|
}
|
|
return TextUtils.isEmpty(mPassphrase);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get the cipher suite specified in this config
|
|
* @return one of {@code Characteristics#WIFI_AWARE_CIPHER_SUITE_*"}
|
|
*/
|
|
@Characteristics.WifiAwareDataPathCipherSuites
|
|
public int getCipherSuite() {
|
|
return mCipherSuite;
|
|
}
|
|
|
|
/**
|
|
* Get the specified PMK in this config.
|
|
* @see Builder#setPmk(byte[])
|
|
* @return A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
|
|
* encrypting the data-path.
|
|
*/
|
|
public @Nullable byte[] getPmk() {
|
|
return mPmk;
|
|
}
|
|
|
|
/**
|
|
* Get the specified PMKID in this config.
|
|
* @return A PMKID (pairwise master key associated identifier, see IEEE 802.11) is generated
|
|
* by Diffie-Hellman key exchange together with a Pairwise Master Key.
|
|
*/
|
|
public @Nullable byte[] getPmkId() {
|
|
return mPmkId;
|
|
}
|
|
|
|
/**
|
|
* Get the specified passphrase in this config.
|
|
* @return The passphrase to be used to encrypt the link.
|
|
*/
|
|
public @Nullable String getPskPassphrase() {
|
|
return mPassphrase;
|
|
}
|
|
|
|
/**
|
|
* A builder class for a Wi-Fi Aware data-path security config to encrypt an Aware connection.
|
|
*/
|
|
public static final class Builder {
|
|
private byte[] mPmk;
|
|
private String mPassphrase;
|
|
private byte[] mPmkId;
|
|
private int mCipherSuite;
|
|
|
|
/**
|
|
* Create a builder for a Wi-Fi Aware data-path security config to encrypt the link with
|
|
* specified cipher suite. Use {@link Characteristics#getSupportedCipherSuites()} to get the
|
|
* supported capabilities of the device.
|
|
* <ul>
|
|
* <li>For shared key cipher suite
|
|
* {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_128} and
|
|
* {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_256}, either passphrase or PMK must
|
|
* be set.</li>
|
|
* <li>For public key cipher suite
|
|
* {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_128} and
|
|
* {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_256}. Both PMK and PMKID must be
|
|
* set.</li>
|
|
* </ul>
|
|
* @see WifiAwareNetworkSpecifier.Builder#setDataPathSecurityConfig(WifiAwareDataPathSecurityConfig)
|
|
* @param cipherSuite The cipher suite to be used to encrypt the link. One of the
|
|
* {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_128},
|
|
* {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_256},
|
|
* {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_128} and
|
|
* {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_256}.
|
|
*/
|
|
public Builder(@Characteristics.WifiAwareDataPathCipherSuites int cipherSuite) {
|
|
if (cipherSuite != WIFI_AWARE_CIPHER_SUITE_NCS_SK_128
|
|
&& cipherSuite != WIFI_AWARE_CIPHER_SUITE_NCS_SK_256
|
|
&& cipherSuite != WIFI_AWARE_CIPHER_SUITE_NCS_PK_128
|
|
&& cipherSuite != WIFI_AWARE_CIPHER_SUITE_NCS_PK_256) {
|
|
throw new IllegalArgumentException("Invalid cipher suite");
|
|
}
|
|
mCipherSuite = cipherSuite;
|
|
}
|
|
|
|
/**
|
|
* Configure the PSK Passphrase for the Wi-Fi Aware connection being requested. For shared
|
|
* key cipher suite {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_128} and
|
|
* {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_256}, either passphrase or PMK must
|
|
* be set.
|
|
*
|
|
* @param pskPassphrase The passphrase to be used to encrypt the link. Alternatively, use
|
|
* the {@link #setPmk(byte[])} to specify a PMK for shared key cipher
|
|
* suite.
|
|
* @return the current {@link Builder} builder, enabling chaining of builder methods.
|
|
*/
|
|
public @NonNull Builder setPskPassphrase(@NonNull String pskPassphrase) {
|
|
if (!WifiAwareUtils.validatePassphrase(pskPassphrase)) {
|
|
throw new IllegalArgumentException("Passphrase must meet length requirements");
|
|
}
|
|
mPassphrase = pskPassphrase;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Configure the PMK for the Wi-Fi Aware connection being requested. For shared key cipher
|
|
* suite {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_128} and
|
|
* {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_SK_256}, either passphrase or PMK must
|
|
* be set.
|
|
* For public key cipher suite {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_128}
|
|
* and {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_256}. Both PMK and PMKID must
|
|
* be set.
|
|
*
|
|
* @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
|
|
* encrypting the data-path. Alternatively, use the
|
|
* {@link #setPskPassphrase(String)} to specify a Passphrase instead for shared
|
|
* key cipher suite. Use the {@link #setPmkId(byte[])} together for public key
|
|
* cipher suite.
|
|
* @return the current {@link Builder} builder, enabling chaining of builder
|
|
* methods.
|
|
*/
|
|
public @NonNull Builder setPmk(@NonNull byte[] pmk) {
|
|
if (!WifiAwareUtils.validatePmk(pmk)) {
|
|
throw new IllegalArgumentException("PMK must 32 bytes");
|
|
}
|
|
mPmk = pmk;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Configure the PMKID for the Wi-Fi Aware connection being requested. For public key cipher
|
|
* suite {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_128} and
|
|
* {@link Characteristics#WIFI_AWARE_CIPHER_SUITE_NCS_PK_256}. both PMK and PMKID must set
|
|
* {@link #setPmk(byte[])}
|
|
*
|
|
* @param pmkId A PMKID (pairwise master key associated identifier, see IEEE 802.11) is
|
|
* generated by Diffie-Hellman key exchange together with a Pairwise Master Key
|
|
* (PMK), specifying the identifier associated to the key to use for encrypting
|
|
* the data-path. Use the {@link #setPmk(byte[])} together for public key
|
|
* cipher suite.
|
|
* @return the current {@link Builder} builder, enabling chaining of builder
|
|
* methods.
|
|
*/
|
|
public @NonNull Builder setPmkId(@NonNull byte[] pmkId) {
|
|
if (!WifiAwareUtils.validatePmkId(pmkId)) {
|
|
throw new IllegalArgumentException("PMKID must 16 bytes");
|
|
}
|
|
mPmkId = pmkId;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Create a {@link WifiAwareDataPathSecurityConfig} to set in
|
|
* {@link WifiAwareNetworkSpecifier.Builder#setDataPathSecurityConfig(WifiAwareDataPathSecurityConfig)} to encrypt the link.
|
|
* @return A {@link WifiAwareDataPathSecurityConfig} to be used for encrypting the Wi-Fi
|
|
* Aware data-path.
|
|
*/
|
|
public @NonNull WifiAwareDataPathSecurityConfig build() {
|
|
if (mPassphrase != null && mPmk != null) {
|
|
throw new IllegalStateException(
|
|
"Can only specify a Passphrase or a PMK - not both!");
|
|
}
|
|
if (mCipherSuite == WIFI_AWARE_CIPHER_SUITE_NCS_SK_128
|
|
|| mCipherSuite == WIFI_AWARE_CIPHER_SUITE_NCS_SK_256) {
|
|
if (TextUtils.isEmpty(mPassphrase) && mPmk == null) {
|
|
throw new IllegalStateException("Must set either PMK or Passphrase for "
|
|
+ "shared key cipher suite");
|
|
}
|
|
if (mPmkId != null) {
|
|
throw new IllegalStateException("PMKID should not set for "
|
|
+ "shared key cipher suite");
|
|
}
|
|
} else {
|
|
if (mPmk == null || mPmkId == null) {
|
|
throw new IllegalStateException("Must set both PMK and PMKID for "
|
|
+ "public key cipher suite");
|
|
}
|
|
if (!TextUtils.isEmpty(mPassphrase)) {
|
|
throw new IllegalStateException("Passphrase is not support for public "
|
|
+ "key cipher suite");
|
|
}
|
|
}
|
|
|
|
return new WifiAwareDataPathSecurityConfig(mCipherSuite, mPmk, mPmkId, mPassphrase);
|
|
}
|
|
}
|
|
}
|