Support getting IPsec algorithm name for a given IKE algorithm ID

This is a preparation CL for supporting interogating supported
algorithms when building ChildSaProposal

Bug: 157577190
Test: atest FrameworksIkeTests (new tests added), CtsIkeTestCases
Change-Id: I9949b9655d09ad3771ec0cf98ec7525b7a05c4b9
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCipher.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCipher.java
index d0e55af..23220be 100644
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCipher.java
+++ b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCipher.java
@@ -16,8 +16,10 @@
 
 package com.android.internal.net.ipsec.ike.crypto;
 
+import android.annotation.Nullable;
 import android.net.IpSecAlgorithm;
 import android.net.ipsec.ike.SaProposal;
+import android.util.SparseArray;
 
 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
 
@@ -52,6 +54,26 @@
     protected static final int SALT_LEN_NOT_INCLUDED = 0;
     protected static final int BLOCK_SIZE_NOT_SPECIFIED = 0;
 
+    // Map IKE algorithm numbers to IPsec algorithm names
+    private static final SparseArray<String> IKE_ALGO_TO_IPSEC_ALGO;
+
+    static {
+        IKE_ALGO_TO_IPSEC_ALGO = new SparseArray<>();
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, IpSecAlgorithm.CRYPT_AES_CBC);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.ENCRYPTION_ALGORITHM_AES_CTR, IpSecAlgorithm.CRYPT_AES_CTR);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8, IpSecAlgorithm.AUTH_CRYPT_AES_GCM);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, IpSecAlgorithm.AUTH_CRYPT_AES_GCM);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16, IpSecAlgorithm.AUTH_CRYPT_AES_GCM);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.ENCRYPTION_ALGORITHM_CHACHA20_POLY1305,
+                IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305);
+    }
+
     private final boolean mIsAead;
     private final int mIvLen;
     private final int mBlockSize;
@@ -188,6 +210,19 @@
     }
 
     /**
+     * Returns the IPsec algorithm name defined in {@link IpSecAlgorithm} given the IKE algorithm
+     * ID.
+     *
+     * <p>Returns null if there is no corresponding IPsec algorithm given the IKE algorithm ID.
+     */
+    @Nullable
+    public static String getIpSecAlgorithmName(int ikeAlgoId) {
+        return IKE_ALGO_TO_IPSEC_ALGO.get(ikeAlgoId);
+    }
+
+    protected abstract IpSecAlgorithm buildIpSecAlgorithmWithKeyImpl(byte[] key);
+
+    /**
      * Build IpSecAlgorithm from this IkeCipher.
      *
      * <p>Build IpSecAlgorithm that represents the same encryption algorithm with this IkeCipher
@@ -196,7 +231,14 @@
      * @param key the encryption key in byte array.
      * @return the IpSecAlgorithm.
      */
