From 8fa5665f0e757cec0063fb4cf1354f1596f93a91 Mon Sep 17 00:00:00 2001 From: Andres Morales Date: Tue, 31 Mar 2015 09:19:50 -0700 Subject: [PATCH] Wire up GateKeeper to LockSettingsService Adds: - Communication to GKService - password upgrade flow - enroll takes previous credential Change-Id: I0161b64642be3d0e34ff4a9e6e3ca8569f2d7c0a --- Android.mk | 1 + .../gatekeeper/IGateKeeperService.aidl | 51 ++++++ .../internal/widget/ILockSettings.aidl | 4 +- .../internal/widget/LockPatternUtils.java | 28 +-- .../providers/settings/DatabaseHelper.java | 2 +- .../android/server/LockSettingsService.java | 163 ++++++++++++++++-- .../android/server/LockSettingsStorage.java | 101 +++++++++-- .../DevicePolicyManagerService.java | 2 +- .../server/LockSettingsStorageTests.java | 44 ++--- 9 files changed, 332 insertions(+), 64 deletions(-) create mode 100644 core/java/android/service/gatekeeper/IGateKeeperService.aidl diff --git a/Android.mk b/Android.mk index f4b9551d0c6b5..2c04c18931863 100644 --- a/Android.mk +++ b/Android.mk @@ -209,6 +209,7 @@ LOCAL_SRC_FILES += \ core/java/android/security/IKeystoreService.aidl \ core/java/android/service/carrier/ICarrierMessagingCallback.aidl \ core/java/android/service/carrier/ICarrierMessagingService.aidl \ + core/java/android/service/gatekeeper/IGateKeeperService.aidl \ core/java/android/service/notification/INotificationListener.aidl \ core/java/android/service/notification/IStatusBarNotificationHolder.aidl \ core/java/android/service/notification/IConditionListener.aidl \ diff --git a/core/java/android/service/gatekeeper/IGateKeeperService.aidl b/core/java/android/service/gatekeeper/IGateKeeperService.aidl new file mode 100644 index 0000000000000..675374d3dd2f7 --- /dev/null +++ b/core/java/android/service/gatekeeper/IGateKeeperService.aidl @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015 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 android.service.gatekeeper; + +/** + * Interface for communication with GateKeeper, the + * secure password storage daemon. + * + * This must be kept manually in sync with system/core/gatekeeperd + * until AIDL can generate both C++ and Java bindings. + * + * @hide + */ +interface IGateKeeperService { + /** + * Enrolls a password, returning the handle to the enrollment to be stored locally. + * @param uid The Android user ID associated to this enrollment + * @param currentPasswordHandle The previously enrolled handle, or null if none + * @param currentPassword The previously enrolled plaintext password, or null if none. + * If provided, must verify against the currentPasswordHandle. + * @param desiredPassword The new desired password, for which a handle will be returned + * upon success. + * @return the handle corresponding to desiredPassword, or null + */ + byte[] enroll(int uid, in byte[] currentPasswordHandle, in byte[] currentPassword, + in byte[] desiredPassword); + + /** + * Verifies an enrolled handle against a provided, plaintext blob. + * @param uid The Android user ID associated to this enrollment + * @param enrolledPasswordHandle The handle against which the provided password will be + * verified. + * @param The plaintext blob to verify against enrolledPassword. + * @return true if success, false if failure + */ + boolean verify(int uid, in byte[] enrolledPasswordHandle, in byte[] providedPassword); +} diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 0cb1f38cf11fe..53a860d71e6db 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -24,9 +24,9 @@ interface ILockSettings { boolean getBoolean(in String key, in boolean defaultValue, in int userId); long getLong(in String key, in long defaultValue, in int userId); String getString(in String key, in String defaultValue, in int userId); - void setLockPattern(in String pattern, int userId); + void setLockPattern(in String pattern, in String savedPattern, int userId); boolean checkPattern(in String pattern, int userId); - void setLockPassword(in String password, int userId); + void setLockPassword(in String password, in String savedPassword, int userId); boolean checkPassword(in String password, int userId); boolean checkVoldPassword(int userId); boolean havePattern(int userId); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 2967876b0098c..fce57bd81d9d4 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -425,8 +425,8 @@ public void clearLock(int userHandle) { setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle); try { - getLockSettings().setLockPassword(null, userHandle); - getLockSettings().setLockPattern(null, userHandle); + getLockSettings().setLockPassword(null, null, userHandle); + getLockSettings().setLockPattern(null, null, userHandle); } catch (RemoteException e) { // well, we tried... } @@ -477,24 +477,30 @@ public boolean isLockScreenDisabled() { /** * Save a lock pattern. * @param pattern The new pattern to save. + * @param savedPattern The previously saved pattern, or null if none */ - public void saveLockPattern(List pattern) { - this.saveLockPattern(pattern, getCurrentOrCallingUserId()); + public void saveLockPattern(List pattern, + String savedPattern) { + this.saveLockPattern(pattern, savedPattern, getCurrentOrCallingUserId()); } + public void saveLockPattern(List pattern, int userId) { + this.saveLockPattern(pattern, null, userId); + } /** * Save a lock pattern. * @param pattern The new pattern to save. + * @param savedPattern The previously saved pattern, converted to String format * @param userId the user whose pattern is to be saved. */ - public void saveLockPattern(List pattern, int userId) { + public void saveLockPattern(List pattern, String savedPattern, int userId) { try { if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) { throw new IllegalArgumentException("pattern must not be null and at least " + MIN_LOCK_PATTERN_SIZE + " dots long."); } - getLockSettings().setLockPattern(patternToString(pattern), userId); + getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId); DevicePolicyManager dpm = getDevicePolicyManager(); // Update the device encryption password. @@ -685,10 +691,11 @@ protected Void doInBackground(Void... dummy) { * as the requested mode, but will adjust the mode to be as good as the * pattern. * @param password The password to save + * @param savedPassword The previously saved lock password, or null if none * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} */ - public void saveLockPassword(String password, int quality) { - saveLockPassword(password, quality, getCurrentOrCallingUserId()); + public void saveLockPassword(String password, String savedPassword, int quality) { + saveLockPassword(password, savedPassword, quality, getCurrentOrCallingUserId()); } /** @@ -699,7 +706,8 @@ public void saveLockPassword(String password, int quality) { * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} * @param userHandle The userId of the user to change the password for */ - public void saveLockPassword(String password, int quality, int userHandle) { + public void saveLockPassword(String password, String savedPassword, int quality, + int userHandle) { try { DevicePolicyManager dpm = getDevicePolicyManager(); if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) { @@ -707,7 +715,7 @@ public void saveLockPassword(String password, int quality, int userHandle) { + "of length " + MIN_LOCK_PASSWORD_SIZE); } - getLockSettings().setLockPassword(password, userHandle); + getLockSettings().setLockPassword(password, savedPassword, userHandle); int computedQuality = computePasswordQuality(password); // Update the device encryption password. diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 0b6ab990d3b80..870f043c83ed0 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -2066,7 +2066,7 @@ private void upgradeLockPatternLocation(SQLiteDatabase db) { LockPatternUtils lpu = new LockPatternUtils(mContext); List cellPattern = LockPatternUtils.stringToPattern(lockPattern); - lpu.saveLockPattern(cellPattern); + lpu.saveLockPattern(cellPattern, null); } catch (IllegalArgumentException e) { // Don't want corrupted lock pattern to hang the reboot process } diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index 2e6d1c16d20e8..48f412012f2fe 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -44,12 +44,14 @@ import android.provider.Settings.Secure; import android.provider.Settings.SettingNotFoundException; import android.security.KeyStore; +import android.service.gatekeeper.IGateKeeperService; import android.text.TextUtils; import android.util.Slog; import com.android.internal.util.ArrayUtils; import com.android.internal.widget.ILockSettings; import com.android.internal.widget.LockPatternUtils; +import com.android.server.LockSettingsStorage.CredentialHash; import java.util.Arrays; import java.util.List; @@ -72,6 +74,7 @@ public class LockSettingsService extends ILockSettings.Stub { private LockPatternUtils mLockPatternUtils; private boolean mFirstCallToVold; + private IGateKeeperService mGateKeeperService; public LockSettingsService(Context context) { mContext = context; @@ -131,6 +134,7 @@ public void onReceive(Context context, Intent intent) { public void systemReady() { migrateOldData(); + getGateKeeperService(); mStorage.prefetchUser(UserHandle.USER_OWNER); } @@ -277,7 +281,6 @@ private void setStringUnchecked(String key, int userId, String value) { @Override public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException { checkReadPermission(key, userId); - String value = getStringUnchecked(key, null, userId); return TextUtils.isEmpty(value) ? defaultValue : (value.equals("1") || value.equals("true")); @@ -345,40 +348,133 @@ private void maybeUpdateKeystore(String password, int userHandle) { } } + + private byte[] getCurrentHandle(int userId) { + CredentialHash credential; + byte[] currentHandle; + + int currentHandleType = mStorage.getStoredCredentialType(userId); + switch (currentHandleType) { + case CredentialHash.TYPE_PATTERN: + credential = mStorage.readPatternHash(userId); + currentHandle = credential != null + ? credential.hash + : null; + break; + case CredentialHash.TYPE_PASSWORD: + credential = mStorage.readPasswordHash(userId); + currentHandle = credential != null + ? credential.hash + : null; + break; + case CredentialHash.TYPE_NONE: + default: + currentHandle = null; + break; + } + + // sanity check + if (currentHandleType != CredentialHash.TYPE_NONE && currentHandle == null) { + Slog.e(TAG, "Stored handle type [" + currentHandleType + "] but no handle available"); + } + + return currentHandle; + } + + @Override - public void setLockPattern(String pattern, int userId) throws RemoteException { - checkWritePermission(userId); + public void setLockPattern(String pattern, String savedCredential, int userId) + throws RemoteException { + byte[] currentHandle = getCurrentHandle(userId); - maybeUpdateKeystore(pattern, userId); + if (currentHandle == null) { + if (savedCredential != null) { + Slog.w(TAG, "Saved credential provided, but none stored"); + } + savedCredential = null; + } - final byte[] hash = LockPatternUtils.patternToHash( - LockPatternUtils.stringToPattern(pattern)); - mStorage.writePatternHash(hash, userId); + byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId); + if (enrolledHandle != null) { + mStorage.writePatternHash(enrolledHandle, userId); + } else { + Slog.e(TAG, "Failed to enroll pattern"); + } } + @Override - public void setLockPassword(String password, int userId) throws RemoteException { - checkWritePermission(userId); + public void setLockPassword(String password, String savedCredential, int userId) + throws RemoteException { - maybeUpdateKeystore(password, userId); + byte[] currentHandle = getCurrentHandle(userId); + + if (currentHandle == null) { + if (savedCredential != null) { + Slog.w(TAG, "Saved credential provided, but none stored"); + } + savedCredential = null; + } + + byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId); + if (enrolledHandle != null) { + mStorage.writePasswordHash(enrolledHandle, userId); + } else { + Slog.e(TAG, "Failed to enroll password"); + } + } + + private byte[] enrollCredential(byte[] enrolledHandle, + String enrolledCredential, String toEnroll, int userId) + throws RemoteException { + checkWritePermission(userId); + byte[] enrolledCredentialBytes = enrolledCredential == null + ? null + : enrolledCredential.getBytes(); + byte[] toEnrollBytes = toEnroll == null + ? null + : toEnroll.getBytes(); + byte[] hash = getGateKeeperService().enroll(userId, enrolledHandle, enrolledCredentialBytes, + toEnrollBytes); + + if (hash != null) { + maybeUpdateKeystore(toEnroll, userId); + } - mStorage.writePasswordHash(mLockPatternUtils.passwordToHash(password, userId), userId); + return hash; } @Override public boolean checkPattern(String pattern, int userId) throws RemoteException { checkPasswordReadPermission(userId); - byte[] hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(pattern)); - byte[] storedHash = mStorage.readPatternHash(userId); + + CredentialHash storedHash = mStorage.readPatternHash(userId); if (storedHash == null) { return true; } - boolean matched = Arrays.equals(hash, storedHash); + if (storedHash.version == CredentialHash.VERSION_LEGACY) { + // Try the old backend and upgrade if a match is found + byte[] hash = LockPatternUtils.patternToHash( + LockPatternUtils.stringToPattern(pattern)); + boolean matched = Arrays.equals(hash, storedHash.hash); + if (matched && !TextUtils.isEmpty(pattern)) { + maybeUpdateKeystore(pattern, userId); + // migrate pattern to GateKeeper + setLockPattern(pattern, null, userId); + } + + return matched; + } + + boolean matched = getGateKeeperService() + .verify(userId, storedHash.hash, pattern.getBytes()); if (matched && !TextUtils.isEmpty(pattern)) { maybeUpdateKeystore(pattern, userId); + return true; } + return matched; } @@ -386,17 +482,31 @@ public boolean checkPattern(String pattern, int userId) throws RemoteException { public boolean checkPassword(String password, int userId) throws RemoteException { checkPasswordReadPermission(userId); - byte[] hash = mLockPatternUtils.passwordToHash(password, userId); - byte[] storedHash = mStorage.readPasswordHash(userId); + CredentialHash storedHash = mStorage.readPasswordHash(userId); if (storedHash == null) { return true; } - boolean matched = Arrays.equals(hash, storedHash); - if (matched && !TextUtils.isEmpty(password)) { + if (storedHash.version == CredentialHash.VERSION_LEGACY) { + byte[] hash = mLockPatternUtils.passwordToHash(password, userId); + boolean matched = Arrays.equals(hash, storedHash.hash); + if (matched && !TextUtils.isEmpty(password)) { + maybeUpdateKeystore(password, userId); + // migrate password to GateKeeper + setLockPassword(password, null, userId); + } + return matched; + } + + + + boolean matched = getGateKeeperService() + .verify(userId, storedHash.hash, password.getBytes()); + if (!TextUtils.isEmpty(password) && matched) { maybeUpdateKeystore(password, userId); } + return matched; } @@ -497,4 +607,21 @@ private IMountService getMountService() { } return null; } + + private synchronized IGateKeeperService getGateKeeperService() { + if (mGateKeeperService != null) { + return mGateKeeperService; + } + + final IBinder service = + ServiceManager.getService("android.service.gatekeeper.IGateKeeperService"); + if (service != null) { + mGateKeeperService = IGateKeeperService.Stub.asInterface(service); + return mGateKeeperService; + } + + Slog.e(TAG, "Unable to acquire GateKeeperService"); + return null; + } + } diff --git a/services/core/java/com/android/server/LockSettingsStorage.java b/services/core/java/com/android/server/LockSettingsStorage.java index d81daa904de51..f202c3657eca3 100644 --- a/services/core/java/com/android/server/LockSettingsStorage.java +++ b/services/core/java/com/android/server/LockSettingsStorage.java @@ -56,8 +56,10 @@ class LockSettingsStorage { }; private static final String SYSTEM_DIRECTORY = "/system/"; - private static final String LOCK_PATTERN_FILE = "gesture.key"; - private static final String LOCK_PASSWORD_FILE = "password.key"; + private static final String LOCK_PATTERN_FILE = "gatekeeper.gesture.key"; + private static final String LEGACY_LOCK_PATTERN_FILE = "gesture.key"; + private static final String LOCK_PASSWORD_FILE = "gatekeeper.password.key"; + private static final String LEGACY_LOCK_PASSWORD_FILE = "password.key"; private static final Object DEFAULT = new Object(); @@ -66,6 +68,25 @@ class LockSettingsStorage { private final Cache mCache = new Cache(); private final Object mFileWriteLock = new Object(); + private int mStoredCredentialType; + + class CredentialHash { + static final int TYPE_NONE = -1; + static final int TYPE_PATTERN = 1; + static final int TYPE_PASSWORD = 2; + + static final int VERSION_LEGACY = 0; + static final int VERSION_GATEKEEPER = 1; + + CredentialHash(byte[] hash, int version) { + this.hash = hash; + this.version = version; + } + + byte[] hash; + int version; + } + public LockSettingsStorage(Context context, Callback callback) { mContext = context; mOpenHelper = new DatabaseHelper(context, callback); @@ -148,28 +169,72 @@ public void prefetchUser(int userId) { readPatternHash(userId); } - public byte[] readPasswordHash(int userId) { - final byte[] stored = readFile(getLockPasswordFilename(userId)); + public int getStoredCredentialType(int userId) { + if (mStoredCredentialType != 0) { + return mStoredCredentialType; + } + + CredentialHash pattern = readPatternHash(userId); + if (pattern == null) { + if (readPasswordHash(userId) != null) { + mStoredCredentialType = CredentialHash.TYPE_PASSWORD; + } else { + mStoredCredentialType = CredentialHash.TYPE_NONE; + } + } else { + CredentialHash password = readPasswordHash(userId); + if (password != null) { + // Both will never be GateKeeper + if (password.version == CredentialHash.VERSION_GATEKEEPER) { + mStoredCredentialType = CredentialHash.TYPE_PASSWORD; + } else { + mStoredCredentialType = CredentialHash.TYPE_PATTERN; + } + } else { + mStoredCredentialType = CredentialHash.TYPE_PATTERN; + } + } + + return mStoredCredentialType; + } + + + public CredentialHash readPasswordHash(int userId) { + byte[] stored = readFile(getLockPasswordFilename(userId)); if (stored != null && stored.length > 0) { - return stored; + return new CredentialHash(stored, CredentialHash.VERSION_GATEKEEPER); } + + stored = readFile(getLegacyLockPasswordFilename(userId)); + if (stored != null && stored.length > 0) { + return new CredentialHash(stored, CredentialHash.VERSION_LEGACY); + } + return null; } - public byte[] readPatternHash(int userId) { - final byte[] stored = readFile(getLockPatternFilename(userId)); + public CredentialHash readPatternHash(int userId) { + byte[] stored = readFile(getLockPatternFilename(userId)); if (stored != null && stored.length > 0) { - return stored; + return new CredentialHash(stored, CredentialHash.VERSION_GATEKEEPER); } + + stored = readFile(getLegacyLockPatternFilename(userId)); + if (stored != null && stored.length > 0) { + return new CredentialHash(stored, CredentialHash.VERSION_LEGACY); + } + return null; } public boolean hasPassword(int userId) { - return hasFile(getLockPasswordFilename(userId)); + return hasFile(getLockPasswordFilename(userId)) || + hasFile(getLegacyLockPasswordFilename(userId)); } public boolean hasPattern(int userId) { - return hasFile(getLockPatternFilename(userId)); + return hasFile(getLockPatternFilename(userId)) || + hasFile(getLegacyLockPatternFilename(userId)); } private boolean hasFile(String name) { @@ -237,6 +302,9 @@ private void writeFile(String name, byte[] hash) { } public void writePatternHash(byte[] hash, int userId) { + mStoredCredentialType = hash == null + ? CredentialHash.TYPE_NONE + : CredentialHash.TYPE_PATTERN; writeFile(getLockPatternFilename(userId), hash); clearPasswordHash(userId); } @@ -246,6 +314,9 @@ private void clearPatternHash(int userId) { } public void writePasswordHash(byte[] hash, int userId) { + mStoredCredentialType = hash == null + ? CredentialHash.TYPE_NONE + : CredentialHash.TYPE_PASSWORD; writeFile(getLockPasswordFilename(userId), hash); clearPatternHash(userId); } @@ -264,6 +335,16 @@ String getLockPasswordFilename(int userId) { return getLockCredentialFilePathForUser(userId, LOCK_PASSWORD_FILE); } + @VisibleForTesting + String getLegacyLockPatternFilename(int userId) { + return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PATTERN_FILE); + } + + @VisibleForTesting + String getLegacyLockPasswordFilename(int userId) { + return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PASSWORD_FILE); + } + private String getLockCredentialFilePathForUser(int userId, String basename) { userId = getUserParentOrSelfId(userId); String dataSystemDirectory = diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 3677132ae08d3..2ff80c63b2ca0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -2799,7 +2799,7 @@ public boolean resetPassword(String passwordOrNull, int flags) { try { LockPatternUtils utils = new LockPatternUtils(mContext); if (!TextUtils.isEmpty(password)) { - utils.saveLockPassword(password, quality, userHandle); + utils.saveLockPassword(password, null, quality, userHandle); } else { utils.clearLock(userHandle); } diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java index bf0e75d297ffa..dae84471d40e9 100644 --- a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java +++ b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java @@ -219,31 +219,31 @@ public void testPassword_Default() { public void testPassword_Write() { mStorage.writePasswordHash("thepassword".getBytes(), 0); - assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0)); + assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0).hash); mStorage.clearCache(); - assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0)); + assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0).hash); } public void testPassword_WriteProfileWritesParent() { mStorage.writePasswordHash("parentpasswordd".getBytes(), 1); mStorage.writePasswordHash("profilepassword".getBytes(), 2); - assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1)); - assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2)); + assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1).hash); + assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2).hash); mStorage.clearCache(); - assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1)); - assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2)); + assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1).hash); + assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2).hash); } public void testPassword_WriteParentWritesProfile() { mStorage.writePasswordHash("profilepassword".getBytes(), 2); mStorage.writePasswordHash("parentpasswordd".getBytes(), 1); - assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1)); - assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2)); + assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1).hash); + assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2).hash); mStorage.clearCache(); - assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1)); - assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2)); + assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1).hash); + assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2).hash); } public void testPattern_Default() { @@ -253,31 +253,31 @@ public void testPattern_Default() { public void testPattern_Write() { mStorage.writePatternHash("thepattern".getBytes(), 0); - assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0)); + assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0).hash); mStorage.clearCache(); - assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0)); + assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0).hash); } public void testPattern_WriteProfileWritesParent() { mStorage.writePatternHash("parentpatternn".getBytes(), 1); mStorage.writePatternHash("profilepattern".getBytes(), 2); - assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1)); - assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2)); + assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1).hash); + assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2).hash); mStorage.clearCache(); - assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1)); - assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2)); + assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1).hash); + assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2).hash); } public void testPattern_WriteParentWritesProfile() { mStorage.writePatternHash("profilepattern".getBytes(), 2); mStorage.writePatternHash("parentpatternn".getBytes(), 1); - assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1)); - assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2)); + assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1).hash); + assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2).hash); mStorage.clearCache(); - assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1)); - assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2)); + assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1).hash); + assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2).hash); } public void testPrefetch() { @@ -289,8 +289,8 @@ public void testPrefetch() { mStorage.prefetchUser(0); assertEquals("toBeFetched", mStorage.readKeyValue("key", "default", 0)); - assertArrayEquals("pattern".getBytes(), mStorage.readPatternHash(0)); - assertArrayEquals("password".getBytes(), mStorage.readPasswordHash(0)); + assertArrayEquals("pattern".getBytes(), mStorage.readPatternHash(0).hash); + assertArrayEquals("password".getBytes(), mStorage.readPasswordHash(0).hash); } public void testFileLocation_Owner() {