diff options
| author | 2020-10-07 19:03:06 -0700 | |
|---|---|---|
| committer | 2020-10-09 13:18:13 -0700 | |
| commit | 275aa876db4d562b965c54868380b00c2b05c16c (patch) | |
| tree | b5c423af3dac0301db736acd29311cd0a42ba71a | |
| parent | 06e8478edbc5460fc086bb09ae33713b3bfc8789 (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
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]); + } + } +} |