Verify kernel implementation of AES-CTR
This CL adds a test to verify kernel implementation of AES-CTR
Since there is no hardware that first launched with SDK beyond R
at the time of writing this CL, new tests for AES-CTR were manually
enabled and verified on coral (coral-kernel already supports
AES-CTR)
Bug: 171083832
Test: atest IpSecAlgorithmImplTest
Original-Change: https://android-review.googlesource.com/1503695
Merged-In: Ib626a6c3999b7d682d0858e92d0dbb5138fdc45d
Change-Id: Ib626a6c3999b7d682d0858e92d0dbb5138fdc45d
diff --git a/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java b/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java
index 3b110a4..73dc80c 100644
--- a/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java
@@ -17,6 +17,14 @@
package android.net.cts;
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;
+import static android.net.cts.PacketUtils.AES_CTR_BLK_SIZE;
+import static android.net.cts.PacketUtils.AES_CTR_IV_LEN;
+import static android.net.cts.PacketUtils.AES_CTR_KEY_LEN_20;
+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.CHACHA20_POLY1305;
import static android.net.cts.PacketUtils.CHACHA20_POLY1305_BLK_SIZE;
import static android.net.cts.PacketUtils.CHACHA20_POLY1305_ICV_LEN;
@@ -43,6 +51,7 @@
import android.net.cts.PacketUtils.EspAuth;
import android.net.cts.PacketUtils.EspAuthNull;
import android.net.cts.PacketUtils.EspCipher;
+import android.net.cts.PacketUtils.EspCryptCipher;
import android.net.cts.PacketUtils.EspHeader;
import android.net.cts.PacketUtils.IpHeader;
import android.net.cts.PacketUtils.UdpHeader;
@@ -194,6 +203,41 @@
}
}
+ private void checkAesCtr(int keyLen) throws Exception {
+ final byte[] cryptKey = getKeyBytes(keyLen);
+
+ final IpSecAlgorithm ipsecEncryptAlgo =
+ new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CTR, cryptKey);
+ final EspCipher espCipher =
+ new EspCryptCipher(
+ AES_CTR, AES_CTR_BLK_SIZE, cryptKey, AES_CTR_IV_LEN, AES_CTR_SALT_LEN);
+
+ runWithShellPermissionIdentity(new TestNetworkRunnable(new CheckCryptoImplTest(
+ ipsecEncryptAlgo, null /* ipsecAuthAlgo */, null /* ipsecAeadAlgo */,
+ espCipher, EspAuthNull.getInstance())));
+ }
+
+ @Test
+ public void testAesCtr160() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
+
+ checkAesCtr(AES_CTR_KEY_LEN_20);
+ }
+
+ @Test
+ public void testAesCtr224() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
+
+ checkAesCtr(AES_CTR_KEY_LEN_28);
+ }
+
+ @Test
+ public void testAesCtr288() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
+
+ checkAesCtr(AES_CTR_KEY_LEN_36);
+ }
+
@Test
public void testChaCha20Poly1305() throws Exception {
assumeTrue(hasIpSecAlgorithm(AUTH_CRYPT_CHACHA20_POLY1305));
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
index e7e1d67..5f79a3e 100644
--- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
@@ -33,7 +33,7 @@
import static android.net.cts.PacketUtils.AES_CMAC_KEY_LEN;
import static android.net.cts.PacketUtils.AES_CTR_BLK_SIZE;
import static android.net.cts.PacketUtils.AES_CTR_IV_LEN;
-import static android.net.cts.PacketUtils.AES_CTR_KEY_LEN;
+import static android.net.cts.PacketUtils.AES_CTR_KEY_LEN_20;
import static android.net.cts.PacketUtils.AES_GCM_BLK_SIZE;
import static android.net.cts.PacketUtils.AES_GCM_IV_LEN;
import static android.net.cts.PacketUtils.AES_XCBC_ICV_LEN;
@@ -928,7 +928,7 @@
}
private static IpSecAlgorithm buildCryptAesCtr() throws Exception {
- return new IpSecAlgorithm(CRYPT_AES_CTR, getKeyBytes(AES_CTR_KEY_LEN));
+ return new IpSecAlgorithm(CRYPT_AES_CTR, getKeyBytes(AES_CTR_KEY_LEN_20));
}
private static IpSecAlgorithm buildAuthHmacSha512() throws Exception {
diff --git a/tests/cts/net/src/android/net/cts/PacketUtils.java b/tests/cts/net/src/android/net/cts/PacketUtils.java
index 27c9f3b..6b409f2 100644
--- a/tests/cts/net/src/android/net/cts/PacketUtils.java
+++ b/tests/cts/net/src/android/net/cts/PacketUtils.java
@@ -54,8 +54,11 @@
// Encryption parameters
static final int AES_CBC_IV_LEN = 16;
static final int AES_CBC_BLK_SIZE = 16;
+ static final int AES_CTR_SALT_LEN = 4;
- static final int AES_CTR_KEY_LEN = 20;
+ static final int AES_CTR_KEY_LEN_20 = 20;
+ static final int AES_CTR_KEY_LEN_28 = 28;
+ static final int AES_CTR_KEY_LEN_36 = 36;
static final int AES_CTR_BLK_SIZE = ESP_BLK_SIZE;
static final int AES_CTR_IV_LEN = 8;
@@ -77,9 +80,13 @@
static final int AES_CMAC_KEY_LEN = 16;
static final int AES_CMAC_ICV_LEN = 12;
+ // Block counter field should be 32 bits and starts from value one as per RFC 3686
+ static final byte[] AES_CTR_INITIAL_COUNTER = new byte[] {0x00, 0x00, 0x00, 0x01};
+
// Encryption algorithms
static final String AES = "AES";
static final String AES_CBC = "AES/CBC/NoPadding";
+ static final String AES_CTR = "AES/CTR/NoPadding";
// AEAD algorithms
static final String CHACHA20_POLY1305 = "ChaCha20/Poly1305/NoPadding";
@@ -552,14 +559,38 @@
public static class EspCryptCipher extends EspCipher {
public EspCryptCipher(String algoName, int blockSize, byte[] key, int ivLen) {
- super(algoName, blockSize, key, ivLen, SALT_LEN_UNUSED);
+ this(algoName, blockSize, key, ivLen, SALT_LEN_UNUSED);
+ }
+
+ public EspCryptCipher(String algoName, int blockSize, byte[] key, int ivLen, int saltLen) {
+ super(algoName, blockSize, key, ivLen, saltLen);
}
@Override
public byte[] getCipherText(int nextHeader, byte[] payload, int spi, int seqNum)
throws GeneralSecurityException {
- final IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
- final SecretKeySpec secretKeySpec = new SecretKeySpec(key, algoName);
+ final IvParameterSpec ivParameterSpec;
+ final SecretKeySpec secretKeySpec;
+
+ if (AES_CBC.equals(algoName)) {
+ ivParameterSpec = new IvParameterSpec(iv);
+ secretKeySpec = new SecretKeySpec(key, algoName);
+ } else if (AES_CTR.equals(algoName)) {
+ // Provided key consists of encryption/decryption key plus 4-byte salt. Salt is used
+ // with ESP payload IV and initial block counter value to build IvParameterSpec.
+ final byte[] secretKey = Arrays.copyOfRange(key, 0, key.length - saltLen);
+ final byte[] salt = Arrays.copyOfRange(key, secretKey.length, key.length);
+ secretKeySpec = new SecretKeySpec(secretKey, algoName);
+
+ final ByteBuffer ivParameterBuffer =
+ ByteBuffer.allocate(iv.length + saltLen + AES_CTR_INITIAL_COUNTER.length);
+ ivParameterBuffer.put(salt);
+ ivParameterBuffer.put(iv);
+ ivParameterBuffer.put(AES_CTR_INITIAL_COUNTER);
+ ivParameterSpec = new IvParameterSpec(ivParameterBuffer.array());
+ } else {
+ throw new IllegalArgumentException("Invalid algorithm " + algoName);
+ }
// Encrypt payload
final Cipher cipher = Cipher.getInstance(algoName);