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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 */);
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user