summaryrefslogtreecommitdiff
path: root/framework-t/src/android/net/IpSecAlgorithm.java
diff options
context:
space:
mode:
authorAaron Huang <huangaaron@google.com>2021-12-10 17:36:49 +0800
committerAaron Huang <huangaaron@google.com>2021-12-14 14:06:44 +0800
commit8f4e23616c25f06a266196f919dea0e8712da359 (patch)
tree885a15b460e2a5f1e5c989e5dbd630d8b02a39e2 /framework-t/src/android/net/IpSecAlgorithm.java
parent442f296638339b1aec0af18fb1ec20defa9774b4 (diff)
Move IpSec associated files to f/b/packages/ConnectivityT
IpSecService is going to be moved into Connectivity mainline module. Move all ipsec associated files to packages/ConnectivityT so that it can be easily migrate these files to connectivity module after clearing the hidden API usages. Bug: 204153604 Test: build pass FrameworksNetTests CtsNetTestCases Change-Id: I562b47f18e345988a2638cf886f86818f9144b91
Diffstat (limited to 'framework-t/src/android/net/IpSecAlgorithm.java')
-rw-r--r--framework-t/src/android/net/IpSecAlgorithm.java500
1 files changed, 500 insertions, 0 deletions
diff --git a/framework-t/src/android/net/IpSecAlgorithm.java b/framework-t/src/android/net/IpSecAlgorithm.java
new file mode 100644
index 0000000000..86052484ea
--- /dev/null
+++ b/framework-t/src/android/net/IpSecAlgorithm.java
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2017 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;
+
+import android.annotation.NonNull;
+import android.annotation.StringDef;
+import android.content.res.Resources;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.HexDump;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * This class represents a single algorithm that can be used by an {@link IpSecTransform}.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
+ * Internet Protocol</a>
+ */
+public final class IpSecAlgorithm implements Parcelable {
+ private static final String TAG = "IpSecAlgorithm";
+
+ /**
+ * Null cipher.
+ *
+ * @hide
+ */
+ public static final String CRYPT_NULL = "ecb(cipher_null)";
+
+ /**
+ * AES-CBC Encryption/Ciphering Algorithm.
+ *
+ * <p>Valid lengths for this key are {128, 192, 256}.
+ */
+ public static final String CRYPT_AES_CBC = "cbc(aes)";
+
+ /**
+ * AES-CTR Encryption/Ciphering Algorithm.
+ *
+ * <p>Valid lengths for keying material are {160, 224, 288}.
+ *
+ * <p>As per <a href="https://tools.ietf.org/html/rfc3686#section-5.1">RFC3686 (Section
+ * 5.1)</a>, keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit
+ * nonce. RFC compliance requires that the nonce must be unique per security association.
+ *
+ * <p>This algorithm may be available on the device. Caller MUST check if it is supported before
+ * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is
+ * included in the returned algorithm set. The returned algorithm set will not change unless the
+ * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is
+ * requested on an unsupported device.
+ *
+ * <p>@see {@link #getSupportedAlgorithms()}
+ */
+ // This algorithm may be available on devices released before Android 12, and is guaranteed
+ // to be available on devices first shipped with Android 12 or later.
+ public static final String CRYPT_AES_CTR = "rfc3686(ctr(aes))";
+
+ /**
+ * MD5 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
+ * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
+ *
+ * <p>Keys for this algorithm must be 128 bits in length.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to 128.
+ */
+ public static final String AUTH_HMAC_MD5 = "hmac(md5)";
+
+ /**
+ * SHA1 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
+ * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
+ *
+ * <p>Keys for this algorithm must be 160 bits in length.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to 160.
+ */
+ public static final String AUTH_HMAC_SHA1 = "hmac(sha1)";
+
+ /**
+ * SHA256 HMAC Authentication/Integrity Algorithm.
+ *
+ * <p>Keys for this algorithm must be 256 bits in length.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to 256.
+ */
+ public static final String AUTH_HMAC_SHA256 = "hmac(sha256)";
+
+ /**
+ * SHA384 HMAC Authentication/Integrity Algorithm.
+ *
+ * <p>Keys for this algorithm must be 384 bits in length.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 192 to 384.
+ */
+ public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
+
+ /**
+ * SHA512 HMAC Authentication/Integrity Algorithm.
+ *
+ * <p>Keys for this algorithm must be 512 bits in length.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 256 to 512.
+ */
+ public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
+
+ /**
+ * AES-XCBC Authentication/Integrity Algorithm.
+ *
+ * <p>Keys for this algorithm must be 128 bits in length.
+ *
+ * <p>The only valid truncation length is 96 bits.
+ *
+ * <p>This algorithm may be available on the device. Caller MUST check if it is supported before
+ * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is
+ * included in the returned algorithm set. The returned algorithm set will not change unless the
+ * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is
+ * requested on an unsupported device.
+ *
+ * <p>@see {@link #getSupportedAlgorithms()}
+ */
+ // This algorithm may be available on devices released before Android 12, and is guaranteed
+ // to be available on devices first shipped with Android 12 or later.
+ public static final String AUTH_AES_XCBC = "xcbc(aes)";
+
+ /**
+ * AES-CMAC Authentication/Integrity Algorithm.
+ *
+ * <p>Keys for this algorithm must be 128 bits in length.
+ *
+ * <p>The only valid truncation length is 96 bits.
+ *
+ * <p>This algorithm may be available on the device. Caller MUST check if it is supported before
+ * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is
+ * included in the returned algorithm set. The returned algorithm set will not change unless the
+ * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is
+ * requested on an unsupported device.
+ *
+ * <p>@see {@link #getSupportedAlgorithms()}
+ */
+ // This algorithm may be available on devices released before Android 12, and is guaranteed
+ // to be available on devices first shipped with Android 12 or later.
+ public static final String AUTH_AES_CMAC = "cmac(aes)";
+
+ /**
+ * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm.
+ *
+ * <p>Valid lengths for keying material are {160, 224, 288}.
+ *
+ * <p>As per <a href="https://tools.ietf.org/html/rfc4106#section-8.1">RFC4106 (Section
+ * 8.1)</a>, keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit
+ * salt. RFC compliance requires that the salt must be unique per invocation with the same key.
+ *
+ * <p>Valid ICV (truncation) lengths are {64, 96, 128}.
+ */
+ public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
+
+ /**
+ * ChaCha20-Poly1305 Authentication/Integrity + Encryption/Ciphering Algorithm.
+ *
+ * <p>Keys for this algorithm must be 288 bits in length.
+ *
+ * <p>As per <a href="https://tools.ietf.org/html/rfc7634#section-2">RFC7634 (Section 2)</a>,
+ * keying material consists of a 256 bit key followed by a 32-bit salt. The salt is fixed per
+ * security association.
+ *
+ * <p>The only valid ICV (truncation) length is 128 bits.
+ *
+ * <p>This algorithm may be available on the device. Caller MUST check if it is supported before
+ * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is
+ * included in the returned algorithm set. The returned algorithm set will not change unless the
+ * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is
+ * requested on an unsupported device.
+ *
+ * <p>@see {@link #getSupportedAlgorithms()}
+ */
+ // This algorithm may be available on devices released before Android 12, and is guaranteed
+ // to be available on devices first shipped with Android 12 or later.
+ public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)";
+
+ /** @hide */
+ @StringDef({
+ CRYPT_AES_CBC,
+ CRYPT_AES_CTR,
+ AUTH_HMAC_MD5,
+ AUTH_HMAC_SHA1,
+ AUTH_HMAC_SHA256,
+ AUTH_HMAC_SHA384,
+ AUTH_HMAC_SHA512,
+ AUTH_AES_XCBC,
+ AUTH_AES_CMAC,
+ AUTH_CRYPT_AES_GCM,
+ AUTH_CRYPT_CHACHA20_POLY1305
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AlgorithmName {}
+
+ /** @hide */
+ @VisibleForTesting
+ public static final Map<String, Integer> ALGO_TO_REQUIRED_FIRST_SDK = new HashMap<>();
+
+ private static final int SDK_VERSION_ZERO = 0;
+
+ static {
+ ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CBC, SDK_VERSION_ZERO);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_MD5, SDK_VERSION_ZERO);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA1, SDK_VERSION_ZERO);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA256, SDK_VERSION_ZERO);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA384, SDK_VERSION_ZERO);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO);
+
+ ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.S);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.S);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.S);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.S);
+ }
+
+ private static final Set<String> ENABLED_ALGOS =
+ Collections.unmodifiableSet(loadAlgos(Resources.getSystem()));
+
+ private final String mName;
+ private final byte[] mKey;
+ private final int mTruncLenBits;
+
+ /**
+ * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
+ * defined as constants in this class.
+ *
+ * <p>For algorithms that produce an integrity check value, the truncation length is a required
+ * parameter. See {@link #IpSecAlgorithm(String algorithm, byte[] key, int truncLenBits)}
+ *
+ * @param algorithm name of the algorithm.
+ * @param key key padded to a multiple of 8 bits.
+ * @throws IllegalArgumentException if algorithm or key length is invalid.
+ */
+ public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) {
+ this(algorithm, key, 0);
+ }
+
+ /**
+ * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
+ * defined as constants in this class.
+ *
+ * <p>This constructor only supports algorithms that use a truncation length. i.e.
+ * Authentication and Authenticated Encryption algorithms.
+ *
+ * @param algorithm name of the algorithm.
+ * @param key key padded to a multiple of 8 bits.
+ * @param truncLenBits number of bits of output hash to use.
+ * @throws IllegalArgumentException if algorithm, key length or truncation length is invalid.
+ */
+ public IpSecAlgorithm(
+ @NonNull @AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) {
+ mName = algorithm;
+ mKey = key.clone();
+ mTruncLenBits = truncLenBits;
+ checkValidOrThrow(mName, mKey.length * 8, mTruncLenBits);
+ }
+
+ /** Get the algorithm name */
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ /** Get the key for this algorithm */
+ @NonNull
+ public byte[] getKey() {
+ return mKey.clone();
+ }
+
+ /** Get the truncation length of this algorithm, in bits */
+ public int getTruncationLengthBits() {
+ return mTruncLenBits;
+ }
+
+ /* Parcelable Implementation */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Write to parcel */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mName);
+ out.writeByteArray(mKey);
+ out.writeInt(mTruncLenBits);
+ }
+
+ /** Parcelable Creator */
+ public static final @android.annotation.NonNull Parcelable.Creator<IpSecAlgorithm> CREATOR =
+ new Parcelable.Creator<IpSecAlgorithm>() {
+ public IpSecAlgorithm createFromParcel(Parcel in) {
+ final String name = in.readString();
+ final byte[] key = in.createByteArray();
+ final int truncLenBits = in.readInt();
+
+ return new IpSecAlgorithm(name, key, truncLenBits);
+ }
+
+ public IpSecAlgorithm[] newArray(int size) {
+ return new IpSecAlgorithm[size];
+ }
+ };
+
+ /**
+ * Returns supported IPsec algorithms for the current device.
+ *
+ * <p>Some algorithms may not be supported on old devices. Callers MUST check if an algorithm is
+ * supported before using it.
+ */
+ @NonNull
+ public static Set<String> getSupportedAlgorithms() {
+ return ENABLED_ALGOS;
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public static Set<String> loadAlgos(Resources systemResources) {
+ final Set<String> enabledAlgos = new HashSet<>();
+
+ // Load and validate the optional algorithm resource. Undefined or duplicate algorithms in
+ // the resource are not allowed.
+ final String[] resourceAlgos = systemResources.getStringArray(
+ com.android.internal.R.array.config_optionalIpSecAlgorithms);
+ for (String str : resourceAlgos) {
+ if (!ALGO_TO_REQUIRED_FIRST_SDK.containsKey(str) || !enabledAlgos.add(str)) {
+ // This error should be caught by CTS and never be thrown to API callers
+ throw new IllegalArgumentException("Invalid or repeated algorithm " + str);
+ }
+ }
+
+ for (Entry<String, Integer> entry : ALGO_TO_REQUIRED_FIRST_SDK.entrySet()) {
+ if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= entry.getValue()) {
+ enabledAlgos.add(entry.getKey());
+ }
+ }
+
+ return enabledAlgos;
+ }
+
+ private static void checkValidOrThrow(String name, int keyLen, int truncLen) {
+ final boolean isValidLen;
+ final boolean isValidTruncLen;
+
+ if (!getSupportedAlgorithms().contains(name)) {
+ throw new IllegalArgumentException("Unsupported algorithm: " + name);
+ }
+
+ switch (name) {
+ case CRYPT_AES_CBC:
+ isValidLen = keyLen == 128 || keyLen == 192 || keyLen == 256;
+ isValidTruncLen = true;
+ break;
+ case CRYPT_AES_CTR:
+ // The keying material for AES-CTR is a key plus a 32-bit salt
+ isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32;
+ isValidTruncLen = true;
+ break;
+ case AUTH_HMAC_MD5:
+ isValidLen = keyLen == 128;
+ isValidTruncLen = truncLen >= 96 && truncLen <= 128;
+ break;
+ case AUTH_HMAC_SHA1:
+ isValidLen = keyLen == 160;
+ isValidTruncLen = truncLen >= 96 && truncLen <= 160;
+ break;
+ case AUTH_HMAC_SHA256:
+ isValidLen = keyLen == 256;
+ isValidTruncLen = truncLen >= 96 && truncLen <= 256;
+ break;
+ case AUTH_HMAC_SHA384:
+ isValidLen = keyLen == 384;
+ isValidTruncLen = truncLen >= 192 && truncLen <= 384;
+ break;
+ case AUTH_HMAC_SHA512:
+ isValidLen = keyLen == 512;
+ isValidTruncLen = truncLen >= 256 && truncLen <= 512;
+ break;
+ case AUTH_AES_XCBC:
+ isValidLen = keyLen == 128;
+ isValidTruncLen = truncLen == 96;
+ break;
+ case AUTH_AES_CMAC:
+ isValidLen = keyLen == 128;
+ isValidTruncLen = truncLen == 96;
+ break;
+ case AUTH_CRYPT_AES_GCM:
+ // The keying material for GCM is a key plus a 32-bit salt
+ isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32;
+ isValidTruncLen = truncLen == 64 || truncLen == 96 || truncLen == 128;
+ break;
+ case AUTH_CRYPT_CHACHA20_POLY1305:
+ // The keying material for ChaCha20Poly1305 is a key plus a 32-bit salt
+ isValidLen = keyLen == 256 + 32;
+ isValidTruncLen = truncLen == 128;
+ break;
+ default:
+ // Should never hit here.
+ throw new IllegalArgumentException("Couldn't find an algorithm: " + name);
+ }
+
+ if (!isValidLen) {
+ throw new IllegalArgumentException("Invalid key material keyLength: " + keyLen);
+ }
+ if (!isValidTruncLen) {
+ throw new IllegalArgumentException("Invalid truncation keyLength: " + truncLen);
+ }
+ }
+
+ /** @hide */
+ public boolean isAuthentication() {
+ switch (getName()) {
+ // Fallthrough
+ case AUTH_HMAC_MD5:
+ case AUTH_HMAC_SHA1:
+ case AUTH_HMAC_SHA256:
+ case AUTH_HMAC_SHA384:
+ case AUTH_HMAC_SHA512:
+ case AUTH_AES_XCBC:
+ case AUTH_AES_CMAC:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /** @hide */
+ public boolean isEncryption() {
+ switch (getName()) {
+ case CRYPT_AES_CBC: // fallthrough
+ case CRYPT_AES_CTR:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /** @hide */
+ public boolean isAead() {
+ switch (getName()) {
+ case AUTH_CRYPT_AES_GCM: // fallthrough
+ case AUTH_CRYPT_CHACHA20_POLY1305:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ // Because encryption keys are sensitive and userdebug builds are used by large user pools
+ // such as beta testers, we only allow sensitive info such as keys on eng builds.
+ private static boolean isUnsafeBuild() {
+ return Build.IS_DEBUGGABLE && Build.IS_ENG;
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return new StringBuilder()
+ .append("{mName=")
+ .append(mName)
+ .append(", mKey=")
+ .append(isUnsafeBuild() ? HexDump.toHexString(mKey) : "<hidden>")
+ .append(", mTruncLenBits=")
+ .append(mTruncLenBits)
+ .append("}")
+ .toString();
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public static boolean equals(IpSecAlgorithm lhs, IpSecAlgorithm rhs) {
+ if (lhs == null || rhs == null) return (lhs == rhs);
+ return (lhs.mName.equals(rhs.mName)
+ && Arrays.equals(lhs.mKey, rhs.mKey)
+ && lhs.mTruncLenBits == rhs.mTruncLenBits);
+ }
+};