[nearby] Add CredentialElement class
This class should extend DataElement ideally, but we cannot do this
since the DataElement class as System API is final.
Bug: 290294482
Test: unit test
Ignore-AOSP-First: nearby_not_in_aosp_yet
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:0e9e44c4f06c6ea58e991b695cb34dbc0c9d3b59)
Merged-In: I2ec80b5975a8fb27edb5f92f134d6076738eaac8
Change-Id: I2ec80b5975a8fb27edb5f92f134d6076738eaac8
diff --git a/nearby/service/java/com/android/server/nearby/presence/EncryptionInfo.java b/nearby/service/java/com/android/server/nearby/presence/EncryptionInfo.java
new file mode 100644
index 0000000..1f9f70b
--- /dev/null
+++ b/nearby/service/java/com/android/server/nearby/presence/EncryptionInfo.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.nearby.presence;
+
+import android.annotation.IntDef;
+import android.nearby.DataElement;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Arrays;
+
+/**
+ * Data Element that indicates the presence of extended 16 bytes salt instead of 2 byte salt and to
+ * indicate which encoding scheme (MIC tag or Signature) is used for a section. If present, it must
+ * be the first DE in a section.
+ */
+public class EncryptionInfo {
+
+ @IntDef({EncodingScheme.MIC, EncodingScheme.SIGNATURE})
+ public @interface EncodingScheme {
+ int MIC = 0;
+ int SIGNATURE = 1;
+ }
+
+ // 1st byte : encryption scheme
+ // 2nd to 17th bytes: salt
+ private static final int ENCRYPTION_INFO_LENGTH = 17;
+ private static final int ENCODING_SCHEME_MASK = 0b01111000;
+ private static final int ENCODING_SCHEME_OFFSET = 3;
+ @EncodingScheme
+ private final int mEncodingScheme;
+ private final byte[] mSalt;
+
+ /**
+ * Constructs a {@link DataElement}.
+ */
+ public EncryptionInfo(@NonNull byte[] value) {
+ Preconditions.checkArgument(value.length == ENCRYPTION_INFO_LENGTH);
+ mEncodingScheme = (value[0] & ENCODING_SCHEME_MASK) >> ENCODING_SCHEME_OFFSET;
+ Preconditions.checkArgument(isValidEncodingScheme(mEncodingScheme));
+ mSalt = Arrays.copyOfRange(value, 1, ENCRYPTION_INFO_LENGTH);
+ }
+
+ private boolean isValidEncodingScheme(int scheme) {
+ return scheme == EncodingScheme.MIC || scheme == EncodingScheme.SIGNATURE;
+ }
+
+ @EncodingScheme
+ public int getEncodingScheme() {
+ return mEncodingScheme;
+ }
+
+ public byte[] getSalt() {
+ return mSalt;
+ }
+}
diff --git a/nearby/service/java/com/android/server/nearby/util/ArrayUtils.java b/nearby/service/java/com/android/server/nearby/util/ArrayUtils.java
index 35251d8..bb5461c 100644
--- a/nearby/service/java/com/android/server/nearby/util/ArrayUtils.java
+++ b/nearby/service/java/com/android/server/nearby/util/ArrayUtils.java
@@ -52,4 +52,17 @@
public static boolean isEmpty(byte[] bytes) {
return bytes == null || bytes.length == 0;
}
+
+ /** Appends a byte array to a byte. */
+ public static byte[] append(byte a, byte[] b) {
+ if (b == null) {
+ return new byte[]{a};
+ }
+
+ int length = b.length;
+ byte[] result = new byte[length + 1];
+ result[0] = a;
+ System.arraycopy(b, 0, result, 1, length);
+ return result;
+ }
}
diff --git a/nearby/tests/unit/src/com/android/server/nearby/presence/EncryptionInfoTest.java b/nearby/tests/unit/src/com/android/server/nearby/presence/EncryptionInfoTest.java
new file mode 100644
index 0000000..a1eb57b
--- /dev/null
+++ b/nearby/tests/unit/src/com/android/server/nearby/presence/EncryptionInfoTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.nearby.presence;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import com.android.server.nearby.util.ArrayUtils;
+
+import org.junit.Test;
+
+
+/**
+ * Unit test for {@link EncryptionInfo}.
+ */
+public class EncryptionInfoTest {
+ private static final byte[] SALT =
+ new byte[]{25, -21, 35, -108, -26, -126, 99, 60, 110, 45, -116, 34, 91, 126, -23, 127};
+
+ @Test
+ public void test_illegalLength() {
+ byte[] data = new byte[]{1, 2};
+ assertThrows(IllegalArgumentException.class, () -> new EncryptionInfo(data));
+ }
+
+ @Test
+ public void test_illegalEncodingScheme() {
+ assertThrows(IllegalArgumentException.class,
+ () -> new EncryptionInfo(ArrayUtils.append((byte) 0b10110000, SALT)));
+ assertThrows(IllegalArgumentException.class,
+ () -> new EncryptionInfo(ArrayUtils.append((byte) 0b01101000, SALT)));
+ }
+
+ @Test
+ public void test_getMethods_signature() {
+ byte[] data = ArrayUtils.append((byte) 0b10001000, SALT);
+ EncryptionInfo info = new EncryptionInfo(data);
+ assertThat(info.getEncodingScheme()).isEqualTo(EncryptionInfo.EncodingScheme.SIGNATURE);
+ assertThat(info.getSalt()).isEqualTo(SALT);
+ }
+
+ @Test
+ public void test_getMethods_mic() {
+ byte[] data = ArrayUtils.append((byte) 0b10000000, SALT);
+ EncryptionInfo info = new EncryptionInfo(data);
+ assertThat(info.getEncodingScheme()).isEqualTo(EncryptionInfo.EncodingScheme.MIC);
+ assertThat(info.getSalt()).isEqualTo(SALT);
+ }
+}