Merge "Use Scrypt to hash long passwords in RecoverableKeyStore" into pi-dev

am: e73074e9a8

Change-Id: I50e3ee0083badc478dd9be5c647b351bfd2a840c
This commit is contained in:
Bo Zhu
2018-04-04 12:33:10 -07:00
committed by android-build-merger
3 changed files with 283 additions and 26 deletions

View File

@@ -20,6 +20,7 @@ import static android.security.keystore.recovery.KeyChainProtectionParams.TYPE_L
import android.annotation.Nullable;
import android.content.Context;
import android.security.Scrypt;
import android.security.keystore.recovery.KeyChainProtectionParams;
import android.security.keystore.recovery.KeyChainSnapshot;
import android.security.keystore.recovery.KeyDerivationParams;
@@ -69,6 +70,17 @@ public class KeySyncTask implements Runnable {
private static final String LOCK_SCREEN_HASH_ALGORITHM = "SHA-256";
private static final int TRUSTED_HARDWARE_MAX_ATTEMPTS = 10;
// TODO: Reduce the minimal length once all other components are updated
private static final int MIN_CREDENTIAL_LEN_TO_USE_SCRYPT = 24;
@VisibleForTesting
static final int SCRYPT_PARAM_N = 4096;
@VisibleForTesting
static final int SCRYPT_PARAM_R = 8;
@VisibleForTesting
static final int SCRYPT_PARAM_P = 1;
@VisibleForTesting
static final int SCRYPT_PARAM_OUTLEN_BYTES = 32;
private final RecoverableKeyStoreDb mRecoverableKeyStoreDb;
private final int mUserId;
private final int mCredentialType;
@@ -78,6 +90,7 @@ public class KeySyncTask implements Runnable {
private final RecoverySnapshotStorage mRecoverySnapshotStorage;
private final RecoverySnapshotListenersStorage mSnapshotListenersStorage;
private final TestOnlyInsecureCertificateHelper mTestOnlyInsecureCertificateHelper;
private final Scrypt mScrypt;
public static KeySyncTask newInstance(
Context context,
@@ -98,7 +111,8 @@ public class KeySyncTask implements Runnable {
credential,
credentialUpdated,
PlatformKeyManager.getInstance(context, recoverableKeyStoreDb),
new TestOnlyInsecureCertificateHelper());
new TestOnlyInsecureCertificateHelper(),
new Scrypt());
}
/**
@@ -110,7 +124,7 @@ public class KeySyncTask implements Runnable {
* @param credential The credential, encoded as a {@link String}.
* @param credentialUpdated signals weather credentials were updated.
* @param platformKeyManager platform key manager
* @param TestOnlyInsecureCertificateHelper utility class used for end-to-end tests
* @param testOnlyInsecureCertificateHelper utility class used for end-to-end tests
*/
@VisibleForTesting
KeySyncTask(
@@ -122,7 +136,8 @@ public class KeySyncTask implements Runnable {
String credential,
boolean credentialUpdated,
PlatformKeyManager platformKeyManager,
TestOnlyInsecureCertificateHelper TestOnlyInsecureCertificateHelper) {
TestOnlyInsecureCertificateHelper testOnlyInsecureCertificateHelper,
Scrypt scrypt) {
mSnapshotListenersStorage = recoverySnapshotListenersStorage;
mRecoverableKeyStoreDb = recoverableKeyStoreDb;
mUserId = userId;
@@ -131,7 +146,8 @@ public class KeySyncTask implements Runnable {
mCredentialUpdated = credentialUpdated;
mPlatformKeyManager = platformKeyManager;
mRecoverySnapshotStorage = snapshotStorage;
mTestOnlyInsecureCertificateHelper = TestOnlyInsecureCertificateHelper;
mTestOnlyInsecureCertificateHelper = testOnlyInsecureCertificateHelper;
mScrypt = scrypt;
}
@Override
@@ -230,8 +246,14 @@ public class KeySyncTask implements Runnable {
}
}
boolean useScryptToHashCredential = shouldUseScryptToHashCredential(rootCertAlias);
byte[] salt = generateSalt();
byte[] localLskfHash = hashCredentials(salt, mCredential);
byte[] localLskfHash;
if (useScryptToHashCredential) {
localLskfHash = hashCredentialsByScrypt(salt, mCredential);
} else {
localLskfHash = hashCredentialsBySaltedSha256(salt, mCredential);
}
Map<String, SecretKey> rawKeys;
try {
@@ -303,10 +325,17 @@ public class KeySyncTask implements Runnable {
Log.e(TAG,"Could not encrypt with recovery key", e);
return;
}
KeyDerivationParams keyDerivationParams;
if (useScryptToHashCredential) {
keyDerivationParams = KeyDerivationParams.createScryptParams(
salt, /*memoryDifficulty=*/ SCRYPT_PARAM_N);
} else {
keyDerivationParams = KeyDerivationParams.createSha256Params(salt);
}
KeyChainProtectionParams metadata = new KeyChainProtectionParams.Builder()
.setUserSecretType(TYPE_LOCKSCREEN)
.setLockScreenUiFormat(getUiFormat(mCredentialType, mCredential))
.setKeyDerivationParams(KeyDerivationParams.createSha256Params(salt))
.setKeyDerivationParams(keyDerivationParams)
.setSecret(new byte[0])
.build();
@@ -443,7 +472,7 @@ public class KeySyncTask implements Runnable {
* @return The SHA-256 hash.
*/
@VisibleForTesting
static byte[] hashCredentials(byte[] salt, String credentials) {
static byte[] hashCredentialsBySaltedSha256(byte[] salt, String credentials) {
byte[] credentialsBytes = credentials.getBytes(StandardCharsets.UTF_8);
ByteBuffer byteBuffer = ByteBuffer.allocate(
salt.length + credentialsBytes.length + LENGTH_PREFIX_BYTES * 2);
@@ -462,6 +491,12 @@ public class KeySyncTask implements Runnable {
}
}
private byte[] hashCredentialsByScrypt(byte[] salt, String credentials) {
return mScrypt.scrypt(
credentials.getBytes(StandardCharsets.UTF_8), salt,
SCRYPT_PARAM_N, SCRYPT_PARAM_R, SCRYPT_PARAM_P, SCRYPT_PARAM_OUTLEN_BYTES);
}
private static SecretKey generateRecoveryKey() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(RECOVERY_KEY_ALGORITHM);
keyGenerator.init(RECOVERY_KEY_SIZE_BITS);
@@ -479,4 +514,11 @@ public class KeySyncTask implements Runnable {
}
return keyEntries;
}
private boolean shouldUseScryptToHashCredential(String rootCertAlias) {
return mCredentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
&& mCredential.length() >= MIN_CREDENTIAL_LEN_TO_USE_SCRYPT
// TODO: Remove the test cert check once all other components are updated
&& mTestOnlyInsecureCertificateHelper.isTestOnlyCertificateAlias(rootCertAlias);
}
}

View File

@@ -50,6 +50,7 @@ import android.security.keystore.KeyProperties;
import android.security.keystore.recovery.KeyChainSnapshot;
import android.security.keystore.recovery.KeyDerivationParams;
import android.security.keystore.recovery.RecoveryController;
import android.security.keystore.recovery.TrustedRootCertificates;
import android.security.keystore.recovery.WrappedApplicationKey;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
@@ -101,6 +102,7 @@ public class KeySyncTaskTest {
@Mock private PlatformKeyManager mPlatformKeyManager;
@Mock private RecoverySnapshotListenersStorage mSnapshotListenersStorage;
@Spy private TestOnlyInsecureCertificateHelper mTestOnlyInsecureCertificateHelper;
@Spy private MockScrypt mMockScrypt;
private RecoverySnapshotStorage mRecoverySnapshotStorage;
private RecoverableKeyStoreDb mRecoverableKeyStoreDb;
@@ -138,7 +140,8 @@ public class KeySyncTaskTest {
TEST_CREDENTIAL,
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper);
mTestOnlyInsecureCertificateHelper,
mMockScrypt);
mWrappingKey = generateAndroidKeyStoreKey();
mEncryptKey = new PlatformEncryptionKey(TEST_GENERATION_ID, mWrappingKey);
@@ -172,41 +175,41 @@ public class KeySyncTaskTest {
}
@Test
public void hashCredentials_returnsSameHashForSameCredentialsAndSalt() {
public void hashCredentialsBySaltedSha256_returnsSameHashForSameCredentialsAndSalt() {
String credentials = "password1234";
byte[] salt = randomBytes(16);
assertArrayEquals(
KeySyncTask.hashCredentials(salt, credentials),
KeySyncTask.hashCredentials(salt, credentials));
KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials),
KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials));
}
@Test
public void hashCredentials_returnsDifferentHashForDifferentCredentials() {
public void hashCredentialsBySaltedSha256_returnsDifferentHashForDifferentCredentials() {
byte[] salt = randomBytes(16);
assertFalse(
Arrays.equals(
KeySyncTask.hashCredentials(salt, "password1234"),
KeySyncTask.hashCredentials(salt, "password12345")));
KeySyncTask.hashCredentialsBySaltedSha256(salt, "password1234"),
KeySyncTask.hashCredentialsBySaltedSha256(salt, "password12345")));
}
@Test
public void hashCredentials_returnsDifferentHashForDifferentSalt() {
public void hashCredentialsBySaltedSha256_returnsDifferentHashForDifferentSalt() {
String credentials = "wowmuch";
assertFalse(
Arrays.equals(
KeySyncTask.hashCredentials(randomBytes(64), credentials),
KeySyncTask.hashCredentials(randomBytes(64), credentials)));
KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), credentials),
KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), credentials)));
}
@Test
public void hashCredentials_returnsDifferentHashEvenIfConcatIsSame() {
public void hashCredentialsBySaltedSha256_returnsDifferentHashEvenIfConcatIsSame() {
assertFalse(
Arrays.equals(
KeySyncTask.hashCredentials(utf8Bytes("123"), "4567"),
KeySyncTask.hashCredentials(utf8Bytes("1234"), "567")));
KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("123"), "4567"),
KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("1234"), "567")));
}
@Test
@@ -276,6 +279,155 @@ public class KeySyncTaskTest {
assertNull(mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID));
}
@Test
public void run_useScryptToHashLongPasswordInTestMode() throws Exception {
String longPassword = TrustedRootCertificates.INSECURE_PASSWORD_PREFIX + "0123456789";
String appKeyAlias = TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX + "alias";
mKeySyncTask = new KeySyncTask(
mRecoverableKeyStoreDb,
mRecoverySnapshotStorage,
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PASSWORD,
/*credential=*/ longPassword,
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
mMockScrypt);
mRecoverableKeyStoreDb.setServerParams(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID);
mRecoverableKeyStoreDb.setActiveRootOfTrust(TEST_USER_ID, TEST_RECOVERY_AGENT_UID,
TrustedRootCertificates.TEST_ONLY_INSECURE_CERTIFICATE_ALIAS);
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID,
TrustedRootCertificates.TEST_ONLY_INSECURE_CERTIFICATE_ALIAS,
TestData.getInsecureCertPathForEndpoint1());
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, appKeyAlias);
mKeySyncTask.run();
KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
assertThat(keyChainSnapshot.getKeyChainProtectionParams()).hasSize(1);
assertThat(keyChainSnapshot.getKeyChainProtectionParams().get(0).getLockScreenUiFormat()).
isEqualTo(UI_FORMAT_PASSWORD);
verify(mMockScrypt).scrypt(eq(longPassword.getBytes()), any(),
eq(KeySyncTask.SCRYPT_PARAM_N), eq(KeySyncTask.SCRYPT_PARAM_R),
eq(KeySyncTask.SCRYPT_PARAM_P), eq(KeySyncTask.SCRYPT_PARAM_OUTLEN_BYTES));
KeyDerivationParams keyDerivationParams =
keyChainSnapshot.getKeyChainProtectionParams().get(0).getKeyDerivationParams();
assertThat(keyDerivationParams.getAlgorithm()).isEqualTo(
KeyDerivationParams.ALGORITHM_SCRYPT);
assertThat(keyDerivationParams.getMemoryDifficulty()).isEqualTo(KeySyncTask.SCRYPT_PARAM_N);
}
@Test
public void run_useSha256ToHashShortPasswordInTestMode() throws Exception {
String shortPassword = TrustedRootCertificates.INSECURE_PASSWORD_PREFIX + "012345678";
String appKeyAlias = TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX + "alias";
mKeySyncTask = new KeySyncTask(
mRecoverableKeyStoreDb,
mRecoverySnapshotStorage,
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PASSWORD,
/*credential=*/ shortPassword,
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
mMockScrypt);
mRecoverableKeyStoreDb.setServerParams(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID);
mRecoverableKeyStoreDb.setActiveRootOfTrust(TEST_USER_ID, TEST_RECOVERY_AGENT_UID,
TrustedRootCertificates.TEST_ONLY_INSECURE_CERTIFICATE_ALIAS);
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID,
TrustedRootCertificates.TEST_ONLY_INSECURE_CERTIFICATE_ALIAS,
TestData.getInsecureCertPathForEndpoint1());
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, appKeyAlias);
mKeySyncTask.run();
KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
assertThat(keyChainSnapshot.getKeyChainProtectionParams()).hasSize(1);
assertThat(keyChainSnapshot.getKeyChainProtectionParams().get(0).getLockScreenUiFormat()).
isEqualTo(UI_FORMAT_PASSWORD);
verify(mMockScrypt, never()).scrypt(any(), any(), anyInt(), anyInt(), anyInt(), anyInt());
KeyDerivationParams keyDerivationParams =
keyChainSnapshot.getKeyChainProtectionParams().get(0).getKeyDerivationParams();
assertThat(keyDerivationParams.getAlgorithm()).isEqualTo(
KeyDerivationParams.ALGORITHM_SHA256);
}
@Test
public void run_useSha256ToHashShortPasswordInProdMode() throws Exception {
String shortPassword = "01234567890123456789abc"; // 23 chars
mKeySyncTask = new KeySyncTask(
mRecoverableKeyStoreDb,
mRecoverySnapshotStorage,
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PASSWORD,
/*credential=*/ shortPassword,
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
mMockScrypt);
mRecoverableKeyStoreDb.setServerParams(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID);
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
mKeySyncTask.run();
KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
assertThat(keyChainSnapshot.getKeyChainProtectionParams()).hasSize(1);
assertThat(keyChainSnapshot.getKeyChainProtectionParams().get(0).getLockScreenUiFormat()).
isEqualTo(UI_FORMAT_PASSWORD);
verify(mMockScrypt, never()).scrypt(any(), any(), anyInt(), anyInt(), anyInt(), anyInt());
KeyDerivationParams keyDerivationParams =
keyChainSnapshot.getKeyChainProtectionParams().get(0).getKeyDerivationParams();
assertThat(keyDerivationParams.getAlgorithm()).isEqualTo(
KeyDerivationParams.ALGORITHM_SHA256);
}
@Test
public void run_useSha256ToHashLongPasswordInProdMode() throws Exception {
String longPassword = "01234567890123456789abcd"; // 24 chars
mKeySyncTask = new KeySyncTask(
mRecoverableKeyStoreDb,
mRecoverySnapshotStorage,
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PASSWORD,
/*credential=*/ longPassword,
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
mMockScrypt);
mRecoverableKeyStoreDb.setServerParams(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID);
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
mKeySyncTask.run();
KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
assertThat(keyChainSnapshot.getKeyChainProtectionParams()).hasSize(1);
assertThat(keyChainSnapshot.getKeyChainProtectionParams().get(0).getLockScreenUiFormat()).
isEqualTo(UI_FORMAT_PASSWORD);
verify(mMockScrypt, never()).scrypt(any(), any(), anyInt(), anyInt(), anyInt(), anyInt());
KeyDerivationParams keyDerivationParams =
keyChainSnapshot.getKeyChainProtectionParams().get(0).getKeyDerivationParams();
assertThat(keyDerivationParams.getAlgorithm()).isEqualTo(
KeyDerivationParams.ALGORITHM_SHA256);
}
@Test
public void run_stillCreatesSnapshotIfNoRecoveryAgentPendingIntentRegistered()
throws Exception {
@@ -319,6 +471,7 @@ public class KeySyncTaskTest {
assertNotNull(keyChainSnapshot); // created snapshot
List<WrappedApplicationKey> applicationKeys = keyChainSnapshot.getWrappedApplicationKeys();
assertThat(applicationKeys).hasSize(0); // non whitelisted key is not included
verify(mMockScrypt, never()).scrypt(any(), any(), anyInt(), anyInt(), anyInt(), anyInt());
}
@Test
@@ -341,6 +494,7 @@ public class KeySyncTaskTest {
.getDefaultCertificateAliasIfEmpty(eq(TEST_ROOT_CERT_ALIAS));
verify(mTestOnlyInsecureCertificateHelper)
.doesCredentialSupportInsecureMode(anyInt(), any());
verify(mMockScrypt, never()).scrypt(any(), any(), anyInt(), anyInt(), anyInt(), anyInt());
}
@Test
@@ -404,7 +558,7 @@ public class KeySyncTaskTest {
assertThat(keyDerivationParams.getAlgorithm()).isEqualTo(
KeyDerivationParams.ALGORITHM_SHA256);
verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID);
byte[] lockScreenHash = KeySyncTask.hashCredentials(
byte[] lockScreenHash = KeySyncTask.hashCredentialsBySaltedSha256(
keyDerivationParams.getSalt(),
TEST_CREDENTIAL);
Long counterId = mRecoverableKeyStoreDb.getCounterId(TEST_USER_ID, TEST_RECOVERY_AGENT_UID);
@@ -501,7 +655,8 @@ public class KeySyncTaskTest {
"password",
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper);
mTestOnlyInsecureCertificateHelper,
mMockScrypt);
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
@@ -515,9 +670,10 @@ public class KeySyncTaskTest {
assertThat(keyChainSnapshot.getKeyChainProtectionParams()).hasSize(1);
assertThat(keyChainSnapshot.getKeyChainProtectionParams().get(0).getLockScreenUiFormat()).
isEqualTo(UI_FORMAT_PASSWORD);
verify(mMockScrypt, never()).scrypt(any(), any(), anyInt(), anyInt(), anyInt(), anyInt());
}
@Test
@Test
public void run_setsCorrectTypeForPin() throws Exception {
mKeySyncTask = new KeySyncTask(
mRecoverableKeyStoreDb,
@@ -528,7 +684,8 @@ public class KeySyncTaskTest {
/*credential=*/ "1234",
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper);
mTestOnlyInsecureCertificateHelper,
mMockScrypt);
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
@@ -543,6 +700,7 @@ public class KeySyncTaskTest {
// Password with only digits is changed to pin.
assertThat(keyChainSnapshot.getKeyChainProtectionParams().get(0).getLockScreenUiFormat()).
isEqualTo(UI_FORMAT_PIN);
verify(mMockScrypt, never()).scrypt(any(), any(), anyInt(), anyInt(), anyInt(), anyInt());
}
@Test
@@ -556,7 +714,8 @@ public class KeySyncTaskTest {
"12345",
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper);
mTestOnlyInsecureCertificateHelper,
mMockScrypt);
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
@@ -570,6 +729,7 @@ public class KeySyncTaskTest {
assertThat(keyChainSnapshot.getKeyChainProtectionParams()).hasSize(1);
assertThat(keyChainSnapshot.getKeyChainProtectionParams().get(0).getLockScreenUiFormat()).
isEqualTo(UI_FORMAT_PATTERN);
verify(mMockScrypt, never()).scrypt(any(), any(), anyInt(), anyInt(), anyInt(), anyInt());
}
@Test
@@ -638,7 +798,8 @@ public class KeySyncTaskTest {
"12345",
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper);
mTestOnlyInsecureCertificateHelper,
mMockScrypt);
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
@@ -654,6 +815,7 @@ public class KeySyncTaskTest {
.getStatusForAllKeys(TEST_RECOVERY_AGENT_UID)
.get(TEST_APP_KEY_ALIAS);
assertEquals(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE, status);
verify(mMockScrypt, never()).scrypt(any(), any(), anyInt(), anyInt(), anyInt(), anyInt());
}
private SecretKey addApplicationKey(int userId, int recoveryAgentUid, String alias)

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2018 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.locksettings.recoverablekeystore;
import static org.junit.Assert.assertEquals;
import android.security.Scrypt;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MockScrypt extends Scrypt {
@Override
public byte[] scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen) {
assertEquals(32, outLen);
ByteBuffer byteBuffer = ByteBuffer.allocate(
password.length + salt.length + Integer.BYTES * 6);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
byteBuffer.putInt(password.length);
byteBuffer.put(password);
byteBuffer.putInt(salt.length);
byteBuffer.put(salt);
byteBuffer.putInt(n);
byteBuffer.putInt(r);
byteBuffer.putInt(p);
byteBuffer.putInt(outLen);
try {
return MessageDigest.getInstance("SHA-256").digest(byteBuffer.array());
} catch (NoSuchAlgorithmException e) {
// Should never happen
throw new RuntimeException(e);
}
}
}