blob: c69a4d4c0beed39dbc8f7a73e7506b507739238f [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 /**
41 * AES-CBC Encryption/Ciphering Algorithm.
42 *
43 * <p>Valid lengths for this key are {128, 192, 256}.
44 */
Nathan Harold60454292017-04-06 18:16:28 -070045 public static final String CRYPT_AES_CBC = "cbc(aes)";
Nathan Harold330e1082017-01-12 18:38:57 -080046
47 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -070048 * MD5 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
49 * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
Nathan Harold330e1082017-01-12 18:38:57 -080050 *
Nathan Harold3349b262017-11-09 16:49:33 -080051 * <p>Keys for this algorithm must be 128 bits in length.
Nathan Harold330e1082017-01-12 18:38:57 -080052 * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128.
53 */
Nathan Harold60454292017-04-06 18:16:28 -070054 public static final String AUTH_HMAC_MD5 = "hmac(md5)";
Nathan Harold330e1082017-01-12 18:38:57 -080055
56 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -070057 * SHA1 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
58 * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
Nathan Harold330e1082017-01-12 18:38:57 -080059 *
Nathan Harold3349b262017-11-09 16:49:33 -080060 * <p>Keys for this algorithm must be 160 bits in length.
Nathan Harold330e1082017-01-12 18:38:57 -080061 * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160.
62 */
Nathan Harold60454292017-04-06 18:16:28 -070063 public static final String AUTH_HMAC_SHA1 = "hmac(sha1)";
Nathan Harold330e1082017-01-12 18:38:57 -080064
65 /**
66 * SHA256 HMAC Authentication/Integrity Algorithm.
67 *
Nathan Harold3349b262017-11-09 16:49:33 -080068 * <p>Keys for this algorithm must be 256 bits in length.
Nathan Harold330e1082017-01-12 18:38:57 -080069 * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 256.
70 */
Nathan Harold60454292017-04-06 18:16:28 -070071 public static final String AUTH_HMAC_SHA256 = "hmac(sha256)";
Nathan Harold330e1082017-01-12 18:38:57 -080072
73 /**
74 * SHA384 HMAC Authentication/Integrity Algorithm.
75 *
Nathan Harold3349b262017-11-09 16:49:33 -080076 * <p>Keys for this algorithm must be 384 bits in length.
Nathan Harold330e1082017-01-12 18:38:57 -080077 * <p>Valid truncation lengths are multiples of 8 bits from 192 to (default) 384.
78 */
Nathan Harold60454292017-04-06 18:16:28 -070079 public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
Benedict Wong0febe5e2017-08-22 21:42:33 -070080
Nathan Harold330e1082017-01-12 18:38:57 -080081 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -070082 * SHA512 HMAC Authentication/Integrity Algorithm.
Nathan Harold330e1082017-01-12 18:38:57 -080083 *
Nathan Harold3349b262017-11-09 16:49:33 -080084 * <p>Keys for this algorithm must be 512 bits in length.
Nathan Harold330e1082017-01-12 18:38:57 -080085 * <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512.
86 */
Nathan Harold60454292017-04-06 18:16:28 -070087 public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
Nathan Harold330e1082017-01-12 18:38:57 -080088
Benedict Wong0febe5e2017-08-22 21:42:33 -070089 /**
90 * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm.
91 *
Benedict Wong4ebc2c52017-11-01 17:14:25 -070092 * <p>Valid lengths for keying material are {160, 224, 288}.
93 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -070094 * <p>As per <a href="https://tools.ietf.org/html/rfc4106#section-8.1">RFC4106 (Section
95 * 8.1)</a>, keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit
96 * salt. RFC compliance requires that the salt must be unique per invocation with the same key.
Benedict Wong0febe5e2017-08-22 21:42:33 -070097 *
98 * <p>Valid ICV (truncation) lengths are {64, 96, 128}.
99 */
100 public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
101
Nathan Harold330e1082017-01-12 18:38:57 -0800102 /** @hide */
Benedict Wong0febe5e2017-08-22 21:42:33 -0700103 @StringDef({
104 CRYPT_AES_CBC,
105 AUTH_HMAC_MD5,
106 AUTH_HMAC_SHA1,
107 AUTH_HMAC_SHA256,
108 AUTH_HMAC_SHA512,
109 AUTH_CRYPT_AES_GCM
110 })
Nathan Harold330e1082017-01-12 18:38:57 -0800111 @Retention(RetentionPolicy.SOURCE)
112 public @interface AlgorithmName {}
113
114 private final String mName;
115 private final byte[] mKey;
116 private final int mTruncLenBits;
117
118 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700119 * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
120 * defined as constants in this class.
Nathan Harold330e1082017-01-12 18:38:57 -0800121 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700122 * @param algorithm name of the algorithm.
123 * @param key key padded to a multiple of 8 bits.
Nathan Harold330e1082017-01-12 18:38:57 -0800124 */
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700125 public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key) {
Nathan Harold330e1082017-01-12 18:38:57 -0800126 this(algorithm, key, key.length * 8);
127 }
128
129 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700130 * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
131 * defined as constants in this class.
Nathan Harold330e1082017-01-12 18:38:57 -0800132 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700133 * <p>This constructor only supports algorithms that use a truncation length. i.e.
134 * Authentication and Authenticated Encryption algorithms.
135 *
136 * @param algorithm name of the algorithm.
137 * @param key key padded to a multiple of 8 bits.
138 * @param truncLenBits number of bits of output hash to use.
Nathan Harold330e1082017-01-12 18:38:57 -0800139 */
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700140 public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) {
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700141 mName = algorithm;
Nathan Harold330e1082017-01-12 18:38:57 -0800142 mKey = key.clone();
Nathan Harold3349b262017-11-09 16:49:33 -0800143 mTruncLenBits = truncLenBits;
144 checkValidOrThrow(mName, mKey.length * 8, mTruncLenBits);
Nathan Harold330e1082017-01-12 18:38:57 -0800145 }
146
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700147 /** Get the algorithm name */
Nathan Harold330e1082017-01-12 18:38:57 -0800148 public String getName() {
149 return mName;
150 }
151
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700152 /** Get the key for this algorithm */
Nathan Harold330e1082017-01-12 18:38:57 -0800153 public byte[] getKey() {
154 return mKey.clone();
155 }
156
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700157 /** Get the truncation length of this algorithm, in bits */
Nathan Harold330e1082017-01-12 18:38:57 -0800158 public int getTruncationLengthBits() {
159 return mTruncLenBits;
160 }
161
162 /* Parcelable Implementation */
163 public int describeContents() {
164 return 0;
165 }
166
167 /** Write to parcel */
168 public void writeToParcel(Parcel out, int flags) {
169 out.writeString(mName);
170 out.writeByteArray(mKey);
171 out.writeInt(mTruncLenBits);
172 }
173
174 /** Parcelable Creator */
175 public static final Parcelable.Creator<IpSecAlgorithm> CREATOR =
176 new Parcelable.Creator<IpSecAlgorithm>() {
177 public IpSecAlgorithm createFromParcel(Parcel in) {
Nathan Harold3349b262017-11-09 16:49:33 -0800178 final String name = in.readString();
179 final byte[] key = in.createByteArray();
180 final int truncLenBits = in.readInt();
181
182 return new IpSecAlgorithm(name, key, truncLenBits);
Nathan Harold330e1082017-01-12 18:38:57 -0800183 }
184
185 public IpSecAlgorithm[] newArray(int size) {
186 return new IpSecAlgorithm[size];
187 }
188 };
189
Nathan Harold3349b262017-11-09 16:49:33 -0800190 private static void checkValidOrThrow(String name, int keyLen, int truncLen) {
191 boolean isValidLen = true;
192 boolean isValidTruncLen = true;
Nathan Harold330e1082017-01-12 18:38:57 -0800193
Nathan Harold3349b262017-11-09 16:49:33 -0800194 switch(name) {
Nathan Harold60454292017-04-06 18:16:28 -0700195 case CRYPT_AES_CBC:
Nathan Harold3349b262017-11-09 16:49:33 -0800196 isValidLen = keyLen == 128 || keyLen == 192 || keyLen == 256;
197 break;
Nathan Harold60454292017-04-06 18:16:28 -0700198 case AUTH_HMAC_MD5:
Nathan Harold3349b262017-11-09 16:49:33 -0800199 isValidLen = keyLen == 128;
200 isValidTruncLen = truncLen >= 96 && truncLen <= 128;
201 break;
Nathan Harold60454292017-04-06 18:16:28 -0700202 case AUTH_HMAC_SHA1:
Nathan Harold3349b262017-11-09 16:49:33 -0800203 isValidLen = keyLen == 160;
204 isValidTruncLen = truncLen >= 96 && truncLen <= 160;
205 break;
Nathan Harold60454292017-04-06 18:16:28 -0700206 case AUTH_HMAC_SHA256:
Nathan Harold3349b262017-11-09 16:49:33 -0800207 isValidLen = keyLen == 256;
208 isValidTruncLen = truncLen >= 96 && truncLen <= 256;
209 break;
Nathan Harold60454292017-04-06 18:16:28 -0700210 case AUTH_HMAC_SHA384:
Nathan Harold3349b262017-11-09 16:49:33 -0800211 isValidLen = keyLen == 384;
212 isValidTruncLen = truncLen >= 192 && truncLen <= 384;
213 break;
Nathan Harold60454292017-04-06 18:16:28 -0700214 case AUTH_HMAC_SHA512:
Nathan Harold3349b262017-11-09 16:49:33 -0800215 isValidLen = keyLen == 512;
216 isValidTruncLen = truncLen >= 256 && truncLen <= 512;
217 break;
Benedict Wong0febe5e2017-08-22 21:42:33 -0700218 case AUTH_CRYPT_AES_GCM:
Nathan Harold3349b262017-11-09 16:49:33 -0800219 // The keying material for GCM is a key plus a 32-bit salt
220 isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32;
221 break;
Nathan Harold330e1082017-01-12 18:38:57 -0800222 default:
Nathan Harold3349b262017-11-09 16:49:33 -0800223 throw new IllegalArgumentException("Couldn't find an algorithm: " + name);
224 }
225
226 if (!isValidLen) {
227 throw new IllegalArgumentException("Invalid key material keyLength: " + keyLen);
228 }
229 if (!isValidTruncLen) {
230 throw new IllegalArgumentException("Invalid truncation keyLength: " + truncLen);
Nathan Harold330e1082017-01-12 18:38:57 -0800231 }
232 }
ludib0c95b12017-05-22 10:52:23 -0700233
Benedict Wong4f255702017-11-06 20:49:10 -0800234 /** @hide */
235 public boolean isAuthentication() {
236 switch (getName()) {
237 // Fallthrough
238 case AUTH_HMAC_MD5:
239 case AUTH_HMAC_SHA1:
240 case AUTH_HMAC_SHA256:
241 case AUTH_HMAC_SHA384:
242 case AUTH_HMAC_SHA512:
243 return true;
244 default:
245 return false;
246 }
247 }
248
249 /** @hide */
250 public boolean isEncryption() {
251 return getName().equals(CRYPT_AES_CBC);
252 }
253
254 /** @hide */
255 public boolean isAead() {
256 return getName().equals(AUTH_CRYPT_AES_GCM);
257 }
258
Nathan Harolda2523312018-01-05 19:25:13 -0800259 // Because encryption keys are sensitive and userdebug builds are used by large user pools
260 // such as beta testers, we only allow sensitive info such as keys on eng builds.
261 private static boolean isUnsafeBuild() {
262 return Build.IS_DEBUGGABLE && Build.IS_ENG;
263 }
264
ludib0c95b12017-05-22 10:52:23 -0700265 @Override
266 public String toString() {
267 return new StringBuilder()
268 .append("{mName=")
269 .append(mName)
270 .append(", mKey=")
Nathan Harolda2523312018-01-05 19:25:13 -0800271 .append(isUnsafeBuild() ? HexDump.toHexString(mKey) : "<hidden>")
ludib0c95b12017-05-22 10:52:23 -0700272 .append(", mTruncLenBits=")
273 .append(mTruncLenBits)
274 .append("}")
275 .toString();
276 }
Nathan Harold19ce70b2017-09-25 19:33:13 -0700277
Nathan Harold3349b262017-11-09 16:49:33 -0800278 /** @hide */
279 @VisibleForTesting
280 public static boolean equals(IpSecAlgorithm lhs, IpSecAlgorithm rhs) {
Nathan Harold19ce70b2017-09-25 19:33:13 -0700281 if (lhs == null || rhs == null) return (lhs == rhs);
282 return (lhs.mName.equals(rhs.mName)
283 && Arrays.equals(lhs.mKey, rhs.mKey)
284 && lhs.mTruncLenBits == rhs.mTruncLenBits);
285 }
Nathan Harold330e1082017-01-12 18:38:57 -0800286};