-    public abstract IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key);
+    public IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key) {
+        validateKeyLenOrThrow(key);
+        if (getIpSecAlgorithmName(getAlgorithmId()) == null) {
+            throw new IllegalStateException(
+                    "Unsupported algorithm " + getAlgorithmId() + " in IPsec");
+        }
+        return buildIpSecAlgorithmWithKeyImpl(key);
+    }
 
     /**
      * Returns algorithm type as a String.
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipher.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipher.java
index 3a27752..a59e566 100644
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipher.java
+++ b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipher.java
@@ -202,21 +202,7 @@
     }
 
     @Override
-    public IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key) {
-        validateKeyLenOrThrow(key);
-        switch (getAlgorithmId()) {
-            case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8:
-                // Fall through
-            case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12:
-                // Fall through
-            case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16:
-                return new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, key, mChecksumLen * 8);
-            case SaProposal.ENCRYPTION_ALGORITHM_CHACHA20_POLY1305:
-                return new IpSecAlgorithm(
-                        IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305, key, mChecksumLen * 8);
-            default:
-                throw new IllegalArgumentException(
-                        "Unrecognized Encryption Algorithm ID: " + getAlgorithmId());
-        }
+    protected IpSecAlgorithm buildIpSecAlgorithmWithKeyImpl(byte[] key) {
+        return new IpSecAlgorithm(getIpSecAlgorithmName(getAlgorithmId()), key, mChecksumLen * 8);
     }
 }
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrity.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrity.java
index cb2aca7..16a5309 100644
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrity.java
+++ b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrity.java
@@ -18,8 +18,10 @@
 
 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96;
 
+import android.annotation.Nullable;
 import android.net.IpSecAlgorithm;
 import android.net.ipsec.ike.SaProposal;
+import android.util.SparseArray;
 
 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
 
@@ -39,7 +41,23 @@
  * Exchange Protocol Version 2 (IKEv2)</a>
  */
 public class IkeMacIntegrity extends IkeMac {
-    // STOPSHIP: b/130190639 Catch unchecked exceptions, notify users and close the IKE session.
+    // Map IKE algorithm numbers to IPsec algorithm names
+    private static final SparseArray<String> IKE_ALGO_TO_IPSEC_ALGO;
+
+    static {
+        IKE_ALGO_TO_IPSEC_ALGO = new SparseArray<>();
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96, IpSecAlgorithm.AUTH_HMAC_SHA1);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96, IpSecAlgorithm.AUTH_AES_XCBC);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, IpSecAlgorithm.AUTH_HMAC_SHA256);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, IpSecAlgorithm.AUTH_HMAC_SHA384);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, IpSecAlgorithm.AUTH_HMAC_SHA512);
+    }
+
     private final int mChecksumLength;
 
     private IkeMacIntegrity(
@@ -149,6 +167,17 @@
     }
 
     /**
+     * Returns the IPsec algorithm name defined in {@link IpSecAlgorithm} given the IKE algorithm
+     * ID.
+     *
+     * <p>Returns null if there is no corresponding IPsec algorithm given the IKE algorithm ID.
+     */
+    @Nullable
+    public static String getIpSecAlgorithmName(int ikeAlgoId) {
+        return IKE_ALGO_TO_IPSEC_ALGO.get(ikeAlgoId);
+    }
+
+    /**
      * Build IpSecAlgorithm from this IkeMacIntegrity.
      *
      * <p>Build IpSecAlgorithm that represents the same integrity algorithm with this
@@ -165,25 +194,12 @@
                             + " Received key with length of : "
                             + key.length);
         }
-
-        switch (getAlgorithmId()) {
-            case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96:
-                return new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, key, mChecksumLength * 8);
-            case SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96:
-                return new IpSecAlgorithm(IpSecAlgorithm.AUTH_AES_XCBC, key, mChecksumLength * 8);
-            case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128:
-                return new IpSecAlgorithm(
-                        IpSecAlgorithm.AUTH_HMAC_SHA256, key, mChecksumLength * 8);
-            case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192:
-                return new IpSecAlgorithm(
-                        IpSecAlgorithm.AUTH_HMAC_SHA384, key, mChecksumLength * 8);
-            case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256:
-                return new IpSecAlgorithm(
-                        IpSecAlgorithm.AUTH_HMAC_SHA512, key, mChecksumLength * 8);
-            default:
-                throw new IllegalArgumentException(
-                        "Unrecognized Integrity Algorithm ID: " + getAlgorithmId());
+        if (getIpSecAlgorithmName(getAlgorithmId()) == null) {
+            throw new IllegalStateException(
+                    "Unsupported algorithm " + getAlgorithmId() + " in IPsec");
         }
+        return new IpSecAlgorithm(
+                getIpSecAlgorithmName(getAlgorithmId()), key, mChecksumLength * 8);
     }
 
     /**
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipher.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipher.java
index f932e14..7fc18ed 100644
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipher.java
+++ b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipher.java
@@ -130,21 +130,8 @@
     }
 
     @Override
-    public IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key) {
-        validateKeyLenOrThrow(key);
-
-        switch (getAlgorithmId()) {
-            case SaProposal.ENCRYPTION_ALGORITHM_3DES:
-                // TODO: Consider supporting 3DES in IpSecTransform.
-                throw new UnsupportedOperationException("Do not support 3Des encryption.");
-            case SaProposal.ENCRYPTION_ALGORITHM_AES_CBC:
-                return new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, key);
-            case SaProposal.ENCRYPTION_ALGORITHM_AES_CTR:
-                return new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CTR, key);
-            default:
-                throw new IllegalArgumentException(
-                        "Unrecognized Encryption Algorithm ID: " + getAlgorithmId());
-        }
+    protected IpSecAlgorithm buildIpSecAlgorithmWithKeyImpl(byte[] key) {
+        return new IpSecAlgorithm(getIpSecAlgorithmName(getAlgorithmId()), key);
     }
 
     private static byte[] concatenateByteArray(byte[] left, byte[] right) {
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrityTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrityTest.java
index fc322bb..946d844 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrityTest.java
+++ b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrityTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -185,4 +186,27 @@
             }
         }
     }
+
+    @Test
+    public void testGetIpSecAlgorithmName() throws Exception {
+        assertEquals(
+                IpSecAlgorithm.AUTH_HMAC_SHA1,
+                IkeMacIntegrity.getIpSecAlgorithmName(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96));
+        assertEquals(
+                IpSecAlgorithm.AUTH_AES_XCBC,
+                IkeMacIntegrity.getIpSecAlgorithmName(SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96));
+        assertEquals(
+                IpSecAlgorithm.AUTH_HMAC_SHA256,
+                IkeMacIntegrity.getIpSecAlgorithmName(
+                        SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128));
+        assertEquals(
+                IpSecAlgorithm.AUTH_HMAC_SHA384,
+                IkeMacIntegrity.getIpSecAlgorithmName(
+                        SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192));
+        assertEquals(
+                IpSecAlgorithm.AUTH_HMAC_SHA512,
+                IkeMacIntegrity.getIpSecAlgorithmName(
+                        SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256));
+        assertNull(IkeMacIntegrity.getIpSecAlgorithmName(SaProposal.INTEGRITY_ALGORITHM_NONE));
+    }
 }
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipherTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipherTest.java
index 9837ac7..15d0092 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipherTest.java
+++ b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipherTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -184,7 +185,7 @@
     }
 
     @Test
-    public void buildIpSecAlgorithmWithInvalidKey() throws Exception {
+    public void testBuildIpSecAlgorithmWithInvalidKey() throws Exception {
         byte[] encryptionKey = TestUtils.hexStringToByteArray(ENCR_KEY_FROM_INIT_TO_RESP + "00");
 
         try {
@@ -195,4 +196,27 @@
 
         }
     }
+
+    @Test
+    public void testGetIpSecAlgorithmName() throws Exception {
+        assertEquals(
+                IpSecAlgorithm.CRYPT_AES_CBC,
+                IkeCipher.getIpSecAlgorithmName(SaProposal.ENCRYPTION_ALGORITHM_AES_CBC));
+        assertEquals(
+                IpSecAlgorithm.CRYPT_AES_CTR,
+                IkeCipher.getIpSecAlgorithmName(SaProposal.ENCRYPTION_ALGORITHM_AES_CTR));
+        assertEquals(
+                IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
+                IkeCipher.getIpSecAlgorithmName(SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8));
+        assertEquals(
+                IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
+                IkeCipher.getIpSecAlgorithmName(SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12));
+        assertEquals(
+                IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
+                IkeCipher.getIpSecAlgorithmName(SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16));
+        assertEquals(
+                IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305,
+                IkeCipher.getIpSecAlgorithmName(SaProposal.ENCRYPTION_ALGORITHM_CHACHA20_POLY1305));
+        assertNull(IkeCipher.getIpSecAlgorithmName(SaProposal.ENCRYPTION_ALGORITHM_3DES));
+    }
 }