blob: 38d9883f0003b4b71b67d5a8be0b68479665194d [file] [log] [blame]
Nathan Harold330e1082017-01-12 18:38:57 -08001/*
2 * Copyright (C) 2017 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 */
16package android.net;
17
Jonathan Basseric61b70d2017-04-21 15:53:51 -070018import android.annotation.NonNull;
Nathan Harold330e1082017-01-12 18:38:57 -080019import android.annotation.StringDef;
ludib0c95b12017-05-22 10:52:23 -070020import android.os.Build;
Nathan Harold330e1082017-01-12 18:38:57 -080021import android.os.Parcel;
22import android.os.Parcelable;
Nathan Haroldb7282172017-09-11 19:50:19 -070023
Nathan Harold3349b262017-11-09 16:49:33 -080024import com.android.internal.annotations.VisibleForTesting;
ludib0c95b12017-05-22 10:52:23 -070025import com.android.internal.util.HexDump;
Nathan Haroldb7282172017-09-11 19:50:19 -070026
Nathan Harold330e1082017-01-12 18:38:57 -080027import java.lang.annotation.Retention;
28import java.lang.annotation.RetentionPolicy;
Nathan Harold19ce70b2017-09-25 19:33:13 -070029import java.util.Arrays;
Nathan Harold330e1082017-01-12 18:38:57 -080030
31/**
Jonathan Basseric61b70d2017-04-21 15:53:51 -070032 * This class represents a single algorithm that can be used by an {@link IpSecTransform}.
33 *
34 * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
35 * Internet Protocol</a>
Nathan Harold330e1082017-01-12 18:38:57 -080036 */
37public final class IpSecAlgorithm implements Parcelable {
Nathan Harold3349b262017-11-09 16:49:33 -080038 private static final String TAG = "IpSecAlgorithm";
39
Nathan Harold330e1082017-01-12 18:38:57 -080040 /**
Benedict Wongbf013a32018-03-15 19:41:41 -070041 * Null cipher.
42 *
43 * @hide
44 */
45 public static final String CRYPT_NULL = "ecb(cipher_null)";
46
47 /**
Nathan Harold330e1082017-01-12 18:38:57 -080048 * AES-CBC Encryption/Ciphering Algorithm.
49 *
50 * <p>Valid lengths for this key are {128, 192, 256}.
51 */
Nathan Harold60454292017-04-06 18:16:28 -070052 public static final String CRYPT_AES_CBC = "cbc(aes)";
Nathan Harold330e1082017-01-12 18:38:57 -080053
54 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -070055 * MD5 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
56 * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
Nathan Harold330e1082017-01-12 18:38:57 -080057 *
Nathan Harold3349b262017-11-09 16:49:33 -080058 * <p>Keys for this algorithm must be 128 bits in length.
Benedict Wongbb7f2822018-03-28 13:10:40 -070059 *
60 * <p>Valid truncation lengths are multiples of 8 bits from 96 to 128.
Nathan Harold330e1082017-01-12 18:38:57 -080061 */
Nathan Harold60454292017-04-06 18:16:28 -070062 public static final String AUTH_HMAC_MD5 = "hmac(md5)";
Nathan Harold330e1082017-01-12 18:38:57 -080063
64 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -070065 * SHA1 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
66 * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
Nathan Harold330e1082017-01-12 18:38:57 -080067 *
Nathan Harold3349b262017-11-09 16:49:33 -080068 * <p>Keys for this algorithm must be 160 bits in length.
Benedict Wongbb7f2822018-03-28 13:10:40 -070069 *
70 * <p>Valid truncation lengths are multiples of 8 bits from 96 to 160.
Nathan Harold330e1082017-01-12 18:38:57 -080071 */
Nathan Harold60454292017-04-06 18:16:28 -070072 public static final String AUTH_HMAC_SHA1 = "hmac(sha1)";
Nathan Harold330e1082017-01-12 18:38:57 -080073
74 /**
75 * SHA256 HMAC Authentication/Integrity Algorithm.
76 *
Nathan Harold3349b262017-11-09 16:49:33 -080077 * <p>Keys for this algorithm must be 256 bits in length.
Benedict Wongbb7f2822018-03-28 13:10:40 -070078 *
79 * <p>Valid truncation lengths are multiples of 8 bits from 96 to 256.
Nathan Harold330e1082017-01-12 18:38:57 -080080 */
Nathan Harold60454292017-04-06 18:16:28 -070081 public static final String AUTH_HMAC_SHA256 = "hmac(sha256)";
Nathan Harold330e1082017-01-12 18:38:57 -080082
83 /**
84 * SHA384 HMAC Authentication/Integrity Algorithm.
85 *
Nathan Harold3349b262017-11-09 16:49:33 -080086 * <p>Keys for this algorithm must be 384 bits in length.
Benedict Wongbb7f2822018-03-28 13:10:40 -070087 *
88 * <p>Valid truncation lengths are multiples of 8 bits from 192 to 384.
Nathan Harold330e1082017-01-12 18:38:57 -080089 */
Nathan Harold60454292017-04-06 18:16:28 -070090 public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
Benedict Wong0febe5e2017-08-22 21:42:33 -070091
Nathan Harold330e1082017-01-12 18:38:57 -080092 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -070093 * SHA512 HMAC Authentication/Integrity Algorithm.
Nathan Harold330e1082017-01-12 18:38:57 -080094 *
Nathan Harold3349b262017-11-09 16:49:33 -080095 * <p>Keys for this algorithm must be 512 bits in length.
Benedict Wongbb7f2822018-03-28 13:10:40 -070096 *
97 * <p>Valid truncation lengths are multiples of 8 bits from 256 to 512.
Nathan Harold330e1082017-01-12 18:38:57 -080098 */
Nathan Harold60454292017-04-06 18:16:28 -070099 public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
Nathan Harold330e1082017-01-12 18:38:57 -0800100
Benedict Wong0febe5e2017-08-22 21:42:33 -0700101 /**
102 * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm.
103 *
Benedict Wong4ebc2c52017-11-01 17:14:25 -0700104 * <p>Valid lengths for keying material are {160, 224, 288}.
105 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700106 * <p>As per <a href="https://tools.ietf.org/html/rfc4106#section-8.1">RFC4106 (Section
107 * 8.1)</a>, keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit
108 * salt. RFC compliance requires that the salt must be unique per invocation with the same key.
Benedict Wong0febe5e2017-08-22 21:42:33 -0700109 *
110 * <p>Valid ICV (truncation) lengths are {64, 96, 128}.
111 */
112 public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
113
Nathan Harold330e1082017-01-12 18:38:57 -0800114 /** @hide */
Benedict Wong0febe5e2017-08-22 21:42:33 -0700115 @StringDef({
116 CRYPT_AES_CBC,
117 AUTH_HMAC_MD5,
118 AUTH_HMAC_SHA1,
119 AUTH_HMAC_SHA256,
Benedict Wongbb7f2822018-03-28 13:10:40 -0700120 AUTH_HMAC_SHA384,
Benedict Wong0febe5e2017-08-22 21:42:33 -0700121 AUTH_HMAC_SHA512,
122 AUTH_CRYPT_AES_GCM
123 })
Nathan Harold330e1082017-01-12 18:38:57 -0800124 @Retention(RetentionPolicy.SOURCE)
125 public @interface AlgorithmName {}
126
127 private final String mName;
128 private final byte[] mKey;
129 private final int mTruncLenBits;
130
131 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700132 * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
133 * defined as constants in this class.
Nathan Harold330e1082017-01-12 18:38:57 -0800134 *
Benedict Wongbb7f2822018-03-28 13:10:40 -0700135 * <p>For algorithms that produce an integrity check value, the truncation length is a required
136 * parameter. See {@link #IpSecAlgorithm(String algorithm, byte[] key, int truncLenBits)}
137 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700138 * @param algorithm name of the algorithm.
139 * @param key key padded to a multiple of 8 bits.
Nathan Harold330e1082017-01-12 18:38:57 -0800140 */
Nathan Harold8fd26f62018-03-16 17:27:30 -0700141 public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) {
Benedict Wongbb7f2822018-03-28 13:10:40 -0700142 this(algorithm, key, 0);
Nathan Harold330e1082017-01-12 18:38:57 -0800143 }
144
145 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700146 * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
147 * defined as constants in this class.
Nathan Harold330e1082017-01-12 18:38:57 -0800148 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700149 * <p>This constructor only supports algorithms that use a truncation length. i.e.
150 * Authentication and Authenticated Encryption algorithms.
151 *
152 * @param algorithm name of the algorithm.
153 * @param key key padded to a multiple of 8 bits.
154 * @param truncLenBits number of bits of output hash to use.
Nathan Harold330e1082017-01-12 18:38:57 -0800155 */
Nathan Harold8fd26f62018-03-16 17:27:30 -0700156 public IpSecAlgorithm(
157 @NonNull @AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) {
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700158 mName = algorithm;
Nathan Harold330e1082017-01-12 18:38:57 -0800159 mKey = key.clone();
Nathan Harold3349b262017-11-09 16:49:33 -0800160 mTruncLenBits = truncLenBits;
161 checkValidOrThrow(mName, mKey.length * 8, mTruncLenBits);
Nathan Harold330e1082017-01-12 18:38:57 -0800162 }
163
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700164 /** Get the algorithm name */
Nathan Harold8fd26f62018-03-16 17:27:30 -0700165 @NonNull
Nathan Harold330e1082017-01-12 18:38:57 -0800166 public String getName() {
167 return mName;
168 }
169
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700170 /** Get the key for this algorithm */
Nathan Harold8fd26f62018-03-16 17:27:30 -0700171 @NonNull
Nathan Harold330e1082017-01-12 18:38:57 -0800172 public byte[] getKey() {
173 return mKey.clone();
174 }
175
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700176 /** Get the truncation length of this algorithm, in bits */
Nathan Harold330e1082017-01-12 18:38:57 -0800177 public int getTruncationLengthBits() {
178 return mTruncLenBits;
179 }
180
181 /* Parcelable Implementation */
182 public int describeContents() {
183 return 0;
184 }
185
186 /** Write to parcel */
187 public void writeToParcel(Parcel out, int flags) {
188 out.writeString(mName);
189 out.writeByteArray(mKey);
190 out.writeInt(mTruncLenBits);
191 }
192
193 /** Parcelable Creator */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700194 public static final @android.annotation.NonNull Parcelable.Creator<IpSecAlgorithm> CREATOR =
Nathan Harold330e1082017-01-12 18:38:57 -0800195 new Parcelable.Creator<IpSecAlgorithm>() {
196 public IpSecAlgorithm createFromParcel(Parcel in) {
Nathan Harold3349b262017-11-09 16:49:33 -0800197 final String name = in.readString();
198 final byte[] key = in.createByteArray();
199 final int truncLenBits = in.readInt();
200
201 return new IpSecAlgorithm(name, key, truncLenBits);
Nathan Harold330e1082017-01-12 18:38:57 -0800202 }
203
204 public IpSecAlgorithm[] newArray(int size) {
205 return new IpSecAlgorithm[size];
206 }
207 };
208
Nathan Harold3349b262017-11-09 16:49:33 -0800209 private static void checkValidOrThrow(String name, int keyLen, int truncLen) {
210 boolean isValidLen = true;
211 boolean isValidTruncLen = true;
Nathan Harold330e1082017-01-12 18:38:57 -0800212
Nathan Harold3349b262017-11-09 16:49:33 -0800213 switch(name) {
Nathan Harold60454292017-04-06 18:16:28 -0700214 case CRYPT_AES_CBC:
Nathan Harold3349b262017-11-09 16:49:33 -0800215 isValidLen = keyLen == 128 || keyLen == 192 || keyLen == 256;
216 break;
Nathan Harold60454292017-04-06 18:16:28 -0700217 case AUTH_HMAC_MD5:
Nathan Harold3349b262017-11-09 16:49:33 -0800218 isValidLen = keyLen == 128;
219 isValidTruncLen = truncLen >= 96 && truncLen <= 128;
220 break;
Nathan Harold60454292017-04-06 18:16:28 -0700221 case AUTH_HMAC_SHA1:
Nathan Harold3349b262017-11-09 16:49:33 -0800222 isValidLen = keyLen == 160;
223 isValidTruncLen = truncLen >= 96 && truncLen <= 160;
224 break;
Nathan Harold60454292017-04-06 18:16:28 -0700225 case AUTH_HMAC_SHA256:
Nathan Harold3349b262017-11-09 16:49:33 -0800226 isValidLen = keyLen == 256;
227 isValidTruncLen = truncLen >= 96 && truncLen <= 256;
228 break;
Nathan Harold60454292017-04-06 18:16:28 -0700229 case AUTH_HMAC_SHA384:
Nathan Harold3349b262017-11-09 16:49:33 -0800230 isValidLen = keyLen == 384;
231 isValidTruncLen = truncLen >= 192 && truncLen <= 384;
232 break;
Nathan Harold60454292017-04-06 18:16:28 -0700233 case AUTH_HMAC_SHA512:
Nathan Harold3349b262017-11-09 16:49:33 -0800234 isValidLen = keyLen == 512;
235 isValidTruncLen = truncLen >= 256 && truncLen <= 512;
236 break;
Benedict Wong0febe5e2017-08-22 21:42:33 -0700237 case AUTH_CRYPT_AES_GCM:
Nathan Harold3349b262017-11-09 16:49:33 -0800238 // The keying material for GCM is a key plus a 32-bit salt
239 isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32;
Benedict Wongbb7f2822018-03-28 13:10:40 -0700240 isValidTruncLen = truncLen == 64 || truncLen == 96 || truncLen == 128;
Nathan Harold3349b262017-11-09 16:49:33 -0800241 break;
Nathan Harold330e1082017-01-12 18:38:57 -0800242 default:
Nathan Harold3349b262017-11-09 16:49:33 -0800243 throw new IllegalArgumentException("Couldn't find an algorithm: " + name);
244 }
245
246 if (!isValidLen) {
247 throw new IllegalArgumentException("Invalid key material keyLength: " + keyLen);
248 }
249 if (!isValidTruncLen) {
250 throw new IllegalArgumentException("Invalid truncation keyLength: " + truncLen);
Nathan Harold330e1082017-01-12 18:38:57 -0800251 }
252 }
ludib0c95b12017-05-22 10:52:23 -0700253
Benedict Wong4f255702017-11-06 20:49:10 -0800254 /** @hide */
255 public boolean isAuthentication() {
256 switch (getName()) {
257 // Fallthrough
258 case AUTH_HMAC_MD5:
259 case AUTH_HMAC_SHA1:
260 case AUTH_HMAC_SHA256:
261 case AUTH_HMAC_SHA384:
262 case AUTH_HMAC_SHA512:
263 return true;
264 default:
265 return false;
266 }
267 }
268
269 /** @hide */
270 public boolean isEncryption() {
271 return getName().equals(CRYPT_AES_CBC);
272 }
273
274 /** @hide */
275 public boolean isAead() {
276 return getName().equals(AUTH_CRYPT_AES_GCM);
277 }
278
Nathan Harolda2523312018-01-05 19:25:13 -0800279 // Because encryption keys are sensitive and userdebug builds are used by large user pools
280 // such as beta testers, we only allow sensitive info such as keys on eng builds.
281 private static boolean isUnsafeBuild() {
282 return Build.IS_DEBUGGABLE && Build.IS_ENG;
283 }
284
ludib0c95b12017-05-22 10:52:23 -0700285 @Override
Nathan Harold8fd26f62018-03-16 17:27:30 -0700286 @NonNull
ludib0c95b12017-05-22 10:52:23 -0700287 public String toString() {
288 return new StringBuilder()
289 .append("{mName=")
290 .append(mName)
291 .append(", mKey=")
Nathan Harolda2523312018-01-05 19:25:13 -0800292 .append(isUnsafeBuild() ? HexDump.toHexString(mKey) : "<hidden>")
ludib0c95b12017-05-22 10:52:23 -0700293 .append(", mTruncLenBits=")
294 .append(mTruncLenBits)
295 .append("}")
296 .toString();
297 }
Nathan Harold19ce70b2017-09-25 19:33:13 -0700298
Nathan Harold3349b262017-11-09 16:49:33 -0800299 /** @hide */
300 @VisibleForTesting
301 public static boolean equals(IpSecAlgorithm lhs, IpSecAlgorithm rhs) {
Nathan Harold19ce70b2017-09-25 19:33:13 -0700302 if (lhs == null || rhs == null) return (lhs == rhs);
303 return (lhs.mName.equals(rhs.mName)
304 && Arrays.equals(lhs.mKey, rhs.mKey)
305 && lhs.mTruncLenBits == rhs.mTruncLenBits);
306 }
Nathan Harold330e1082017-01-12 18:38:57 -0800307};