summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Kevin Chyn <kchyn@google.com> 2020-10-07 19:03:06 -0700
committer Kevin Chyn <kchyn@google.com> 2020-10-09 13:18:13 -0700
commit275aa876db4d562b965c54868380b00c2b05c16c (patch)
treeb5c423af3dac0301db736acd29311cd0a42ba71a
parent06e8478edbc5460fc086bb09ae33713b3bfc8789 (diff)
2/n: Add HardwareAuthTokenUtils
This should move to android.security in the future. However, with changing interfaces and build issues, this should suffice for now. Fixes: 170163175 Bug: 168843828 Test: atest HardwareAuthTokenUtilsTest Change-Id: Ib566e3f3739dbd72e0e2b4dea67a8921465ed963
-rw-r--r--services/core/java/com/android/server/biometrics/HardwareAuthTokenUtils.java138
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/HardwareAuthTokenUtilsTest.java83
3 files changed, 224 insertions, 2 deletions
diff --git a/services/core/java/com/android/server/biometrics/HardwareAuthTokenUtils.java b/services/core/java/com/android/server/biometrics/HardwareAuthTokenUtils.java
new file mode 100644
index 000000000000..eff4da3132fe
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/HardwareAuthTokenUtils.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2020 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.biometrics;
+
+import static java.nio.ByteOrder.LITTLE_ENDIAN;
+
+import android.hardware.keymaster.HardwareAuthToken;
+import android.hardware.keymaster.Timestamp;
+
+import java.nio.ByteOrder;
+
+/**
+ * Utilities for converting between old and new HardwareAuthToken types. See
+ * {@link HardwareAuthToken}.
+ */
+public class HardwareAuthTokenUtils {
+ public static byte[] toByteArray(HardwareAuthToken hat) {
+ final byte[] array = new byte[69];
+
+ // Version, first byte. Used in hw_auth_token.h but not HardwareAuthToken
+ array[0] = 0;
+
+ // Challenge, 1:8.
+ writeLong(hat.challenge, array, 1 /* offset */);
+
+ // UserId, 9:16.
+ writeLong(hat.userId, array, 9 /* offset */);
+
+ // AuthenticatorId, 17:24.
+ writeLong(hat.authenticatorId, array, 17 /* offset */);
+
+ // AuthenticatorType, 25:28.
+ writeInt(flipIfNativelyLittle(hat.authenticatorType), array, 25 /* offset */);
+
+ // Timestamp, 29:36.
+ writeLong(flipIfNativelyLittle(hat.timestamp.milliSeconds), array, 29 /* offset */);
+
+ // MAC, 37:69. Byte array.
+ System.arraycopy(hat.mac, 0 /* srcPos */, array, 37 /* destPos */, hat.mac.length);
+
+ return array;
+ }
+
+ public static HardwareAuthToken toHardwareAuthToken(byte[] array) {
+ final HardwareAuthToken hardwareAuthToken = new HardwareAuthToken();
+
+ // First byte is version, which doesn't not exist in HardwareAuthToken anymore
+ // Next 8 bytes is the challenge.
+ hardwareAuthToken.challenge = getLong(array, 1 /* offset */);
+
+ // Next 8 bytes is the userId
+ hardwareAuthToken.userId = getLong(array, 9 /* offset */);
+
+ // Next 8 bytes is the authenticatorId.
+ hardwareAuthToken.authenticatorId = getLong(array, 17 /* offset */);
+
+ // Next 4 bytes is the authenticatorType.
+ hardwareAuthToken.authenticatorType = flipIfNativelyLittle(getInt(array, 25 /* offset */));
+
+ // Next 8 bytes is the timestamp.
+ final Timestamp timestamp = new Timestamp();
+ timestamp.milliSeconds = flipIfNativelyLittle(getLong(array, 29 /* offset */));
+ hardwareAuthToken.timestamp = timestamp;
+
+ // Last 32 bytes is the mac, 37:69
+ hardwareAuthToken.mac = new byte[32];
+ System.arraycopy(array, 37 /* srcPos */,
+ hardwareAuthToken.mac,
+ 0 /* destPos */,
+ 32 /* length */);
+
+ return hardwareAuthToken;
+ }
+
+ private static long flipIfNativelyLittle(long l) {
+ if (LITTLE_ENDIAN == ByteOrder.nativeOrder()) {
+ return Long.reverseBytes(l);
+ }
+ return l;
+ }
+
+ private static int flipIfNativelyLittle(int i) {
+ if (LITTLE_ENDIAN == ByteOrder.nativeOrder()) {
+ return Integer.reverseBytes(i);
+ }
+ return i;
+ }
+
+ private static void writeLong(long l, byte[] dest, int offset) {
+ dest[offset + 0] = (byte) l;
+ dest[offset + 1] = (byte) (l >> 8);
+ dest[offset + 2] = (byte) (l >> 16);
+ dest[offset + 3] = (byte) (l >> 24);
+ dest[offset + 4] = (byte) (l >> 32);
+ dest[offset + 5] = (byte) (l >> 40);
+ dest[offset + 6] = (byte) (l >> 48);
+ dest[offset + 7] = (byte) (l >> 56);
+ }
+
+ private static void writeInt(int i, byte[] dest, int offset) {
+ dest[offset + 0] = (byte) i;
+ dest[offset + 1] = (byte) (i >> 8);
+ dest[offset + 2] = (byte) (i >> 16);
+ dest[offset + 3] = (byte) (i >> 24);
+ }
+
+ private static long getLong(byte[] array, int offset) {
+ long result = 0;
+ // Lowest bit is LSB
+ for (int i = 0; i < 8; i++) {
+ result += (long) ((array[i + offset] & 0xffL) << (8 * i));
+ }
+ return result;
+ }
+
+ private static int getInt(byte[] array, int offset) {
+ int result = 0;
+ // Lowest bit is LSB
+ for (int i = 0; i < 4; i++) {
+ result += (int) (((int) array[i + offset] & 0xff) << (8 * i));
+ }
+ return result;
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index f91a11968106..33f5418ee620 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -29,6 +29,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.EnrollClient;
@@ -82,8 +83,8 @@ public class FingerprintEnrollClient extends EnrollClient<ISession> implements U
protected void startHalOperation() {
UdfpsHelper.showUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
try {
- // TODO(b/170163175): Need a way to convert byte arrays to HardwareAuthToken
- getFreshDaemon().enroll(mSequentialId, null /* hat */);
+ getFreshDaemon().enroll(mSequentialId,
+ HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken));
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting enroll", e);
onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/HardwareAuthTokenUtilsTest.java b/services/tests/servicestests/src/com/android/server/biometrics/HardwareAuthTokenUtilsTest.java
new file mode 100644
index 000000000000..84987e641544
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/HardwareAuthTokenUtilsTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 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.biometrics;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.hardware.keymaster.HardwareAuthToken;
+import android.hardware.keymaster.Timestamp;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+@Presubmit
+@SmallTest
+public class HardwareAuthTokenUtilsTest {
+
+ @Test
+ public void testByteArrayLoopBack() {
+ final byte[] hat = new byte[69];
+ for (int i = 0; i < 69; i++) {
+ hat[i] = (byte) i;
+ }
+
+ final HardwareAuthToken hardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hat);
+ final byte[] hat2 = HardwareAuthTokenUtils.toByteArray(hardwareAuthToken);
+
+ for (int i = 0; i < hat.length; i++) {
+ assertEquals(hat[i], hat2[i]);
+ }
+ }
+
+ @Test
+ public void testHardwareAuthTokenLoopBack() {
+ final long testChallenge = 1000L;
+ final long testUserId = 2000L;
+ final long testAuthenticatorId = 3000L;
+ final int testAuthenticatorType = 4000;
+ final long testTimestamp = 5000L;
+
+ final HardwareAuthToken hardwareAuthToken = new HardwareAuthToken();
+ hardwareAuthToken.challenge = testChallenge;
+ hardwareAuthToken.userId = testUserId;
+ hardwareAuthToken.authenticatorId = testAuthenticatorId;
+ hardwareAuthToken.authenticatorType = testAuthenticatorType;
+ hardwareAuthToken.timestamp = new Timestamp();
+ hardwareAuthToken.timestamp.milliSeconds = testTimestamp;
+ hardwareAuthToken.mac = new byte[32];
+
+ for (int i = 0; i < hardwareAuthToken.mac.length; i++) {
+ hardwareAuthToken.mac[i] = (byte) i;
+ }
+
+ final byte[] hat = HardwareAuthTokenUtils.toByteArray(hardwareAuthToken);
+ final HardwareAuthToken hardwareAuthToken2 =
+ HardwareAuthTokenUtils.toHardwareAuthToken(hat);
+
+ assertEquals(testChallenge, hardwareAuthToken2.challenge);
+ assertEquals(testUserId, hardwareAuthToken2.userId);
+ assertEquals(testAuthenticatorId, hardwareAuthToken2.authenticatorId);
+ assertEquals(testAuthenticatorType, hardwareAuthToken2.authenticatorType);
+ assertEquals(testTimestamp, hardwareAuthToken2.timestamp.milliSeconds);
+
+ for (int i = 0; i < hardwareAuthToken.mac.length; i++) {
+ assertEquals(hardwareAuthToken.mac[i], hardwareAuthToken2.mac[i]);
+ }
+ }
+}