1 /* 2 * Copyright (C) 2018 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.ipsec.ike; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.SystemApi; 22 import android.util.Pair; 23 import android.util.SparseArray; 24 25 import com.android.internal.net.ipsec.ike.message.IkePayload; 26 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.DhGroupTransform; 27 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform; 28 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform; 29 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform; 30 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.Transform; 31 32 import java.lang.annotation.Retention; 33 import java.lang.annotation.RetentionPolicy; 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.LinkedHashSet; 37 import java.util.LinkedList; 38 import java.util.List; 39 40 /** 41 * SaProposal represents a proposed configuration to negotiate an IKE or Child SA. 42 * 43 * <p>SaProposal will contain cryptograhic algorithms and key generation materials for the 44 * negotiation of an IKE or Child SA. 45 * 46 * <p>User must provide at least one valid SaProposal when they are creating a new IKE or Child SA. 47 * 48 * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key Exchange 49 * Protocol Version 2 (IKEv2)</a> 50 * @hide 51 */ 52 @SystemApi 53 public abstract class SaProposal { 54 /** @hide */ 55 @Retention(RetentionPolicy.SOURCE) 56 @IntDef({ 57 ENCRYPTION_ALGORITHM_3DES, 58 ENCRYPTION_ALGORITHM_AES_CBC, 59 ENCRYPTION_ALGORITHM_AES_GCM_8, 60 ENCRYPTION_ALGORITHM_AES_GCM_12, 61 ENCRYPTION_ALGORITHM_AES_GCM_16 62 }) 63 public @interface EncryptionAlgorithm {} 64 65 /** 3DES Encryption/Ciphering Algorithm. */ 66 public static final int ENCRYPTION_ALGORITHM_3DES = 3; 67 /** AES-CBC Encryption/Ciphering Algorithm. */ 68 public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; 69 /** 70 * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm with 8-octet ICV 71 * (truncation). 72 */ 73 public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 = 18; 74 /** 75 * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm with 12-octet ICV 76 * (truncation). 77 */ 78 public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 = 19; 79 /** 80 * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm with 16-octet ICV 81 * (truncation). 82 */ 83 public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 = 20; 84 85 private static final SparseArray<String> SUPPORTED_ENCRYPTION_ALGO_TO_STR; 86 87 static { 88 SUPPORTED_ENCRYPTION_ALGO_TO_STR = new SparseArray<>(); SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_3DES, "ENCR_3DES")89 SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_3DES, "ENCR_3DES"); SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_AES_CBC, "ENCR_AES_CBC")90 SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_AES_CBC, "ENCR_AES_CBC"); SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_AES_GCM_8, "ENCR_AES_GCM_8")91 SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_AES_GCM_8, "ENCR_AES_GCM_8"); SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_AES_GCM_12, "ENCR_AES_GCM_12")92 SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_AES_GCM_12, "ENCR_AES_GCM_12"); SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_AES_GCM_16, "ENCR_AES_GCM_16")93 SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_AES_GCM_16, "ENCR_AES_GCM_16"); 94 } 95 96 /** 97 * Key length unused. 98 * 99 * <p>This value should only be used with the Encryption/Ciphering Algorithm that accepts a 100 * fixed key size such as {@link ENCRYPTION_ALGORITHM_3DES}. 101 */ 102 public static final int KEY_LEN_UNUSED = 0; 103 /** AES Encryption/Ciphering Algorithm key length 128 bits. */ 104 public static final int KEY_LEN_AES_128 = 128; 105 /** AES Encryption/Ciphering Algorithm key length 192 bits. */ 106 public static final int KEY_LEN_AES_192 = 192; 107 /** AES Encryption/Ciphering Algorithm key length 256 bits. */ 108 public static final int KEY_LEN_AES_256 = 256; 109 110 /** @hide */ 111 @Retention(RetentionPolicy.SOURCE) 112 @IntDef({ 113 PSEUDORANDOM_FUNCTION_HMAC_SHA1, 114 PSEUDORANDOM_FUNCTION_AES128_XCBC, 115 PSEUDORANDOM_FUNCTION_SHA2_256, 116 PSEUDORANDOM_FUNCTION_SHA2_384, 117 PSEUDORANDOM_FUNCTION_SHA2_512 118 }) 119 public @interface PseudorandomFunction {} 120 121 /** HMAC-SHA1 Pseudorandom Function. */ 122 public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; 123 /** AES128-XCBC Pseudorandom Function. */ 124 public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; 125 /** HMAC-SHA2-256 Pseudorandom Function. */ 126 public static final int PSEUDORANDOM_FUNCTION_SHA2_256 = 5; 127 /** HMAC-SHA2-384 Pseudorandom Function. */ 128 public static final int PSEUDORANDOM_FUNCTION_SHA2_384 = 6; 129 /** HMAC-SHA2-384 Pseudorandom Function. */ 130 public static final int PSEUDORANDOM_FUNCTION_SHA2_512 = 7; 131 132 private static final SparseArray<String> SUPPORTED_PRF_TO_STR; 133 134 static { 135 SUPPORTED_PRF_TO_STR = new SparseArray<>(); SUPPORTED_PRF_TO_STR.put(PSEUDORANDOM_FUNCTION_HMAC_SHA1, "PRF_HMAC_SHA1")136 SUPPORTED_PRF_TO_STR.put(PSEUDORANDOM_FUNCTION_HMAC_SHA1, "PRF_HMAC_SHA1"); SUPPORTED_PRF_TO_STR.put(PSEUDORANDOM_FUNCTION_AES128_XCBC, "PRF_AES128_XCBC")137 SUPPORTED_PRF_TO_STR.put(PSEUDORANDOM_FUNCTION_AES128_XCBC, "PRF_AES128_XCBC"); SUPPORTED_PRF_TO_STR.put(PSEUDORANDOM_FUNCTION_SHA2_256, "PRF_HMAC2_256")138 SUPPORTED_PRF_TO_STR.put(PSEUDORANDOM_FUNCTION_SHA2_256, "PRF_HMAC2_256"); SUPPORTED_PRF_TO_STR.put(PSEUDORANDOM_FUNCTION_SHA2_384, "PRF_HMAC2_384")139 SUPPORTED_PRF_TO_STR.put(PSEUDORANDOM_FUNCTION_SHA2_384, "PRF_HMAC2_384"); SUPPORTED_PRF_TO_STR.put(PSEUDORANDOM_FUNCTION_SHA2_512, "PRF_HMAC2_512")140 SUPPORTED_PRF_TO_STR.put(PSEUDORANDOM_FUNCTION_SHA2_512, "PRF_HMAC2_512"); 141 } 142 143 /** @hide */ 144 @Retention(RetentionPolicy.SOURCE) 145 @IntDef({ 146 INTEGRITY_ALGORITHM_NONE, 147 INTEGRITY_ALGORITHM_HMAC_SHA1_96, 148 INTEGRITY_ALGORITHM_AES_XCBC_96, 149 INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, 150 INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, 151 INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 152 }) 153 public @interface IntegrityAlgorithm {} 154 155 /** None Authentication/Integrity Algorithm. */ 156 public static final int INTEGRITY_ALGORITHM_NONE = 0; 157 /** HMAC-SHA1 Authentication/Integrity Algorithm. */ 158 public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; 159 /** AES-XCBC-96 Authentication/Integrity Algorithm. */ 160 public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; 161 /** HMAC-SHA256 Authentication/Integrity Algorithm with 128-bit truncation. */ 162 public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; 163 /** HMAC-SHA384 Authentication/Integrity Algorithm with 192-bit truncation. */ 164 public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; 165 /** HMAC-SHA512 Authentication/Integrity Algorithm with 256-bit truncation. */ 166 public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; 167 168 private static final SparseArray<String> SUPPORTED_INTEGRITY_ALGO_TO_STR; 169 170 static { 171 SUPPORTED_INTEGRITY_ALGO_TO_STR = new SparseArray<>(); SUPPORTED_INTEGRITY_ALGO_TO_STR.put(INTEGRITY_ALGORITHM_NONE, "AUTH_NONE")172 SUPPORTED_INTEGRITY_ALGO_TO_STR.put(INTEGRITY_ALGORITHM_NONE, "AUTH_NONE"); SUPPORTED_INTEGRITY_ALGO_TO_STR.put(INTEGRITY_ALGORITHM_HMAC_SHA1_96, "AUTH_HMAC_SHA1_96")173 SUPPORTED_INTEGRITY_ALGO_TO_STR.put(INTEGRITY_ALGORITHM_HMAC_SHA1_96, "AUTH_HMAC_SHA1_96"); SUPPORTED_INTEGRITY_ALGO_TO_STR.put(INTEGRITY_ALGORITHM_AES_XCBC_96, "AUTH_AES_XCBC_96")174 SUPPORTED_INTEGRITY_ALGO_TO_STR.put(INTEGRITY_ALGORITHM_AES_XCBC_96, "AUTH_AES_XCBC_96"); SUPPORTED_INTEGRITY_ALGO_TO_STR.put( INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, "AUTH_HMAC_SHA2_256_128")175 SUPPORTED_INTEGRITY_ALGO_TO_STR.put( 176 INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, "AUTH_HMAC_SHA2_256_128"); SUPPORTED_INTEGRITY_ALGO_TO_STR.put( INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, "AUTH_HMAC_SHA2_384_192")177 SUPPORTED_INTEGRITY_ALGO_TO_STR.put( 178 INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, "AUTH_HMAC_SHA2_384_192"); SUPPORTED_INTEGRITY_ALGO_TO_STR.put( INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, "AUTH_HMAC_SHA2_512_256")179 SUPPORTED_INTEGRITY_ALGO_TO_STR.put( 180 INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, "AUTH_HMAC_SHA2_512_256"); 181 } 182 183 /** @hide */ 184 @Retention(RetentionPolicy.SOURCE) 185 @IntDef({DH_GROUP_NONE, DH_GROUP_1024_BIT_MODP, DH_GROUP_2048_BIT_MODP}) 186 public @interface DhGroup {} 187 188 /** None Diffie-Hellman Group. */ 189 public static final int DH_GROUP_NONE = 0; 190 /** 1024-bit MODP Diffie-Hellman Group. */ 191 public static final int DH_GROUP_1024_BIT_MODP = 2; 192 /** 2048-bit MODP Diffie-Hellman Group. */ 193 public static final int DH_GROUP_2048_BIT_MODP = 14; 194 /** 3072-bit MODP Diffie-Hellman Group. @hide */ 195 public static final int DH_GROUP_3072_BIT_MODP = 15; 196 /** 4096-bit MODP Diffie-Hellman Group. @hide */ 197 public static final int DH_GROUP_4096_BIT_MODP = 16; 198 199 private static final SparseArray<String> SUPPORTED_DH_GROUP_TO_STR; 200 201 static { 202 SUPPORTED_DH_GROUP_TO_STR = new SparseArray<>(); SUPPORTED_DH_GROUP_TO_STR.put(DH_GROUP_NONE, "DH_NONE")203 SUPPORTED_DH_GROUP_TO_STR.put(DH_GROUP_NONE, "DH_NONE"); SUPPORTED_DH_GROUP_TO_STR.put(DH_GROUP_1024_BIT_MODP, "DH_1024_BIT_MODP")204 SUPPORTED_DH_GROUP_TO_STR.put(DH_GROUP_1024_BIT_MODP, "DH_1024_BIT_MODP"); SUPPORTED_DH_GROUP_TO_STR.put(DH_GROUP_2048_BIT_MODP, "DH_2048_BIT_MODP")205 SUPPORTED_DH_GROUP_TO_STR.put(DH_GROUP_2048_BIT_MODP, "DH_2048_BIT_MODP"); SUPPORTED_DH_GROUP_TO_STR.put(DH_GROUP_3072_BIT_MODP, "DH_3072_BIT_MODP")206 SUPPORTED_DH_GROUP_TO_STR.put(DH_GROUP_3072_BIT_MODP, "DH_3072_BIT_MODP"); SUPPORTED_DH_GROUP_TO_STR.put(DH_GROUP_4096_BIT_MODP, "DH_4096_BIT_MODP")207 SUPPORTED_DH_GROUP_TO_STR.put(DH_GROUP_4096_BIT_MODP, "DH_4096_BIT_MODP"); 208 } 209 210 @IkePayload.ProtocolId private final int mProtocolId; 211 private final EncryptionTransform[] mEncryptionAlgorithms; 212 private final IntegrityTransform[] mIntegrityAlgorithms; 213 private final DhGroupTransform[] mDhGroups; 214 215 /** @hide */ SaProposal( @kePayload.ProtocolId int protocol, EncryptionTransform[] encryptionAlgos, IntegrityTransform[] integrityAlgos, DhGroupTransform[] dhGroups)216 protected SaProposal( 217 @IkePayload.ProtocolId int protocol, 218 EncryptionTransform[] encryptionAlgos, 219 IntegrityTransform[] integrityAlgos, 220 DhGroupTransform[] dhGroups) { 221 mProtocolId = protocol; 222 mEncryptionAlgorithms = encryptionAlgos; 223 mIntegrityAlgorithms = integrityAlgos; 224 mDhGroups = dhGroups; 225 } 226 227 /** 228 * Check if the current SaProposal from the SA responder is consistent with the selected 229 * reqProposal from the SA initiator. 230 * 231 * <p>As per RFC 7296, The accepted cryptographic suite MUST contain exactly one transform of 232 * each type included in the proposal. But for interoperability reason, IKE library allows 233 * exceptions when the accepted suite or the request proposal has a NONE value transform. 234 * Currently only IntegrityTransform and DhGroupTransform have NONE value transform ID defined. 235 * 236 * @param reqProposal selected SaProposal from SA initiator 237 * @return if current SaProposal from SA responder is consistent with the selected reqProposal 238 * from SA initiator. 239 * @hide 240 */ isNegotiatedFrom(SaProposal reqProposal)241 public boolean isNegotiatedFrom(SaProposal reqProposal) { 242 return this.mProtocolId == reqProposal.mProtocolId 243 && isTransformSelectedFrom(mEncryptionAlgorithms, reqProposal.mEncryptionAlgorithms) 244 && isIntegrityTransformSelectedFrom( 245 mIntegrityAlgorithms, reqProposal.mIntegrityAlgorithms) 246 && isDhGroupTransformSelectedFrom(mDhGroups, reqProposal.mDhGroups); 247 } 248 249 /** 250 * Check if the response transform can be selected from the request transforms 251 * 252 * <p>Package private 253 */ isTransformSelectedFrom(Transform[] selected, Transform[] selectFrom)254 static boolean isTransformSelectedFrom(Transform[] selected, Transform[] selectFrom) { 255 // If the selected proposal has multiple transforms with the same type, the responder MUST 256 // choose a single one. 257 if ((selected.length > 1) || (selected.length == 0) != (selectFrom.length == 0)) { 258 return false; 259 } 260 261 if (selected.length == 0) return true; 262 263 return Arrays.asList(selectFrom).contains(selected[0]); 264 } 265 266 /** 267 * Check if the response integrity transform can be selected from the request integrity 268 * transforms. 269 * 270 * <p>For interoperability reason, it is allowed to do not include integrity transform in the 271 * response proposal when the request proposal has a NONE value integrity transform; and it is 272 * also allowed to have a NONE value integrity transform when the request proposal does not have 273 * integrity transforms. 274 */ isIntegrityTransformSelectedFrom( IntegrityTransform[] selected, IntegrityTransform[] selectFrom)275 private static boolean isIntegrityTransformSelectedFrom( 276 IntegrityTransform[] selected, IntegrityTransform[] selectFrom) { 277 if (selected.length == 0) { 278 selected = new IntegrityTransform[] {new IntegrityTransform(INTEGRITY_ALGORITHM_NONE)}; 279 } 280 if (selectFrom.length == 0) { 281 selectFrom = 282 new IntegrityTransform[] {new IntegrityTransform(INTEGRITY_ALGORITHM_NONE)}; 283 } 284 return isTransformSelectedFrom(selected, selectFrom); 285 } 286 287 /** 288 * Check if the response DH group can be selected from the request DH groups 289 * 290 * <p>For interoperability reason, it is allowed to do not include DH group in the response 291 * proposal when the request proposal has a NONE value DH group; and it is also allowed to have 292 * a NONE value DH group when the request proposal does not have DH groups. 293 */ isDhGroupTransformSelectedFrom( DhGroupTransform[] selected, DhGroupTransform[] selectFrom)294 private static boolean isDhGroupTransformSelectedFrom( 295 DhGroupTransform[] selected, DhGroupTransform[] selectFrom) { 296 if (selected.length == 0) { 297 selected = new DhGroupTransform[] {new DhGroupTransform(DH_GROUP_NONE)}; 298 } 299 if (selectFrom.length == 0) { 300 selectFrom = new DhGroupTransform[] {new DhGroupTransform(DH_GROUP_NONE)}; 301 } 302 return isTransformSelectedFrom(selected, selectFrom); 303 } 304 305 /** @hide */ 306 @IkePayload.ProtocolId getProtocolId()307 public int getProtocolId() { 308 return mProtocolId; 309 } 310 311 /** 312 * Gets all proposed encryption algorithms 313 * 314 * @return A list of Pairs, with the IANA-defined ID for the proposed encryption algorithm as 315 * the first item, and the key length (in bits) as the second. 316 */ 317 @NonNull getEncryptionAlgorithms()318 public List<Pair<Integer, Integer>> getEncryptionAlgorithms() { 319 final List<Pair<Integer, Integer>> result = new ArrayList<>(); 320 for (EncryptionTransform transform : mEncryptionAlgorithms) { 321 result.add(new Pair(transform.id, transform.getSpecifiedKeyLength())); 322 } 323 return result; 324 } 325 326 /** 327 * Gets all proposed integrity algorithms 328 * 329 * @return A list of the IANA-defined IDs for the proposed integrity algorithms 330 */ 331 @NonNull getIntegrityAlgorithms()332 public List<Integer> getIntegrityAlgorithms() { 333 final List<Integer> result = new ArrayList<>(); 334 for (Transform transform : mIntegrityAlgorithms) { 335 result.add(transform.id); 336 } 337 return result; 338 } 339 340 /** 341 * Gets all proposed Diffie-Hellman groups 342 * 343 * @return A list of the IANA-defined IDs for the proposed Diffie-Hellman groups 344 */ 345 @NonNull getDhGroups()346 public List<Integer> getDhGroups() { 347 final List<Integer> result = new ArrayList<>(); 348 for (Transform transform : mDhGroups) { 349 result.add(transform.id); 350 } 351 return result; 352 } 353 354 /** @hide */ getEncryptionTransforms()355 public EncryptionTransform[] getEncryptionTransforms() { 356 return mEncryptionAlgorithms; 357 } 358 359 /** @hide */ getIntegrityTransforms()360 public IntegrityTransform[] getIntegrityTransforms() { 361 return mIntegrityAlgorithms; 362 } 363 364 /** @hide */ getDhGroupTransforms()365 public DhGroupTransform[] getDhGroupTransforms() { 366 return mDhGroups; 367 } 368 369 /** @hide */ getAllTransformsAsList()370 protected List<Transform> getAllTransformsAsList() { 371 List<Transform> transformList = new LinkedList<>(); 372 373 transformList.addAll(Arrays.asList(mEncryptionAlgorithms)); 374 transformList.addAll(Arrays.asList(mIntegrityAlgorithms)); 375 transformList.addAll(Arrays.asList(mDhGroups)); 376 377 return transformList; 378 } 379 380 /** 381 * Return all SA Transforms in this SaProposal to be encoded for building an outbound IKE 382 * message. 383 * 384 * <p>This method should be called by only IKE library. 385 * 386 * @return Array of Transforms to be encoded. 387 * @hide 388 */ getAllTransforms()389 public abstract Transform[] getAllTransforms(); 390 391 /** 392 * This class is an abstract Builder for building a SaProposal. 393 * 394 * @hide 395 */ 396 protected abstract static class Builder { 397 protected static final String ERROR_TAG = "Invalid SA Proposal: "; 398 399 // Use LinkedHashSet to ensure uniqueness and that ordering is maintained. 400 protected final LinkedHashSet<EncryptionTransform> mProposedEncryptAlgos = 401 new LinkedHashSet<>(); 402 protected final LinkedHashSet<PrfTransform> mProposedPrfs = new LinkedHashSet<>(); 403 protected final LinkedHashSet<IntegrityTransform> mProposedIntegrityAlgos = 404 new LinkedHashSet<>(); 405 protected final LinkedHashSet<DhGroupTransform> mProposedDhGroups = new LinkedHashSet<>(); 406 407 protected boolean mHasAead = false; 408 isAead(@ncryptionAlgorithm int algorithm)409 protected static boolean isAead(@EncryptionAlgorithm int algorithm) { 410 switch (algorithm) { 411 case ENCRYPTION_ALGORITHM_3DES: 412 // Fall through 413 case ENCRYPTION_ALGORITHM_AES_CBC: 414 return false; 415 case ENCRYPTION_ALGORITHM_AES_GCM_8: 416 // Fall through 417 case ENCRYPTION_ALGORITHM_AES_GCM_12: 418 // Fall through 419 case ENCRYPTION_ALGORITHM_AES_GCM_16: 420 return true; 421 default: 422 // Won't hit here. 423 throw new IllegalArgumentException("Unsupported Encryption Algorithm."); 424 } 425 } 426 buildEncryptAlgosOrThrow()427 protected EncryptionTransform[] buildEncryptAlgosOrThrow() { 428 if (mProposedEncryptAlgos.isEmpty()) { 429 throw new IllegalArgumentException( 430 ERROR_TAG + "Encryption algorithm must be proposed."); 431 } 432 433 return mProposedEncryptAlgos.toArray( 434 new EncryptionTransform[mProposedEncryptAlgos.size()]); 435 } 436 validateAndAddEncryptAlgo( @ncryptionAlgorithm int algorithm, int keyLength)437 protected void validateAndAddEncryptAlgo( 438 @EncryptionAlgorithm int algorithm, int keyLength) { 439 // Construct EncryptionTransform and validate proposed algorithm during 440 // construction. 441 EncryptionTransform encryptionTransform = new EncryptionTransform(algorithm, keyLength); 442 443 // Validate that only one mode encryption algorithm has been proposed. 444 boolean isCurrentAead = isAead(algorithm); 445 if (!mProposedEncryptAlgos.isEmpty() && (mHasAead ^ isCurrentAead)) { 446 throw new IllegalArgumentException( 447 ERROR_TAG 448 + "Proposal cannot has both normal ciphers " 449 + "and combined-mode ciphers."); 450 } 451 if (isCurrentAead) mHasAead = true; 452 453 mProposedEncryptAlgos.add(encryptionTransform); 454 } 455 addIntegrityAlgo(@ntegrityAlgorithm int algorithm)456 protected void addIntegrityAlgo(@IntegrityAlgorithm int algorithm) { 457 // Construct IntegrityTransform and validate proposed algorithm during 458 // construction. 459 mProposedIntegrityAlgos.add(new IntegrityTransform(algorithm)); 460 } 461 addDh(@hGroup int dhGroup)462 protected void addDh(@DhGroup int dhGroup) { 463 // Construct DhGroupTransform and validate proposed dhGroup during 464 // construction. 465 mProposedDhGroups.add(new DhGroupTransform(dhGroup)); 466 } 467 } 468 469 /** @hide */ 470 @Override 471 @NonNull toString()472 public String toString() { 473 StringBuilder sb = new StringBuilder(); 474 475 sb.append(IkePayload.getProtocolTypeString(mProtocolId)).append(": "); 476 477 int len = getAllTransforms().length; 478 for (int i = 0; i < len; i++) { 479 sb.append(getAllTransforms()[i].toString()); 480 if (i < len - 1) sb.append("|"); 481 } 482 483 return sb.toString(); 484 } 485 486 /** 487 * Check if the provided algorithm is a supported encryption algorithm. 488 * 489 * @param algorithm IKE standard encryption algorithm id. 490 * @return true if the provided algorithm is a supported encryption algorithm. 491 * @hide 492 */ isSupportedEncryptionAlgorithm(@ncryptionAlgorithm int algorithm)493 public static boolean isSupportedEncryptionAlgorithm(@EncryptionAlgorithm int algorithm) { 494 return SUPPORTED_ENCRYPTION_ALGO_TO_STR.get(algorithm) != null; 495 } 496 497 /** 498 * Check if the provided algorithm is a supported pseudorandom function. 499 * 500 * @param algorithm IKE standard pseudorandom function id. 501 * @return true if the provided algorithm is a supported pseudorandom function. 502 * @hide 503 */ isSupportedPseudorandomFunction(@seudorandomFunction int algorithm)504 public static boolean isSupportedPseudorandomFunction(@PseudorandomFunction int algorithm) { 505 return SUPPORTED_PRF_TO_STR.get(algorithm) != null; 506 } 507 508 /** 509 * Check if the provided algorithm is a supported integrity algorithm. 510 * 511 * @param algorithm IKE standard integrity algorithm id. 512 * @return true if the provided algorithm is a supported integrity algorithm. 513 * @hide 514 */ isSupportedIntegrityAlgorithm(@ntegrityAlgorithm int algorithm)515 public static boolean isSupportedIntegrityAlgorithm(@IntegrityAlgorithm int algorithm) { 516 return SUPPORTED_INTEGRITY_ALGO_TO_STR.get(algorithm) != null; 517 } 518 519 /** 520 * Check if the provided group number is for a supported Diffie-Hellman Group. 521 * 522 * @param dhGroup IKE standard DH Group id. 523 * @return true if the provided number is for a supported Diffie-Hellman Group. 524 * @hide 525 */ isSupportedDhGroup(@hGroup int dhGroup)526 public static boolean isSupportedDhGroup(@DhGroup int dhGroup) { 527 return SUPPORTED_DH_GROUP_TO_STR.get(dhGroup) != null; 528 } 529 530 /** 531 * Return the encryption algorithm as a String. 532 * 533 * @hide 534 */ getEncryptionAlgorithmString(int algorithm)535 public static String getEncryptionAlgorithmString(int algorithm) { 536 if (isSupportedEncryptionAlgorithm(algorithm)) { 537 return SUPPORTED_ENCRYPTION_ALGO_TO_STR.get(algorithm); 538 } 539 return "ENC_Unknown_" + algorithm; 540 } 541 542 /** 543 * Return the pseudorandom function as a String. 544 * 545 * @hide 546 */ getPseudorandomFunctionString(int algorithm)547 public static String getPseudorandomFunctionString(int algorithm) { 548 if (isSupportedPseudorandomFunction(algorithm)) { 549 return SUPPORTED_PRF_TO_STR.get(algorithm); 550 } 551 return "PRF_Unknown_" + algorithm; 552 } 553 554 /** 555 * Return the integrity algorithm as a String. 556 * 557 * @hide 558 */ getIntegrityAlgorithmString(int algorithm)559 public static String getIntegrityAlgorithmString(int algorithm) { 560 if (isSupportedIntegrityAlgorithm(algorithm)) { 561 return SUPPORTED_INTEGRITY_ALGO_TO_STR.get(algorithm); 562 } 563 return "AUTH_Unknown_" + algorithm; 564 } 565 566 /** 567 * Return Diffie-Hellman Group as a String. 568 * 569 * @hide 570 */ getDhGroupString(int dhGroup)571 public static String getDhGroupString(int dhGroup) { 572 if (isSupportedDhGroup(dhGroup)) { 573 return SUPPORTED_DH_GROUP_TO_STR.get(dhGroup); 574 } 575 return "DH_Unknown_" + dhGroup; 576 } 577 } 578