Verify kernel implementation of AES-XCBC

This CL adds a test to verify kernel implementation of AES-XCBC.

Since there is no hardware that first launched with SDK beyond R
at the time of writing this CL, the test for AES-XCBC was manually
enabled and verified on coral (coral-kernel already supports
AES-XCBC)

Bug: 171083832
Test: atest IpSecAlgorithmImplTest
Change-Id: I57e2bbed2954e4c7de906caae20390f7aebac0e3
diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp
index cd69b13..e28c33f 100644
--- a/tests/cts/net/Android.bp
+++ b/tests/cts/net/Android.bp
@@ -38,6 +38,7 @@
     srcs: [
         "src/**/*.java",
         "src/**/*.kt",
+        ":ike-aes-xcbc",
     ],
     jarjar_rules: "jarjar-rules-shared.txt",
     static_libs: [
diff --git a/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java b/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java
index 73dc80c..080f7f9 100644
--- a/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java
@@ -16,6 +16,7 @@
 
 package android.net.cts;
 
+import static android.net.IpSecAlgorithm.AUTH_AES_XCBC;
 import static android.net.IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305;
 import static android.net.IpSecAlgorithm.CRYPT_AES_CTR;
 import static android.net.cts.PacketUtils.AES_CTR;
@@ -25,6 +26,9 @@
 import static android.net.cts.PacketUtils.AES_CTR_KEY_LEN_28;
 import static android.net.cts.PacketUtils.AES_CTR_KEY_LEN_36;
 import static android.net.cts.PacketUtils.AES_CTR_SALT_LEN;
+import static android.net.cts.PacketUtils.AES_XCBC;
+import static android.net.cts.PacketUtils.AES_XCBC_ICV_LEN;
+import static android.net.cts.PacketUtils.AES_XCBC_KEY_LEN;
 import static android.net.cts.PacketUtils.CHACHA20_POLY1305;
 import static android.net.cts.PacketUtils.CHACHA20_POLY1305_BLK_SIZE;
 import static android.net.cts.PacketUtils.CHACHA20_POLY1305_ICV_LEN;
@@ -51,6 +55,7 @@
 import android.net.cts.PacketUtils.EspAuth;
 import android.net.cts.PacketUtils.EspAuthNull;
 import android.net.cts.PacketUtils.EspCipher;
+import android.net.cts.PacketUtils.EspCipherNull;
 import android.net.cts.PacketUtils.EspCryptCipher;
 import android.net.cts.PacketUtils.EspHeader;
 import android.net.cts.PacketUtils.IpHeader;
@@ -239,6 +244,20 @@
     }
 
     @Test
+    public void testAesXcbc() throws Exception {
+        assumeTrue(hasIpSecAlgorithm(AUTH_AES_XCBC));
+
+        final byte[] authKey = getKeyBytes(AES_XCBC_KEY_LEN);
+        final IpSecAlgorithm ipsecAuthAlgo =
+                new IpSecAlgorithm(IpSecAlgorithm.AUTH_AES_XCBC, authKey, AES_XCBC_ICV_LEN * 8);
+        final EspAuth espAuth = new EspAuth(AES_XCBC, authKey, AES_XCBC_ICV_LEN);
+
+        runWithShellPermissionIdentity(new TestNetworkRunnable(new CheckCryptoImplTest(
+                null /* ipsecEncryptAlgo */, ipsecAuthAlgo, null /* ipsecAeadAlgo */,
+                EspCipherNull.getInstance(), espAuth)));
+    }
+
+    @Test
     public void testChaCha20Poly1305() throws Exception {
         assumeTrue(hasIpSecAlgorithm(AUTH_CRYPT_CHACHA20_POLY1305));
 
diff --git a/tests/cts/net/src/android/net/cts/PacketUtils.java b/tests/cts/net/src/android/net/cts/PacketUtils.java
index 6b409f2..0b3bad4 100644
--- a/tests/cts/net/src/android/net/cts/PacketUtils.java
+++ b/tests/cts/net/src/android/net/cts/PacketUtils.java
@@ -19,6 +19,8 @@
 import static android.system.OsConstants.IPPROTO_IPV6;
 import static android.system.OsConstants.IPPROTO_UDP;
 
+import com.android.internal.net.ipsec.ike.crypto.AesXCbcImpl;
+
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -27,6 +29,8 @@
 import java.security.GeneralSecurityException;
 import java.security.SecureRandom;
 import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
 
 import javax.crypto.Cipher;
 import javax.crypto.Mac;
@@ -92,7 +96,12 @@
     static final String CHACHA20_POLY1305 = "ChaCha20/Poly1305/NoPadding";
 
     // Authentication algorithms
+    static final String HMAC_MD5 = "HmacMD5";
+    static final String HMAC_SHA1 = "HmacSHA1";
     static final String HMAC_SHA_256 = "HmacSHA256";
+    static final String HMAC_SHA_384 = "HmacSHA384";
+    static final String HMAC_SHA_512 = "HmacSHA512";
+    static final String AES_XCBC = "AesXCbc";
 
     public interface Payload {
         byte[] getPacketBytes(IpHeader header) throws Exception;
@@ -657,6 +666,16 @@
         public final byte[] key;
         public final int icvLen;
 
+        private static final Set<String> SUPPORTED_HMAC_ALGOS = new HashSet<>();
+
+        static {
+            SUPPORTED_HMAC_ALGOS.add(HMAC_MD5);
+            SUPPORTED_HMAC_ALGOS.add(HMAC_SHA1);
+            SUPPORTED_HMAC_ALGOS.add(HMAC_SHA_256);
+            SUPPORTED_HMAC_ALGOS.add(HMAC_SHA_384);
+            SUPPORTED_HMAC_ALGOS.add(HMAC_SHA_512);
+        }
+
         public EspAuth(String algoName, byte[] key, int icvLen) {
             this.algoName = algoName;
             this.key = key;
@@ -664,14 +683,21 @@
         }
 
         public byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException {
-            final Mac mac = Mac.getInstance(algoName);
-            final SecretKeySpec authKey = new SecretKeySpec(key, HMAC_SHA_256);
-            mac.init(authKey);
+            if (AES_XCBC.equals(algoName)) {
+                final Cipher aesCipher = Cipher.getInstance(AES_CBC);
+                return new AesXCbcImpl().mac(key, authenticatedSection, true /* needTruncation */);
+            } else if (SUPPORTED_HMAC_ALGOS.contains(algoName)) {
+                final Mac mac = Mac.getInstance(algoName);
+                final SecretKeySpec authKey = new SecretKeySpec(key, algoName);
+                mac.init(authKey);
 
-            final ByteBuffer buffer = ByteBuffer.wrap(mac.doFinal(authenticatedSection));
-            final byte[] icv = new byte[icvLen];
-            buffer.get(icv);
-            return icv;
+                final ByteBuffer buffer = ByteBuffer.wrap(mac.doFinal(authenticatedSection));
+                final byte[] icv = new byte[icvLen];
+                buffer.get(icv);
+                return icv;
+            } else {
+                throw new IllegalArgumentException("Invalid algorithm: " + algoName);
+            }
         }
     }