Skip to content
Snippets Groups Projects
Commit 275aa876 authored by Kevin Chyn's avatar Kevin Chyn
Browse files

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
parent 06e8478e
No related branches found
No related tags found
No related merge requests found
/*
* 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;
}
}
......@@ -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 */);
......
/*
* 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]);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment