• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.locksettings;
18 
19 import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.app.admin.PasswordMetrics;
25 import android.content.Context;
26 import android.content.pm.UserInfo;
27 import android.hardware.weaver.V1_0.IWeaver;
28 import android.hardware.weaver.V1_0.WeaverConfig;
29 import android.hardware.weaver.V1_0.WeaverReadResponse;
30 import android.hardware.weaver.V1_0.WeaverReadStatus;
31 import android.hardware.weaver.V1_0.WeaverStatus;
32 import android.os.RemoteCallbackList;
33 import android.os.RemoteException;
34 import android.os.UserManager;
35 import android.security.GateKeeper;
36 import android.security.Scrypt;
37 import android.service.gatekeeper.GateKeeperResponse;
38 import android.service.gatekeeper.IGateKeeperService;
39 import android.util.ArrayMap;
40 import android.util.ArraySet;
41 import android.util.Slog;
42 
43 import com.android.internal.annotations.VisibleForTesting;
44 import com.android.internal.util.ArrayUtils;
45 import com.android.internal.widget.ICheckCredentialProgressCallback;
46 import com.android.internal.widget.IWeakEscrowTokenRemovedListener;
47 import com.android.internal.widget.LockPatternUtils;
48 import com.android.internal.widget.LockscreenCredential;
49 import com.android.internal.widget.VerifyCredentialResponse;
50 import com.android.server.locksettings.LockSettingsStorage.PersistentData;
51 
52 import libcore.util.HexEncoding;
53 
54 import java.lang.annotation.Retention;
55 import java.lang.annotation.RetentionPolicy;
56 import java.nio.ByteBuffer;
57 import java.security.NoSuchAlgorithmException;
58 import java.security.SecureRandom;
59 import java.util.ArrayList;
60 import java.util.Arrays;
61 import java.util.Collections;
62 import java.util.HashSet;
63 import java.util.List;
64 import java.util.Map;
65 import java.util.NoSuchElementException;
66 import java.util.Objects;
67 import java.util.Set;
68 
69 
70 /**
71  * A class that maintains the wrapping of synthetic password by user credentials or escrow tokens.
72  * It's (mostly) a pure storage for synthetic passwords, providing APIs to creating and destroying
73  * synthetic password blobs which are wrapped by user credentials or escrow tokens.
74  *
75  * Here is the assumptions it makes:
76  *   Each user has one single synthetic password at any time.
77  *   The SP has an associated password handle, which binds to the SID for that user. The password
78  *   handle is persisted by SyntheticPasswordManager internally.
79  *   If the user credential is null, it's treated as if the credential is DEFAULT_PASSWORD
80  *
81  * Information persisted on disk:
82  *   for each user (stored under DEFAULT_HANDLE):
83  *     SP_HANDLE_NAME: GateKeeper password handle of synthetic password. Only available if user
84  *                     credential exists, cleared when user clears their credential.
85  *     SP_E0_NAME, SP_P1_NAME: Secret to derive synthetic password when combined with escrow
86  *                     tokens. Destroyed when escrow support is turned off for the given user.
87  *
88  *     for each SP blob under the user (stored under the corresponding handle):
89  *       SP_BLOB_NAME: The encrypted synthetic password. Always exists.
90  *       PASSWORD_DATA_NAME: Metadata about user credential. Only exists for password based SP.
91  *       SECDISCARDABLE_NAME: Part of the necessary ingredient to decrypt SP_BLOB_NAME for the
92  *                            purpose of secure deletion. Exists if this is a non-weaver SP
93  *                            (both password and token based), or it's a token-based SP under weaver.
94  *       WEAVER_SLOT: Metadata about the weaver slot used. Only exists if this is a SP under weaver.
95  *
96  *
97  */
98 public class SyntheticPasswordManager {
99     private static final String SP_BLOB_NAME = "spblob";
100     private static final String SP_E0_NAME = "e0";
101     private static final String SP_P1_NAME = "p1";
102     private static final String SP_HANDLE_NAME = "handle";
103     private static final String SECDISCARDABLE_NAME = "secdis";
104     private static final int SECDISCARDABLE_LENGTH = 16 * 1024;
105     private static final String PASSWORD_DATA_NAME = "pwd";
106     private static final String WEAVER_SLOT_NAME = "weaver";
107     private static final String PASSWORD_METRICS_NAME = "metrics";
108 
109     public static final long DEFAULT_HANDLE = 0L;
110     private static final byte[] DEFAULT_PASSWORD = "default-password".getBytes();
111 
112     private static final byte WEAVER_VERSION = 1;
113     private static final int INVALID_WEAVER_SLOT = -1;
114 
115     private static final byte SYNTHETIC_PASSWORD_VERSION_V1 = 1;
116     private static final byte SYNTHETIC_PASSWORD_VERSION_V2 = 2;
117     private static final byte SYNTHETIC_PASSWORD_VERSION_V3 = 3;
118     private static final byte SYNTHETIC_PASSWORD_PASSWORD_BASED = 0;
119     private static final byte SYNTHETIC_PASSWORD_STRONG_TOKEN_BASED = 1;
120     private static final byte SYNTHETIC_PASSWORD_WEAK_TOKEN_BASED = 2;
121 
122     // 256-bit synthetic password
123     private static final byte SYNTHETIC_PASSWORD_LENGTH = 256 / 8;
124 
125     private static final int PASSWORD_SCRYPT_N = 11;
126     private static final int PASSWORD_SCRYPT_R = 3;
127     private static final int PASSWORD_SCRYPT_P = 1;
128     private static final int PASSWORD_SALT_LENGTH = 16;
129     private static final int PASSWORD_TOKEN_LENGTH = 32;
130     private static final String TAG = "SyntheticPasswordManager";
131 
132     private static final byte[] PERSONALISATION_SECDISCARDABLE = "secdiscardable-transform".getBytes();
133     private static final byte[] PERSONALIZATION_KEY_STORE_PASSWORD = "keystore-password".getBytes();
134     private static final byte[] PERSONALIZATION_USER_GK_AUTH = "user-gk-authentication".getBytes();
135     private static final byte[] PERSONALIZATION_SP_GK_AUTH = "sp-gk-authentication".getBytes();
136     private static final byte[] PERSONALIZATION_FBE_KEY = "fbe-key".getBytes();
137     private static final byte[] PERSONALIZATION_AUTHSECRET_KEY = "authsecret-hal".getBytes();
138     private static final byte[] PERSONALIZATION_SP_SPLIT = "sp-split".getBytes();
139     private static final byte[] PERSONALIZATION_PASSWORD_HASH = "pw-hash".getBytes();
140     private static final byte[] PERSONALIZATION_E0 = "e0-encryption".getBytes();
141     private static final byte[] PERSONALISATION_WEAVER_PASSWORD = "weaver-pwd".getBytes();
142     private static final byte[] PERSONALISATION_WEAVER_KEY = "weaver-key".getBytes();
143     private static final byte[] PERSONALISATION_WEAVER_TOKEN = "weaver-token".getBytes();
144     private static final byte[] PERSONALIZATION_PASSWORD_METRICS = "password-metrics".getBytes();
145     private static final byte[] PERSONALISATION_CONTEXT =
146         "android-synthetic-password-personalization-context".getBytes();
147 
148     static class AuthenticationResult {
149         // Non-null if password/token passes verification, null otherwise
150         @Nullable public AuthenticationToken authToken;
151         // OK:    password / token passes verification, user has a lockscreen
152         // null:  user does not have a lockscreen (but password / token passes verification)
153         // ERROR: password / token fails verification
154         // RETRY: password / token verification is throttled at the moment.
155         @Nullable public VerifyCredentialResponse gkResponse;
156     }
157 
158     /**
159      * This class represents the main cryptographic secret for a given user (a.k.a synthietic
160      * password). This secret is derived from the user's lockscreen credential or password escrow
161      * token. All other cryptograhic keys related to the user, including disk encryption key,
162      * keystore encryption key, gatekeeper auth key, vendor auth secret and others are directly
163      * derived from this token.
164      * <p>
165      * The main secret associated with an authentication token is retrievable from
166      * {@link AuthenticationToken#getSyntheticPassword()} and the authentication token can be
167      * reconsturcted from the main secret later with
168      * {@link AuthenticationToken#recreateDirectly(byte[])}. The first time an authentication token
169      * is needed, it should be created with {@link AuthenticationToken#create()} so that the
170      * necessary escrow data ({@link #mEncryptedEscrowSplit0} and {@link #mEscrowSplit1}) is
171      * properly initialized. The caller can either persist the (non-secret) esscrow data if escrow
172      * is required, or discard it to cryptograhically disable escrow. To support escrow, the caller
173      * needs to securely store the secret returned from
174      * {@link AuthenticationToken#getEscrowSecret()}, and at the time of use, load the escrow data
175      * back with {@link AuthenticationToken#setEscrowData(byte[], byte[])} and then re-create the
176      * main secret from the escrow secret via
177      * {@link AuthenticationToken#recreateFromEscrow(byte[])}.
178      */
179     static class AuthenticationToken {
180         private final byte mVersion;
181         /**
182          * Here is the relationship between these fields:
183          * Generate two random block P0 and P1. P1 is recorded in mEscrowSplit1 but P0 is not.
184          * mSyntheticPassword = hash(P0 || P1)
185          * E0 = P0 encrypted under syntheticPassword, recoreded in mEncryptedEscrowSplit0.
186          */
187         private @NonNull byte[] mSyntheticPassword;
188         private @Nullable byte[] mEncryptedEscrowSplit0;
189         private @Nullable byte[] mEscrowSplit1;
190 
AuthenticationToken(byte version)191         AuthenticationToken(byte version) {
192             mVersion = version;
193         }
194 
derivePassword(byte[] personalization)195         private byte[] derivePassword(byte[] personalization) {
196             if (mVersion == SYNTHETIC_PASSWORD_VERSION_V3) {
197                 return (new SP800Derive(mSyntheticPassword))
198                     .withContext(personalization, PERSONALISATION_CONTEXT);
199             } else {
200                 return SyntheticPasswordCrypto.personalisedHash(personalization,
201                         mSyntheticPassword);
202             }
203         }
204 
deriveKeyStorePassword()205         public byte[] deriveKeyStorePassword() {
206             return bytesToHex(derivePassword(PERSONALIZATION_KEY_STORE_PASSWORD));
207         }
208 
deriveGkPassword()209         public byte[] deriveGkPassword() {
210             return derivePassword(PERSONALIZATION_SP_GK_AUTH);
211         }
212 
deriveDiskEncryptionKey()213         public byte[] deriveDiskEncryptionKey() {
214             return derivePassword(PERSONALIZATION_FBE_KEY);
215         }
216 
deriveVendorAuthSecret()217         public byte[] deriveVendorAuthSecret() {
218             return derivePassword(PERSONALIZATION_AUTHSECRET_KEY);
219         }
220 
derivePasswordHashFactor()221         public byte[] derivePasswordHashFactor() {
222             return derivePassword(PERSONALIZATION_PASSWORD_HASH);
223         }
224 
225         /** Derives key used to encrypt password metrics */
deriveMetricsKey()226         public byte[] deriveMetricsKey() {
227             return derivePassword(PERSONALIZATION_PASSWORD_METRICS);
228         }
229 
230         /**
231          * Assign escrow data to this auth token. This is a prerequisite to call
232          * {@link AuthenticationToken#recreateFromEscrow}.
233          */
setEscrowData(@ullable byte[] encryptedEscrowSplit0, @Nullable byte[] escrowSplit1)234         public void setEscrowData(@Nullable byte[] encryptedEscrowSplit0,
235                 @Nullable byte[] escrowSplit1) {
236             mEncryptedEscrowSplit0 = encryptedEscrowSplit0;
237             mEscrowSplit1 = escrowSplit1;
238         }
239 
240         /**
241          * Re-creates authentication token from escrow secret (escrowSplit0, returned from
242          * {@link AuthenticationToken#getEscrowSecret}). Escrow data needs to be loaded
243          * by {@link #setEscrowData} before calling this.
244          */
recreateFromEscrow(byte[] escrowSplit0)245         public void recreateFromEscrow(byte[] escrowSplit0) {
246             Objects.requireNonNull(mEscrowSplit1);
247             Objects.requireNonNull(mEncryptedEscrowSplit0);
248             recreate(escrowSplit0, mEscrowSplit1);
249         }
250 
251         /**
252          * Re-creates authentication token from synthetic password directly.
253          */
recreateDirectly(byte[] syntheticPassword)254         public void recreateDirectly(byte[] syntheticPassword) {
255             this.mSyntheticPassword = Arrays.copyOf(syntheticPassword, syntheticPassword.length);
256         }
257 
258         /**
259          * Generates a new random synthetic password with escrow data.
260          */
create()261         static AuthenticationToken create() {
262             AuthenticationToken result = new AuthenticationToken(SYNTHETIC_PASSWORD_VERSION_V3);
263             byte[] escrowSplit0 = secureRandom(SYNTHETIC_PASSWORD_LENGTH);
264             byte[] escrowSplit1 = secureRandom(SYNTHETIC_PASSWORD_LENGTH);
265             result.recreate(escrowSplit0, escrowSplit1);
266             byte[] encrypteEscrowSplit0 = SyntheticPasswordCrypto.encrypt(result.mSyntheticPassword,
267                     PERSONALIZATION_E0, escrowSplit0);
268             result.setEscrowData(encrypteEscrowSplit0,  escrowSplit1);
269             return result;
270         }
271 
272         /**
273          * Re-creates synthetic password from both escrow splits. See javadoc for
274          * AuthenticationToken.mSyntheticPassword for details on what each block means.
275          */
recreate(byte[] escrowSplit0, byte[] escrowSplit1)276         private void recreate(byte[] escrowSplit0, byte[] escrowSplit1) {
277             mSyntheticPassword = String.valueOf(HexEncoding.encode(
278                     SyntheticPasswordCrypto.personalisedHash(
279                             PERSONALIZATION_SP_SPLIT, escrowSplit0, escrowSplit1))).getBytes();
280         }
281 
282         /**
283          * Returns the escrow secret that can be used later to reconstruct this authentication
284          * token from {@link #recreateFromEscrow(byte[])}. Only possible if escrow is not disabled
285          * (encryptedEscrowSplit0 known).
286          */
getEscrowSecret()287         public byte[] getEscrowSecret() {
288             if (mEncryptedEscrowSplit0 == null) {
289                 return null;
290             }
291             return SyntheticPasswordCrypto.decrypt(mSyntheticPassword, PERSONALIZATION_E0,
292                     mEncryptedEscrowSplit0);
293         }
294 
295         /**
296          * Returns the raw synthetic password that can be used later to reconstruct this
297          * authentication token from {@link #recreateDirectly(byte[])}
298          */
getSyntheticPassword()299         public byte[] getSyntheticPassword() {
300             return mSyntheticPassword;
301         }
302 
303         /**
304          * Returns the version of this AuthenticationToken for use with reconstructing
305          * this with a synthetic password version.
306          */
getVersion()307         public byte getVersion() {
308             return mVersion;
309         }
310     }
311 
312     static class PasswordData {
313         byte scryptN;
314         byte scryptR;
315         byte scryptP;
316         public int credentialType;
317         byte[] salt;
318         // For GateKeeper-based credential, this is the password handle returned by GK,
319         // for weaver-based credential, this is empty.
320         public byte[] passwordHandle;
321 
create(int passwordType)322         public static PasswordData create(int passwordType) {
323             PasswordData result = new PasswordData();
324             result.scryptN = PASSWORD_SCRYPT_N;
325             result.scryptR = PASSWORD_SCRYPT_R;
326             result.scryptP = PASSWORD_SCRYPT_P;
327             result.credentialType = passwordType;
328             result.salt = secureRandom(PASSWORD_SALT_LENGTH);
329             return result;
330         }
331 
fromBytes(byte[] data)332         public static PasswordData fromBytes(byte[] data) {
333             PasswordData result = new PasswordData();
334             ByteBuffer buffer = ByteBuffer.allocate(data.length);
335             buffer.put(data, 0, data.length);
336             buffer.flip();
337             result.credentialType = buffer.getInt();
338             result.scryptN = buffer.get();
339             result.scryptR = buffer.get();
340             result.scryptP = buffer.get();
341             int saltLen = buffer.getInt();
342             result.salt = new byte[saltLen];
343             buffer.get(result.salt);
344             int handleLen = buffer.getInt();
345             if (handleLen > 0) {
346                 result.passwordHandle = new byte[handleLen];
347                 buffer.get(result.passwordHandle);
348             } else {
349                 result.passwordHandle = null;
350             }
351             return result;
352         }
353 
toBytes()354         public byte[] toBytes() {
355 
356             ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES + 3 * Byte.BYTES
357                     + Integer.BYTES + salt.length + Integer.BYTES +
358                     (passwordHandle != null ? passwordHandle.length : 0));
359             buffer.putInt(credentialType);
360             buffer.put(scryptN);
361             buffer.put(scryptR);
362             buffer.put(scryptP);
363             buffer.putInt(salt.length);
364             buffer.put(salt);
365             if (passwordHandle != null && passwordHandle.length > 0) {
366                 buffer.putInt(passwordHandle.length);
367                 buffer.put(passwordHandle);
368             } else {
369                 buffer.putInt(0);
370             }
371             return buffer.array();
372         }
373     }
374 
375     static class SyntheticPasswordBlob {
376         byte mVersion;
377         byte mType;
378         byte[] mContent;
379 
create(byte version, byte type, byte[] content)380         public static SyntheticPasswordBlob create(byte version, byte type, byte[] content) {
381             SyntheticPasswordBlob result = new SyntheticPasswordBlob();
382             result.mVersion = version;
383             result.mType = type;
384             result.mContent = content;
385             return result;
386         }
387 
fromBytes(byte[] data)388         public static SyntheticPasswordBlob fromBytes(byte[] data) {
389             SyntheticPasswordBlob result = new SyntheticPasswordBlob();
390             result.mVersion = data[0];
391             result.mType = data[1];
392             result.mContent = Arrays.copyOfRange(data, 2, data.length);
393             return result;
394         }
395 
toByte()396         public byte[] toByte() {
397             byte[] blob = new byte[mContent.length + 1 + 1];
398             blob[0] = mVersion;
399             blob[1] = mType;
400             System.arraycopy(mContent, 0, blob, 2, mContent.length);
401             return blob;
402         }
403     }
404 
405     @Retention(RetentionPolicy.SOURCE)
406     @IntDef({TOKEN_TYPE_STRONG, TOKEN_TYPE_WEAK})
407     @interface TokenType {}
408     static final int TOKEN_TYPE_STRONG = 0;
409     static final int TOKEN_TYPE_WEAK = 1;
410 
411     static class TokenData {
412         byte[] secdiscardableOnDisk;
413         byte[] weaverSecret;
414         byte[] aggregatedSecret;
415         @TokenType int mType;
416         EscrowTokenStateChangeCallback mCallback;
417     }
418 
419     private final Context mContext;
420     private LockSettingsStorage mStorage;
421     private IWeaver mWeaver;
422     private WeaverConfig mWeaverConfig;
423     private PasswordSlotManager mPasswordSlotManager;
424 
425     private final UserManager mUserManager;
426 
427     private final RemoteCallbackList<IWeakEscrowTokenRemovedListener> mListeners =
428             new RemoteCallbackList<>();
429 
SyntheticPasswordManager(Context context, LockSettingsStorage storage, UserManager userManager, PasswordSlotManager passwordSlotManager)430     public SyntheticPasswordManager(Context context, LockSettingsStorage storage,
431             UserManager userManager, PasswordSlotManager passwordSlotManager) {
432         mContext = context;
433         mStorage = storage;
434         mUserManager = userManager;
435         mPasswordSlotManager = passwordSlotManager;
436     }
437 
438     @VisibleForTesting
getWeaverService()439     protected IWeaver getWeaverService() throws RemoteException {
440         try {
441             return IWeaver.getService(/* retry */ true);
442         } catch (NoSuchElementException e) {
443             Slog.i(TAG, "Device does not support weaver");
444             return null;
445         }
446     }
447 
initWeaverService()448     public synchronized void initWeaverService() {
449         if (mWeaver != null) {
450             return;
451         }
452         try {
453             mWeaverConfig = null;
454             mWeaver = getWeaverService();
455             if (mWeaver != null) {
456                 mWeaver.getConfig((int status, WeaverConfig config) -> {
457                     if (status == WeaverStatus.OK && config.slots > 0) {
458                         mWeaverConfig = config;
459                     } else {
460                         Slog.e(TAG, "Failed to get weaver config, status " + status
461                                 + " slots: " + config.slots);
462                         mWeaver = null;
463                     }
464                 });
465                 mPasswordSlotManager.refreshActiveSlots(getUsedWeaverSlots());
466             }
467         } catch (RemoteException e) {
468             Slog.e(TAG, "Failed to get weaver service", e);
469         }
470     }
471 
isWeaverAvailable()472     private synchronized boolean isWeaverAvailable() {
473         if (mWeaver == null) {
474             //Re-initializing weaver in case there was a transient error preventing access to it.
475             initWeaverService();
476         }
477         return mWeaver != null && mWeaverConfig.slots > 0;
478     }
479 
480     /**
481      * Enroll the given key value pair into the specified weaver slot. if the given key is null,
482      * a default all-zero key is used. If the value is not specified, a fresh random secret is
483      * generated as the value.
484      *
485      * @return the value stored in the weaver slot, or null if the operation fails
486      */
weaverEnroll(int slot, byte[] key, @Nullable byte[] value)487     private byte[] weaverEnroll(int slot, byte[] key, @Nullable byte[] value) {
488         if (slot == INVALID_WEAVER_SLOT || slot >= mWeaverConfig.slots) {
489             throw new IllegalArgumentException("Invalid slot for weaver");
490         }
491         if (key == null) {
492             key = new byte[mWeaverConfig.keySize];
493         } else if (key.length != mWeaverConfig.keySize) {
494             throw new IllegalArgumentException("Invalid key size for weaver");
495         }
496         if (value == null) {
497             value = secureRandom(mWeaverConfig.valueSize);
498         }
499         try {
500             int writeStatus = mWeaver.write(slot, toByteArrayList(key), toByteArrayList(value));
501             if (writeStatus != WeaverStatus.OK) {
502                 Slog.e(TAG, "weaver write failed, slot: " + slot + " status: " + writeStatus);
503                 return null;
504             }
505         } catch (RemoteException e) {
506             Slog.e(TAG, "weaver write failed", e);
507             return null;
508         }
509         return value;
510     }
511 
512     /**
513      * Verify the supplied key against a weaver slot, returning a response indicating whether
514      * the verification is successful, throttled or failed. If successful, the bound secret
515      * is also returned.
516      */
weaverVerify(int slot, byte[] key)517     private VerifyCredentialResponse weaverVerify(int slot, byte[] key) {
518         if (slot == INVALID_WEAVER_SLOT || slot >= mWeaverConfig.slots) {
519             throw new IllegalArgumentException("Invalid slot for weaver");
520         }
521         if (key == null) {
522             key = new byte[mWeaverConfig.keySize];
523         } else if (key.length != mWeaverConfig.keySize) {
524             throw new IllegalArgumentException("Invalid key size for weaver");
525         }
526         final VerifyCredentialResponse[] response = new VerifyCredentialResponse[1];
527         try {
528             mWeaver.read(slot, toByteArrayList(key),
529                     (int status, WeaverReadResponse readResponse) -> {
530                     switch (status) {
531                         case WeaverReadStatus.OK:
532                             response[0] = new VerifyCredentialResponse.Builder().setGatekeeperHAT(
533                                     fromByteArrayList(readResponse.value)).build();
534                             break;
535                         case WeaverReadStatus.THROTTLE:
536                             response[0] = VerifyCredentialResponse
537                                     .fromTimeout(readResponse.timeout);
538                             Slog.e(TAG, "weaver read failed (THROTTLE), slot: " + slot);
539                             break;
540                         case WeaverReadStatus.INCORRECT_KEY:
541                             if (readResponse.timeout == 0) {
542                                 response[0] = VerifyCredentialResponse.ERROR;
543                                 Slog.e(TAG, "weaver read failed (INCORRECT_KEY), slot: " + slot);
544                             } else {
545                                 response[0] = VerifyCredentialResponse
546                                         .fromTimeout(readResponse.timeout);
547                                 Slog.e(TAG, "weaver read failed (INCORRECT_KEY/THROTTLE), slot: "
548                                         + slot);
549                             }
550                             break;
551                         case WeaverReadStatus.FAILED:
552                             response[0] = VerifyCredentialResponse.ERROR;
553                             Slog.e(TAG, "weaver read failed (FAILED), slot: " + slot);
554                             break;
555                         default:
556                             response[0] = VerifyCredentialResponse.ERROR;
557                             Slog.e(TAG, "weaver read unknown status " + status + ", slot: " + slot);
558                             break;
559                     }
560                 });
561         } catch (RemoteException e) {
562             response[0] = VerifyCredentialResponse.ERROR;
563             Slog.e(TAG, "weaver read failed, slot: " + slot, e);
564         }
565         return response[0];
566     }
567 
removeUser(IGateKeeperService gatekeeper, int userId)568     public void removeUser(IGateKeeperService gatekeeper, int userId) {
569         for (long handle : mStorage.listSyntheticPasswordHandlesForUser(SP_BLOB_NAME, userId)) {
570             destroyWeaverSlot(handle, userId);
571             destroySPBlobKey(getKeyName(handle));
572         }
573         // Remove potential persistent state (in RPMB), to prevent them from accumulating and
574         // causing problems.
575         try {
576             gatekeeper.clearSecureUserId(fakeUid(userId));
577         } catch (RemoteException ignore) {
578             Slog.w(TAG, "Failed to clear SID from gatekeeper");
579         }
580     }
581 
getCredentialType(long handle, int userId)582     int getCredentialType(long handle, int userId) {
583         byte[] passwordData = loadState(PASSWORD_DATA_NAME, handle, userId);
584         if (passwordData == null) {
585             Slog.w(TAG, "getCredentialType: encountered empty password data for user " + userId);
586             return LockPatternUtils.CREDENTIAL_TYPE_NONE;
587         }
588         return PasswordData.fromBytes(passwordData).credentialType;
589     }
590 
getFrpCredentialType(byte[] payload)591     static int getFrpCredentialType(byte[] payload) {
592         if (payload == null) {
593             return LockPatternUtils.CREDENTIAL_TYPE_NONE;
594         }
595         return PasswordData.fromBytes(payload).credentialType;
596     }
597 
598     /**
599      * Initializing a new Authentication token, possibly from an existing credential and hash.
600      *
601      * The authentication token would bear a randomly-generated synthetic password.
602      *
603      * This method has the side effect of rebinding the SID of the given user to the
604      * newly-generated SP.
605      *
606      * If the existing credential hash is non-null, the existing SID mill be migrated so
607      * the synthetic password in the authentication token will produce the same SID
608      * (the corresponding synthetic password handle is persisted by SyntheticPasswordManager
609      * in a per-user data storage.)
610      *
611      * If the existing credential hash is null, it means the given user should have no SID so
612      * SyntheticPasswordManager will nuke any SP handle previously persisted. In this case,
613      * the supplied credential parameter is also ignored.
614      *
615      * Also saves the escrow information necessary to re-generate the synthetic password under
616      * an escrow scheme. This information can be removed with {@link #destroyEscrowData} if
617      * password escrow should be disabled completely on the given user.
618      *
619      */
newSyntheticPasswordAndSid(IGateKeeperService gatekeeper, byte[] hash, LockscreenCredential credential, int userId)620     public AuthenticationToken newSyntheticPasswordAndSid(IGateKeeperService gatekeeper,
621             byte[] hash, LockscreenCredential credential, int userId) {
622         AuthenticationToken result = AuthenticationToken.create();
623         GateKeeperResponse response;
624         if (hash != null) {
625             try {
626                 response = gatekeeper.enroll(userId, hash, credential.getCredential(),
627                         result.deriveGkPassword());
628             } catch (RemoteException e) {
629                 throw new IllegalStateException("Failed to enroll credential duing SP init", e);
630             }
631             if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
632                 Slog.w(TAG, "Fail to migrate SID, assuming no SID, user " + userId);
633                 clearSidForUser(userId);
634             } else {
635                 saveSyntheticPasswordHandle(response.getPayload(), userId);
636             }
637         } else {
638             clearSidForUser(userId);
639         }
640         saveEscrowData(result, userId);
641         return result;
642     }
643 
644     /**
645      * Enroll a new password handle and SID for the given synthetic password and persist it on disk.
646      * Used when adding password to previously-unsecured devices.
647      */
newSidForUser(IGateKeeperService gatekeeper, AuthenticationToken authToken, int userId)648     public void newSidForUser(IGateKeeperService gatekeeper, AuthenticationToken authToken,
649             int userId) {
650         GateKeeperResponse response;
651         try {
652             response = gatekeeper.enroll(userId, null, null, authToken.deriveGkPassword());
653         } catch (RemoteException e) {
654             throw new IllegalStateException("Failed to create new SID for user", e);
655         }
656         if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
657             throw new IllegalStateException("Fail to create new SID for user " + userId
658                     + " response: " + response.getResponseCode());
659         }
660         saveSyntheticPasswordHandle(response.getPayload(), userId);
661     }
662 
663     // Nuke the SP handle (and as a result, its SID) for the given user.
clearSidForUser(int userId)664     public void clearSidForUser(int userId) {
665         destroyState(SP_HANDLE_NAME, DEFAULT_HANDLE, userId);
666     }
667 
hasSidForUser(int userId)668     public boolean hasSidForUser(int userId) {
669         return hasState(SP_HANDLE_NAME, DEFAULT_HANDLE, userId);
670     }
671 
672     // if null, it means there is no SID associated with the user
673     // This can happen if the user is migrated to SP but currently
674     // do not have a lockscreen password.
loadSyntheticPasswordHandle(int userId)675     private byte[] loadSyntheticPasswordHandle(int userId) {
676         return loadState(SP_HANDLE_NAME, DEFAULT_HANDLE, userId);
677     }
678 
saveSyntheticPasswordHandle(byte[] spHandle, int userId)679     private void saveSyntheticPasswordHandle(byte[] spHandle, int userId) {
680         saveState(SP_HANDLE_NAME, spHandle, DEFAULT_HANDLE, userId);
681     }
682 
loadEscrowData(AuthenticationToken authToken, int userId)683     private boolean loadEscrowData(AuthenticationToken authToken, int userId) {
684         byte[] e0 = loadState(SP_E0_NAME, DEFAULT_HANDLE, userId);
685         byte[] p1 = loadState(SP_P1_NAME, DEFAULT_HANDLE, userId);
686         authToken.setEscrowData(e0,  p1);
687         return e0 != null && p1 != null;
688     }
689 
saveEscrowData(AuthenticationToken authToken, int userId)690     private void saveEscrowData(AuthenticationToken authToken, int userId) {
691         saveState(SP_E0_NAME, authToken.mEncryptedEscrowSplit0, DEFAULT_HANDLE, userId);
692         saveState(SP_P1_NAME, authToken.mEscrowSplit1, DEFAULT_HANDLE, userId);
693     }
694 
hasEscrowData(int userId)695     public boolean hasEscrowData(int userId) {
696         return hasState(SP_E0_NAME, DEFAULT_HANDLE, userId)
697                 && hasState(SP_P1_NAME, DEFAULT_HANDLE, userId);
698     }
699 
destroyEscrowData(int userId)700     public void destroyEscrowData(int userId) {
701         destroyState(SP_E0_NAME, DEFAULT_HANDLE, userId);
702         destroyState(SP_P1_NAME, DEFAULT_HANDLE, userId);
703     }
704 
loadWeaverSlot(long handle, int userId)705     private int loadWeaverSlot(long handle, int userId) {
706         final int LENGTH = Byte.BYTES + Integer.BYTES;
707         byte[] data = loadState(WEAVER_SLOT_NAME, handle, userId);
708         if (data == null || data.length != LENGTH) {
709             return INVALID_WEAVER_SLOT;
710         }
711         ByteBuffer buffer = ByteBuffer.allocate(LENGTH);
712         buffer.put(data, 0, data.length);
713         buffer.flip();
714         if (buffer.get() != WEAVER_VERSION) {
715             Slog.e(TAG, "Invalid weaver slot version of handle " + handle);
716             return INVALID_WEAVER_SLOT;
717         }
718         return buffer.getInt();
719     }
720 
saveWeaverSlot(int slot, long handle, int userId)721     private void saveWeaverSlot(int slot, long handle, int userId) {
722         ByteBuffer buffer = ByteBuffer.allocate(Byte.BYTES + Integer.BYTES);
723         buffer.put(WEAVER_VERSION);
724         buffer.putInt(slot);
725         saveState(WEAVER_SLOT_NAME, buffer.array(), handle, userId);
726     }
727 
destroyWeaverSlot(long handle, int userId)728     private void destroyWeaverSlot(long handle, int userId) {
729         int slot = loadWeaverSlot(handle, userId);
730         destroyState(WEAVER_SLOT_NAME, handle, userId);
731         if (slot != INVALID_WEAVER_SLOT) {
732             Set<Integer> usedSlots = getUsedWeaverSlots();
733             if (!usedSlots.contains(slot)) {
734                 Slog.i(TAG, "Destroy weaver slot " + slot + " for user " + userId);
735                 weaverEnroll(slot, null, null);
736                 mPasswordSlotManager.markSlotDeleted(slot);
737             } else {
738                 Slog.w(TAG, "Skip destroying reused weaver slot " + slot + " for user " + userId);
739             }
740         }
741     }
742 
743     /**
744      * Return the set of weaver slots that are currently in use by all users on the device.
745      * <p>
746      * <em>Note:</em> Users who are in the process of being deleted are not tracked here
747      * (due to them being marked as partial in UserManager so not visible from
748      * {@link UserManager#getUsers}). As a result their weaver slots will not be considered
749      * taken and can be reused by new users. Care should be taken when cleaning up the
750      * deleted user in {@link #removeUser}, to prevent a reused slot from being erased
751      * unintentionally.
752      */
getUsedWeaverSlots()753     private Set<Integer> getUsedWeaverSlots() {
754         Map<Integer, List<Long>> slotHandles = mStorage.listSyntheticPasswordHandlesForAllUsers(
755                 WEAVER_SLOT_NAME);
756         HashSet<Integer> slots = new HashSet<>();
757         for (Map.Entry<Integer, List<Long>> entry : slotHandles.entrySet()) {
758             for (Long handle : entry.getValue()) {
759                 int slot = loadWeaverSlot(handle, entry.getKey());
760                 slots.add(slot);
761             }
762         }
763         return slots;
764     }
765 
getNextAvailableWeaverSlot()766     private int getNextAvailableWeaverSlot() {
767         Set<Integer> usedSlots = getUsedWeaverSlots();
768         usedSlots.addAll(mPasswordSlotManager.getUsedSlots());
769         for (int i = 0; i < mWeaverConfig.slots; i++) {
770             if (!usedSlots.contains(i)) {
771                 return i;
772             }
773         }
774         throw new IllegalStateException("Run out of weaver slots.");
775     }
776 
777     /**
778      * Create a new password based SP blob based on the supplied authentication token, such that
779      * a future successful authentication with unwrapPasswordBasedSyntheticPassword() would result
780      * in the same authentication token.
781      *
782      * This method only creates SP blob wrapping around the given synthetic password and does not
783      * handle logic around SID or SP handle. The caller should separately ensure that the user's SID
784      * is consistent with the device state by calling other APIs in this class.
785      *
786      * @see #newSidForUser
787      * @see #clearSidForUser
788      * @return a new password handle for the wrapped SP blob
789      * @throw IllegalStateException if creation fails.
790      */
createPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper, LockscreenCredential credential, AuthenticationToken authToken, int userId)791     public long createPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
792             LockscreenCredential credential, AuthenticationToken authToken, int userId) {
793         long handle = generateHandle();
794         PasswordData pwd = PasswordData.create(credential.getType());
795         byte[] pwdToken = computePasswordToken(credential, pwd);
796         final long sid;
797         final byte[] applicationId;
798 
799         if (isWeaverAvailable()) {
800             // Weaver based user password
801             int weaverSlot = getNextAvailableWeaverSlot();
802             Slog.i(TAG, "Weaver enroll password to slot " + weaverSlot + " for user " + userId);
803             byte[] weaverSecret = weaverEnroll(weaverSlot, passwordTokenToWeaverKey(pwdToken),
804                     null);
805             if (weaverSecret == null) {
806                 throw new IllegalStateException(
807                         "Fail to enroll user password under weaver " + userId);
808             }
809             saveWeaverSlot(weaverSlot, handle, userId);
810             mPasswordSlotManager.markSlotInUse(weaverSlot);
811             // No need to pass in quality since the credential type already encodes sufficient info
812             synchronizeWeaverFrpPassword(pwd, 0, userId, weaverSlot);
813 
814             pwd.passwordHandle = null;
815             sid = GateKeeper.INVALID_SECURE_USER_ID;
816             applicationId = transformUnderWeaverSecret(pwdToken, weaverSecret);
817         } else {
818             // In case GK enrollment leaves persistent state around (in RPMB), this will nuke them
819             // to prevent them from accumulating and causing problems.
820             try {
821                 gatekeeper.clearSecureUserId(fakeUid(userId));
822             } catch (RemoteException ignore) {
823                 Slog.w(TAG, "Failed to clear SID from gatekeeper");
824             }
825             // GateKeeper based user password
826             GateKeeperResponse response;
827             try {
828                 response = gatekeeper.enroll(fakeUid(userId), null, null,
829                         passwordTokenToGkInput(pwdToken));
830             } catch (RemoteException e) {
831                 throw new IllegalStateException("Failed to enroll password for new SP blob", e);
832             }
833             if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
834                 throw new IllegalStateException(
835                         "Fail to enroll user password when creating SP for user " + userId);
836             }
837             pwd.passwordHandle = response.getPayload();
838             sid = sidFromPasswordHandle(pwd.passwordHandle);
839             applicationId = transformUnderSecdiscardable(pwdToken,
840                     createSecdiscardable(handle, userId));
841             // No need to pass in quality since the credential type already encodes sufficient info
842             synchronizeFrpPassword(pwd, 0, userId);
843         }
844         saveState(PASSWORD_DATA_NAME, pwd.toBytes(), handle, userId);
845         savePasswordMetrics(credential, authToken, handle, userId);
846         createSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_PASSWORD_BASED, authToken,
847                 applicationId, sid, userId);
848         return handle;
849     }
850 
verifyFrpCredential(IGateKeeperService gatekeeper, LockscreenCredential userCredential, ICheckCredentialProgressCallback progressCallback)851     public VerifyCredentialResponse verifyFrpCredential(IGateKeeperService gatekeeper,
852             LockscreenCredential userCredential,
853             ICheckCredentialProgressCallback progressCallback) {
854         PersistentData persistentData = mStorage.readPersistentDataBlock();
855         if (persistentData.type == PersistentData.TYPE_SP) {
856             PasswordData pwd = PasswordData.fromBytes(persistentData.payload);
857             byte[] pwdToken = computePasswordToken(userCredential, pwd);
858 
859             GateKeeperResponse response;
860             try {
861                 response = gatekeeper.verifyChallenge(fakeUid(persistentData.userId),
862                         0 /* challenge */, pwd.passwordHandle, passwordTokenToGkInput(pwdToken));
863             } catch (RemoteException e) {
864                 Slog.e(TAG, "FRP verifyChallenge failed", e);
865                 return VerifyCredentialResponse.ERROR;
866             }
867             return VerifyCredentialResponse.fromGateKeeperResponse(response);
868         } else if (persistentData.type == PersistentData.TYPE_SP_WEAVER) {
869             if (!isWeaverAvailable()) {
870                 Slog.e(TAG, "No weaver service to verify SP-based FRP credential");
871                 return VerifyCredentialResponse.ERROR;
872             }
873             PasswordData pwd = PasswordData.fromBytes(persistentData.payload);
874             byte[] pwdToken = computePasswordToken(userCredential, pwd);
875             int weaverSlot = persistentData.userId;
876 
877             return weaverVerify(weaverSlot, passwordTokenToWeaverKey(pwdToken)).stripPayload();
878         } else {
879             Slog.e(TAG, "persistentData.type must be TYPE_SP or TYPE_SP_WEAVER, but is "
880                     + persistentData.type);
881             return VerifyCredentialResponse.ERROR;
882         }
883     }
884 
885 
migrateFrpPasswordLocked(long handle, UserInfo userInfo, int requestedQuality)886     public void migrateFrpPasswordLocked(long handle, UserInfo userInfo, int requestedQuality) {
887         if (mStorage.getPersistentDataBlockManager() != null
888                 && LockPatternUtils.userOwnsFrpCredential(mContext, userInfo)) {
889             PasswordData pwd = PasswordData.fromBytes(loadState(PASSWORD_DATA_NAME, handle,
890                     userInfo.id));
891             if (pwd.credentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
892                 int weaverSlot = loadWeaverSlot(handle, userInfo.id);
893                 if (weaverSlot != INVALID_WEAVER_SLOT) {
894                     synchronizeWeaverFrpPassword(pwd, requestedQuality, userInfo.id, weaverSlot);
895                 } else {
896                     synchronizeFrpPassword(pwd, requestedQuality, userInfo.id);
897                 }
898             }
899         }
900     }
901 
synchronizeFrpPassword(PasswordData pwd, int requestedQuality, int userId)902     private void synchronizeFrpPassword(PasswordData pwd,
903             int requestedQuality, int userId) {
904         if (mStorage.getPersistentDataBlockManager() != null
905                 && LockPatternUtils.userOwnsFrpCredential(mContext,
906                 mUserManager.getUserInfo(userId))) {
907             if (pwd.credentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
908                 mStorage.writePersistentDataBlock(PersistentData.TYPE_SP, userId, requestedQuality,
909                         pwd.toBytes());
910             } else {
911                 mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, userId, 0, null);
912             }
913         }
914     }
915 
synchronizeWeaverFrpPassword(PasswordData pwd, int requestedQuality, int userId, int weaverSlot)916     private void synchronizeWeaverFrpPassword(PasswordData pwd, int requestedQuality, int userId,
917             int weaverSlot) {
918         if (mStorage.getPersistentDataBlockManager() != null
919                 && LockPatternUtils.userOwnsFrpCredential(mContext,
920                 mUserManager.getUserInfo(userId))) {
921             if (pwd.credentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
922                 mStorage.writePersistentDataBlock(PersistentData.TYPE_SP_WEAVER, weaverSlot,
923                         requestedQuality, pwd.toBytes());
924             } else {
925                 mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, 0, 0, null);
926             }
927         }
928     }
929 
930     private ArrayMap<Integer, ArrayMap<Long, TokenData>> tokenMap = new ArrayMap<>();
931 
932     /**
933      * Create a token based Synthetic password for the given user.
934      * @return the handle of the token
935      */
createStrongTokenBasedSyntheticPassword(byte[] token, int userId, @Nullable EscrowTokenStateChangeCallback changeCallback)936     public long createStrongTokenBasedSyntheticPassword(byte[] token, int userId,
937             @Nullable EscrowTokenStateChangeCallback changeCallback) {
938         return createTokenBasedSyntheticPassword(token, TOKEN_TYPE_STRONG, userId,
939                 changeCallback);
940     }
941 
942     /**
943      * Create a weak token based Synthetic password for the given user.
944      * @return the handle of the weak token
945      */
createWeakTokenBasedSyntheticPassword(byte[] token, int userId, @Nullable EscrowTokenStateChangeCallback changeCallback)946     public long createWeakTokenBasedSyntheticPassword(byte[] token, int userId,
947             @Nullable EscrowTokenStateChangeCallback changeCallback) {
948         return createTokenBasedSyntheticPassword(token, TOKEN_TYPE_WEAK, userId,
949                 changeCallback);
950     }
951 
952     /**
953      * Create a token based Synthetic password of the given type for the given user.
954      * @return the handle of the token
955      */
createTokenBasedSyntheticPassword(byte[] token, @TokenType int type, int userId, @Nullable EscrowTokenStateChangeCallback changeCallback)956     public long createTokenBasedSyntheticPassword(byte[] token, @TokenType int type, int userId,
957             @Nullable EscrowTokenStateChangeCallback changeCallback) {
958         long handle = generateHandle();
959         if (!tokenMap.containsKey(userId)) {
960             tokenMap.put(userId, new ArrayMap<>());
961         }
962         TokenData tokenData = new TokenData();
963         tokenData.mType = type;
964         final byte[] secdiscardable = secureRandom(SECDISCARDABLE_LENGTH);
965         if (isWeaverAvailable()) {
966             tokenData.weaverSecret = secureRandom(mWeaverConfig.valueSize);
967             tokenData.secdiscardableOnDisk = SyntheticPasswordCrypto.encrypt(tokenData.weaverSecret,
968                             PERSONALISATION_WEAVER_TOKEN, secdiscardable);
969         } else {
970             tokenData.secdiscardableOnDisk = secdiscardable;
971             tokenData.weaverSecret = null;
972         }
973         tokenData.aggregatedSecret = transformUnderSecdiscardable(token, secdiscardable);
974         tokenData.mCallback = changeCallback;
975 
976         tokenMap.get(userId).put(handle, tokenData);
977         return handle;
978     }
979 
getPendingTokensForUser(int userId)980     public Set<Long> getPendingTokensForUser(int userId) {
981         if (!tokenMap.containsKey(userId)) {
982             return Collections.emptySet();
983         }
984         return new ArraySet<>(tokenMap.get(userId).keySet());
985     }
986 
987     /** Remove the given pending token. */
removePendingToken(long handle, int userId)988     public boolean removePendingToken(long handle, int userId) {
989         if (!tokenMap.containsKey(userId)) {
990             return false;
991         }
992         return tokenMap.get(userId).remove(handle) != null;
993     }
994 
activateTokenBasedSyntheticPassword(long handle, AuthenticationToken authToken, int userId)995     public boolean activateTokenBasedSyntheticPassword(long handle, AuthenticationToken authToken,
996             int userId) {
997         if (!tokenMap.containsKey(userId)) {
998             return false;
999         }
1000         TokenData tokenData = tokenMap.get(userId).get(handle);
1001         if (tokenData == null) {
1002             return false;
1003         }
1004         if (!loadEscrowData(authToken, userId)) {
1005             Slog.w(TAG, "User is not escrowable");
1006             return false;
1007         }
1008         if (isWeaverAvailable()) {
1009             int slot = getNextAvailableWeaverSlot();
1010             Slog.i(TAG, "Weaver enroll token to slot " + slot + " for user " + userId);
1011             if (weaverEnroll(slot, null, tokenData.weaverSecret) == null) {
1012                 Slog.e(TAG, "Failed to enroll weaver secret when activating token");
1013                 return false;
1014             }
1015             saveWeaverSlot(slot, handle, userId);
1016             mPasswordSlotManager.markSlotInUse(slot);
1017         }
1018         saveSecdiscardable(handle, tokenData.secdiscardableOnDisk, userId);
1019         createSyntheticPasswordBlob(handle, getTokenBasedBlobType(tokenData.mType), authToken,
1020                 tokenData.aggregatedSecret, 0L, userId);
1021         tokenMap.get(userId).remove(handle);
1022         if (tokenData.mCallback != null) {
1023             tokenData.mCallback.onEscrowTokenActivated(handle, userId);
1024         }
1025         return true;
1026     }
1027 
createSyntheticPasswordBlob(long handle, byte type, AuthenticationToken authToken, byte[] applicationId, long sid, int userId)1028     private void createSyntheticPasswordBlob(long handle, byte type, AuthenticationToken authToken,
1029             byte[] applicationId, long sid, int userId) {
1030         final byte[] secret;
1031         if (type == SYNTHETIC_PASSWORD_STRONG_TOKEN_BASED
1032                 || type == SYNTHETIC_PASSWORD_WEAK_TOKEN_BASED) {
1033             secret = authToken.getEscrowSecret();
1034         } else {
1035             secret = authToken.getSyntheticPassword();
1036         }
1037         byte[] content = createSPBlob(getKeyName(handle), secret, applicationId, sid);
1038         /*
1039          * We can upgrade from v1 to v2 because that's just a change in the way that
1040          * the SP is stored. However, we can't upgrade to v3 because that is a change
1041          * in the way that passwords are derived from the SP.
1042          */
1043         byte version = authToken.mVersion == SYNTHETIC_PASSWORD_VERSION_V3
1044                 ? SYNTHETIC_PASSWORD_VERSION_V3 : SYNTHETIC_PASSWORD_VERSION_V2;
1045 
1046         SyntheticPasswordBlob blob = SyntheticPasswordBlob.create(version, type, content);
1047         saveState(SP_BLOB_NAME, blob.toByte(), handle, userId);
1048     }
1049 
1050     /**
1051      * Decrypt a synthetic password by supplying the user credential and corresponding password
1052      * blob handle generated previously. If the decryption is successful, initiate a GateKeeper
1053      * verification to referesh the SID & Auth token maintained by the system.
1054      */
unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper, long handle, @NonNull LockscreenCredential credential, int userId, ICheckCredentialProgressCallback progressCallback)1055     public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
1056             long handle, @NonNull LockscreenCredential credential, int userId,
1057             ICheckCredentialProgressCallback progressCallback) {
1058         AuthenticationResult result = new AuthenticationResult();
1059         PasswordData pwd = PasswordData.fromBytes(loadState(PASSWORD_DATA_NAME, handle, userId));
1060 
1061         if (!credential.checkAgainstStoredType(pwd.credentialType)) {
1062             Slog.e(TAG, String.format("Credential type mismatch: expected %d actual %d",
1063                     pwd.credentialType, credential.getType()));
1064             result.gkResponse = VerifyCredentialResponse.ERROR;
1065             return result;
1066         }
1067 
1068         byte[] pwdToken = computePasswordToken(credential, pwd);
1069 
1070         final byte[] applicationId;
1071         final long sid;
1072         int weaverSlot = loadWeaverSlot(handle, userId);
1073         if (weaverSlot != INVALID_WEAVER_SLOT) {
1074             // Weaver based user password
1075             if (!isWeaverAvailable()) {
1076                 Slog.e(TAG, "No weaver service to unwrap password based SP");
1077                 result.gkResponse = VerifyCredentialResponse.ERROR;
1078                 return result;
1079             }
1080             result.gkResponse = weaverVerify(weaverSlot, passwordTokenToWeaverKey(pwdToken));
1081             if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1082                 return result;
1083             }
1084             sid = GateKeeper.INVALID_SECURE_USER_ID;
1085             applicationId = transformUnderWeaverSecret(pwdToken,
1086                     result.gkResponse.getGatekeeperHAT());
1087         } else {
1088             byte[] gkPwdToken = passwordTokenToGkInput(pwdToken);
1089             GateKeeperResponse response;
1090             try {
1091                 response = gatekeeper.verifyChallenge(fakeUid(userId), 0L,
1092                         pwd.passwordHandle, gkPwdToken);
1093             } catch (RemoteException e) {
1094                 Slog.e(TAG, "gatekeeper verify failed", e);
1095                 result.gkResponse = VerifyCredentialResponse.ERROR;
1096                 return result;
1097             }
1098             int responseCode = response.getResponseCode();
1099             if (responseCode == GateKeeperResponse.RESPONSE_OK) {
1100                 result.gkResponse = VerifyCredentialResponse.OK;
1101                 if (response.getShouldReEnroll()) {
1102                     GateKeeperResponse reenrollResponse;
1103                     try {
1104                         reenrollResponse = gatekeeper.enroll(fakeUid(userId),
1105                                 pwd.passwordHandle, gkPwdToken, gkPwdToken);
1106                     } catch (RemoteException e) {
1107                         Slog.w(TAG, "Fail to invoke gatekeeper.enroll", e);
1108                         reenrollResponse = GateKeeperResponse.ERROR;
1109                         // continue the flow anyway
1110                     }
1111                     if (reenrollResponse.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
1112                         pwd.passwordHandle = reenrollResponse.getPayload();
1113                         // Use the reenrollment opportunity to update credential type
1114                         // (getting rid of CREDENTIAL_TYPE_PASSWORD_OR_PIN)
1115                         pwd.credentialType = credential.getType();
1116                         saveState(PASSWORD_DATA_NAME, pwd.toBytes(), handle, userId);
1117                         synchronizeFrpPassword(pwd, 0, userId);
1118                     } else {
1119                         Slog.w(TAG, "Fail to re-enroll user password for user " + userId);
1120                         // continue the flow anyway
1121                     }
1122                 }
1123             } else if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
1124                 result.gkResponse = VerifyCredentialResponse.fromTimeout(response.getTimeout());
1125                 return result;
1126             } else  {
1127                 result.gkResponse = VerifyCredentialResponse.ERROR;
1128                 return result;
1129             }
1130             sid = sidFromPasswordHandle(pwd.passwordHandle);
1131             applicationId = transformUnderSecdiscardable(pwdToken,
1132                     loadSecdiscardable(handle, userId));
1133         }
1134         // Supplied credential passes first stage weaver/gatekeeper check so it should be correct.
1135         // Notify the callback so the keyguard UI can proceed immediately.
1136         if (progressCallback != null) {
1137             try {
1138                 progressCallback.onCredentialVerified();
1139             } catch (RemoteException e) {
1140                 Slog.w(TAG, "progressCallback throws exception", e);
1141             }
1142         }
1143         result.authToken = unwrapSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_PASSWORD_BASED,
1144                 applicationId, sid, userId);
1145 
1146         // Perform verifyChallenge to refresh auth tokens for GK if user password exists.
1147         result.gkResponse = verifyChallenge(gatekeeper, result.authToken, 0L, userId);
1148 
1149         // Upgrade case: store the metrics if the device did not have stored metrics before, should
1150         // only happen once on old synthetic password blobs.
1151         if (result.authToken != null && !hasPasswordMetrics(handle, userId)) {
1152             savePasswordMetrics(credential, result.authToken, handle, userId);
1153         }
1154         return result;
1155     }
1156 
1157     /**
1158      * Decrypt a synthetic password by supplying an escrow token and corresponding token
1159      * blob handle generated previously. If the decryption is successful, initiate a GateKeeper
1160      * verification to referesh the SID & Auth token maintained by the system.
1161      */
unwrapTokenBasedSyntheticPassword( IGateKeeperService gatekeeper, long handle, byte[] token, int userId)1162     public @NonNull AuthenticationResult unwrapTokenBasedSyntheticPassword(
1163             IGateKeeperService gatekeeper, long handle, byte[] token, int userId) {
1164         SyntheticPasswordBlob blob = SyntheticPasswordBlob
1165                 .fromBytes(loadState(SP_BLOB_NAME, handle, userId));
1166         return unwrapTokenBasedSyntheticPasswordInternal(gatekeeper, handle,
1167                 blob.mType, token, userId);
1168     }
1169 
1170     /**
1171      * Decrypt a synthetic password by supplying an strong escrow token and corresponding token
1172      * blob handle generated previously. If the decryption is successful, initiate a GateKeeper
1173      * verification to referesh the SID & Auth token maintained by the system.
1174      */
unwrapStrongTokenBasedSyntheticPassword( IGateKeeperService gatekeeper, long handle, byte[] token, int userId)1175     public @NonNull AuthenticationResult unwrapStrongTokenBasedSyntheticPassword(
1176             IGateKeeperService gatekeeper, long handle, byte[] token, int userId) {
1177         return unwrapTokenBasedSyntheticPasswordInternal(gatekeeper, handle,
1178                 SYNTHETIC_PASSWORD_STRONG_TOKEN_BASED, token, userId);
1179     }
1180 
1181     /**
1182      * Decrypt a synthetic password by supplying a weak escrow token and corresponding token
1183      * blob handle generated previously. If the decryption is successful, initiate a GateKeeper
1184      * verification to referesh the SID & Auth token maintained by the system.
1185      */
unwrapWeakTokenBasedSyntheticPassword( IGateKeeperService gatekeeper, long handle, byte[] token, int userId)1186     public @NonNull AuthenticationResult unwrapWeakTokenBasedSyntheticPassword(
1187             IGateKeeperService gatekeeper, long handle, byte[] token, int userId) {
1188         return unwrapTokenBasedSyntheticPasswordInternal(gatekeeper, handle,
1189                 SYNTHETIC_PASSWORD_WEAK_TOKEN_BASED, token, userId);
1190     }
1191 
unwrapTokenBasedSyntheticPasswordInternal( IGateKeeperService gatekeeper, long handle, byte type, byte[] token, int userId)1192     private  @NonNull AuthenticationResult unwrapTokenBasedSyntheticPasswordInternal(
1193             IGateKeeperService gatekeeper, long handle, byte type, byte[] token, int userId) {
1194         AuthenticationResult result = new AuthenticationResult();
1195         byte[] secdiscardable = loadSecdiscardable(handle, userId);
1196         int slotId = loadWeaverSlot(handle, userId);
1197         if (slotId != INVALID_WEAVER_SLOT) {
1198             if (!isWeaverAvailable()) {
1199                 Slog.e(TAG, "No weaver service to unwrap token based SP");
1200                 result.gkResponse = VerifyCredentialResponse.ERROR;
1201                 return result;
1202             }
1203             VerifyCredentialResponse response = weaverVerify(slotId, null);
1204             if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK ||
1205                     response.getGatekeeperHAT() == null) {
1206                 Slog.e(TAG, "Failed to retrieve weaver secret when unwrapping token");
1207                 result.gkResponse = VerifyCredentialResponse.ERROR;
1208                 return result;
1209             }
1210             secdiscardable = SyntheticPasswordCrypto.decrypt(response.getGatekeeperHAT(),
1211                     PERSONALISATION_WEAVER_TOKEN, secdiscardable);
1212         }
1213         byte[] applicationId = transformUnderSecdiscardable(token, secdiscardable);
1214         result.authToken = unwrapSyntheticPasswordBlob(handle, type, applicationId, 0L, userId);
1215         if (result.authToken != null) {
1216             result.gkResponse = verifyChallenge(gatekeeper, result.authToken, 0L, userId);
1217             if (result.gkResponse == null) {
1218                 // The user currently has no password. return OK with null payload so null
1219                 // is propagated to unlockUser()
1220                 result.gkResponse = VerifyCredentialResponse.OK;
1221             }
1222         } else {
1223             result.gkResponse = VerifyCredentialResponse.ERROR;
1224         }
1225         return result;
1226     }
1227 
unwrapSyntheticPasswordBlob(long handle, byte type, byte[] applicationId, long sid, int userId)1228     private AuthenticationToken unwrapSyntheticPasswordBlob(long handle, byte type,
1229             byte[] applicationId, long sid, int userId) {
1230         byte[] data = loadState(SP_BLOB_NAME, handle, userId);
1231         if (data == null) {
1232             return null;
1233         }
1234         SyntheticPasswordBlob blob = SyntheticPasswordBlob.fromBytes(data);
1235         if (blob.mVersion != SYNTHETIC_PASSWORD_VERSION_V3
1236                 && blob.mVersion != SYNTHETIC_PASSWORD_VERSION_V2
1237                 && blob.mVersion != SYNTHETIC_PASSWORD_VERSION_V1) {
1238             throw new IllegalArgumentException("Unknown blob version");
1239         }
1240         if (blob.mType != type) {
1241             throw new IllegalArgumentException("Invalid blob type");
1242         }
1243         final byte[] secret;
1244         if (blob.mVersion == SYNTHETIC_PASSWORD_VERSION_V1) {
1245             secret = SyntheticPasswordCrypto.decryptBlobV1(getKeyName(handle), blob.mContent,
1246                     applicationId);
1247         } else {
1248             secret = decryptSPBlob(getKeyName(handle), blob.mContent, applicationId);
1249         }
1250         if (secret == null) {
1251             Slog.e(TAG, "Fail to decrypt SP for user " + userId);
1252             return null;
1253         }
1254         AuthenticationToken result = new AuthenticationToken(blob.mVersion);
1255         if (type == SYNTHETIC_PASSWORD_STRONG_TOKEN_BASED
1256                 || type == SYNTHETIC_PASSWORD_WEAK_TOKEN_BASED) {
1257             if (!loadEscrowData(result, userId)) {
1258                 Slog.e(TAG, "User is not escrowable: " + userId);
1259                 return null;
1260             }
1261             result.recreateFromEscrow(secret);
1262         } else {
1263             result.recreateDirectly(secret);
1264         }
1265         if (blob.mVersion == SYNTHETIC_PASSWORD_VERSION_V1) {
1266             Slog.i(TAG, "Upgrade v1 SP blob for user " + userId + ", type = " + type);
1267             createSyntheticPasswordBlob(handle, type, result, applicationId, sid, userId);
1268         }
1269         return result;
1270     }
1271 
1272     /**
1273      * performs GK verifyChallenge and returns auth token, re-enrolling SP password handle
1274      * if required.
1275      *
1276      * Normally performing verifyChallenge with an AuthenticationToken should always return
1277      * RESPONSE_OK, since user authentication failures are detected earlier when trying to
1278      * decrypt SP.
1279      */
verifyChallenge(IGateKeeperService gatekeeper, @NonNull AuthenticationToken auth, long challenge, int userId)1280     public @Nullable VerifyCredentialResponse verifyChallenge(IGateKeeperService gatekeeper,
1281             @NonNull AuthenticationToken auth, long challenge, int userId) {
1282         return verifyChallengeInternal(gatekeeper, auth.deriveGkPassword(), challenge, userId);
1283     }
1284 
verifyChallengeInternal( IGateKeeperService gatekeeper, @NonNull byte[] gatekeeperPassword, long challenge, int userId)1285     protected @Nullable VerifyCredentialResponse verifyChallengeInternal(
1286             IGateKeeperService gatekeeper, @NonNull byte[] gatekeeperPassword, long challenge,
1287             int userId) {
1288         byte[] spHandle = loadSyntheticPasswordHandle(userId);
1289         if (spHandle == null) {
1290             // There is no password handle associated with the given user, i.e. the user is not
1291             // secured by lockscreen and has no SID, so just return here;
1292             return null;
1293         }
1294         GateKeeperResponse response;
1295         try {
1296             response = gatekeeper.verifyChallenge(userId, challenge,
1297                     spHandle, gatekeeperPassword);
1298         } catch (RemoteException e) {
1299             Slog.e(TAG, "Fail to verify with gatekeeper " + userId, e);
1300             return VerifyCredentialResponse.ERROR;
1301         }
1302         int responseCode = response.getResponseCode();
1303         if (responseCode == GateKeeperResponse.RESPONSE_OK) {
1304             VerifyCredentialResponse result = new VerifyCredentialResponse.Builder()
1305                     .setGatekeeperHAT(response.getPayload()).build();
1306             if (response.getShouldReEnroll()) {
1307                 try {
1308                     response = gatekeeper.enroll(userId, spHandle, spHandle,
1309                             gatekeeperPassword);
1310                 } catch (RemoteException e) {
1311                     Slog.e(TAG, "Failed to invoke gatekeeper.enroll", e);
1312                     response = GateKeeperResponse.ERROR;
1313                 }
1314                 if (response.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
1315                     spHandle = response.getPayload();
1316                     saveSyntheticPasswordHandle(spHandle, userId);
1317                     // Call self again to re-verify with updated handle
1318                     return verifyChallengeInternal(gatekeeper, gatekeeperPassword, challenge,
1319                             userId);
1320                 } else {
1321                     // Fall through, return result from the previous verification attempt.
1322                     Slog.w(TAG, "Fail to re-enroll SP handle for user " + userId);
1323                 }
1324             }
1325             return result;
1326         } else if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
1327             return VerifyCredentialResponse.fromTimeout(response.getTimeout());
1328         } else {
1329             return VerifyCredentialResponse.ERROR;
1330         }
1331     }
1332 
existsHandle(long handle, int userId)1333     public boolean existsHandle(long handle, int userId) {
1334         return hasState(SP_BLOB_NAME, handle, userId);
1335     }
1336 
1337     /** Destroy the escrow token with the given handle for the given user. */
destroyTokenBasedSyntheticPassword(long handle, int userId)1338     public void destroyTokenBasedSyntheticPassword(long handle, int userId) {
1339         SyntheticPasswordBlob blob = SyntheticPasswordBlob.fromBytes(loadState(SP_BLOB_NAME, handle,
1340                 userId));
1341         destroySyntheticPassword(handle, userId);
1342         destroyState(SECDISCARDABLE_NAME, handle, userId);
1343         if (blob.mType == SYNTHETIC_PASSWORD_WEAK_TOKEN_BASED) {
1344             notifyWeakEscrowTokenRemovedListeners(handle, userId);
1345         }
1346     }
1347 
1348     /** Destroy all weak escrow tokens for the given user. */
destroyAllWeakTokenBasedSyntheticPasswords(int userId)1349     public void destroyAllWeakTokenBasedSyntheticPasswords(int userId) {
1350         List<Long> handles = mStorage.listSyntheticPasswordHandlesForUser(SECDISCARDABLE_NAME,
1351                 userId);
1352         for (long handle: handles) {
1353             SyntheticPasswordBlob blob = SyntheticPasswordBlob.fromBytes(loadState(SP_BLOB_NAME,
1354                     handle, userId));
1355             if (blob.mType == SYNTHETIC_PASSWORD_WEAK_TOKEN_BASED) {
1356                 destroyTokenBasedSyntheticPassword(handle, userId);
1357             }
1358         }
1359     }
1360 
destroyPasswordBasedSyntheticPassword(long handle, int userId)1361     public void destroyPasswordBasedSyntheticPassword(long handle, int userId) {
1362         destroySyntheticPassword(handle, userId);
1363         destroyState(SECDISCARDABLE_NAME, handle, userId);
1364         destroyState(PASSWORD_DATA_NAME, handle, userId);
1365         destroyState(PASSWORD_METRICS_NAME, handle, userId);
1366     }
1367 
destroySyntheticPassword(long handle, int userId)1368     private void destroySyntheticPassword(long handle, int userId) {
1369         destroyState(SP_BLOB_NAME, handle, userId);
1370         destroySPBlobKey(getKeyName(handle));
1371         if (hasState(WEAVER_SLOT_NAME, handle, userId)) {
1372             destroyWeaverSlot(handle, userId);
1373         }
1374     }
1375 
transformUnderWeaverSecret(byte[] data, byte[] secret)1376     private byte[] transformUnderWeaverSecret(byte[] data, byte[] secret) {
1377         byte[] weaverSecret = SyntheticPasswordCrypto.personalisedHash(
1378                 PERSONALISATION_WEAVER_PASSWORD, secret);
1379         byte[] result = new byte[data.length + weaverSecret.length];
1380         System.arraycopy(data, 0, result, 0, data.length);
1381         System.arraycopy(weaverSecret, 0, result, data.length, weaverSecret.length);
1382         return result;
1383     }
1384 
transformUnderSecdiscardable(byte[] data, byte[] rawSecdiscardable)1385     private byte[] transformUnderSecdiscardable(byte[] data, byte[] rawSecdiscardable) {
1386         byte[] secdiscardable = SyntheticPasswordCrypto.personalisedHash(
1387                 PERSONALISATION_SECDISCARDABLE, rawSecdiscardable);
1388         byte[] result = new byte[data.length + secdiscardable.length];
1389         System.arraycopy(data, 0, result, 0, data.length);
1390         System.arraycopy(secdiscardable, 0, result, data.length, secdiscardable.length);
1391         return result;
1392     }
1393 
createSecdiscardable(long handle, int userId)1394     private byte[] createSecdiscardable(long handle, int userId) {
1395         byte[] data = secureRandom(SECDISCARDABLE_LENGTH);
1396         saveSecdiscardable(handle, data, userId);
1397         return data;
1398     }
1399 
saveSecdiscardable(long handle, byte[] secdiscardable, int userId)1400     private void saveSecdiscardable(long handle, byte[] secdiscardable, int userId) {
1401         saveState(SECDISCARDABLE_NAME, secdiscardable, handle, userId);
1402     }
1403 
loadSecdiscardable(long handle, int userId)1404     private byte[] loadSecdiscardable(long handle, int userId) {
1405         return loadState(SECDISCARDABLE_NAME, handle, userId);
1406     }
1407 
getTokenBasedBlobType(@okenType int type)1408     private byte getTokenBasedBlobType(@TokenType int type) {
1409         switch (type) {
1410             case TOKEN_TYPE_WEAK:
1411                 return SYNTHETIC_PASSWORD_WEAK_TOKEN_BASED;
1412             case TOKEN_TYPE_STRONG:
1413             default:
1414                 return SYNTHETIC_PASSWORD_STRONG_TOKEN_BASED;
1415         }
1416     }
1417 
1418     /**
1419      * Retrieves the saved password metrics associated with a SP handle. Only meaningful to be
1420      * called on the handle of a password-based synthetic password. A valid AuthenticationToken for
1421      * the target user is required in order to be able to decrypt the encrypted password metrics on
1422      * disk.
1423      */
getPasswordMetrics(AuthenticationToken authToken, long handle, int userId)1424     public @Nullable PasswordMetrics getPasswordMetrics(AuthenticationToken authToken, long handle,
1425             int userId) {
1426         final byte[] encrypted = loadState(PASSWORD_METRICS_NAME, handle, userId);
1427         if (encrypted == null) return null;
1428         final byte[] decrypted = SyntheticPasswordCrypto.decrypt(authToken.deriveMetricsKey(),
1429                 /* personalization= */ new byte[0], encrypted);
1430         if (decrypted == null) return null;
1431         return VersionedPasswordMetrics.deserialize(decrypted).getMetrics();
1432     }
1433 
savePasswordMetrics(LockscreenCredential credential, AuthenticationToken authToken, long handle, int userId)1434     private void savePasswordMetrics(LockscreenCredential credential, AuthenticationToken authToken,
1435             long handle, int userId) {
1436         final byte[] encrypted = SyntheticPasswordCrypto.encrypt(authToken.deriveMetricsKey(),
1437                 /* personalization= */ new byte[0],
1438                 new VersionedPasswordMetrics(credential).serialize());
1439         saveState(PASSWORD_METRICS_NAME, encrypted, handle, userId);
1440     }
1441 
hasPasswordMetrics(long handle, int userId)1442     private boolean hasPasswordMetrics(long handle, int userId) {
1443         return hasState(PASSWORD_METRICS_NAME, handle, userId);
1444     }
1445 
hasState(String stateName, long handle, int userId)1446     private boolean hasState(String stateName, long handle, int userId) {
1447         return !ArrayUtils.isEmpty(loadState(stateName, handle, userId));
1448     }
1449 
loadState(String stateName, long handle, int userId)1450     private byte[] loadState(String stateName, long handle, int userId) {
1451         return mStorage.readSyntheticPasswordState(userId, handle, stateName);
1452     }
1453 
saveState(String stateName, byte[] data, long handle, int userId)1454     private void saveState(String stateName, byte[] data, long handle, int userId) {
1455         mStorage.writeSyntheticPasswordState(userId, handle, stateName, data);
1456     }
1457 
destroyState(String stateName, long handle, int userId)1458     private void destroyState(String stateName, long handle, int userId) {
1459         mStorage.deleteSyntheticPasswordState(userId, handle, stateName);
1460     }
1461 
decryptSPBlob(String blobKeyName, byte[] blob, byte[] applicationId)1462     protected byte[] decryptSPBlob(String blobKeyName, byte[] blob, byte[] applicationId) {
1463         return SyntheticPasswordCrypto.decryptBlob(blobKeyName, blob, applicationId);
1464     }
1465 
createSPBlob(String blobKeyName, byte[] data, byte[] applicationId, long sid)1466     protected byte[] createSPBlob(String blobKeyName, byte[] data, byte[] applicationId, long sid) {
1467         return SyntheticPasswordCrypto.createBlob(blobKeyName, data, applicationId, sid);
1468     }
1469 
destroySPBlobKey(String keyAlias)1470     protected void destroySPBlobKey(String keyAlias) {
1471         SyntheticPasswordCrypto.destroyBlobKey(keyAlias);
1472     }
1473 
generateHandle()1474     public static long generateHandle() {
1475         SecureRandom rng = new SecureRandom();
1476         long result;
1477         do {
1478             result = rng.nextLong();
1479         } while (result == DEFAULT_HANDLE);
1480         return result;
1481     }
1482 
fakeUid(int uid)1483     private int fakeUid(int uid) {
1484         return 100000 + uid;
1485     }
1486 
secureRandom(int length)1487     protected static byte[] secureRandom(int length) {
1488         try {
1489             return SecureRandom.getInstance("SHA1PRNG").generateSeed(length);
1490         } catch (NoSuchAlgorithmException e) {
1491             e.printStackTrace();
1492             return null;
1493         }
1494     }
1495 
getKeyName(long handle)1496     private String getKeyName(long handle) {
1497         return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, handle);
1498     }
1499 
computePasswordToken(LockscreenCredential credential, PasswordData data)1500     private byte[] computePasswordToken(LockscreenCredential credential, PasswordData data) {
1501         final byte[] password = credential.isNone() ? DEFAULT_PASSWORD : credential.getCredential();
1502         return scrypt(password, data.salt, 1 << data.scryptN, 1 << data.scryptR, 1 << data.scryptP,
1503                 PASSWORD_TOKEN_LENGTH);
1504     }
1505 
passwordTokenToGkInput(byte[] token)1506     private byte[] passwordTokenToGkInput(byte[] token) {
1507         return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_USER_GK_AUTH, token);
1508     }
1509 
passwordTokenToWeaverKey(byte[] token)1510     private byte[] passwordTokenToWeaverKey(byte[] token) {
1511         byte[] key = SyntheticPasswordCrypto.personalisedHash(PERSONALISATION_WEAVER_KEY, token);
1512         if (key.length < mWeaverConfig.keySize) {
1513             throw new IllegalArgumentException("weaver key length too small");
1514         }
1515         return Arrays.copyOf(key, mWeaverConfig.keySize);
1516     }
1517 
sidFromPasswordHandle(byte[] handle)1518     protected long sidFromPasswordHandle(byte[] handle) {
1519         return nativeSidFromPasswordHandle(handle);
1520     }
1521 
scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen)1522     protected byte[] scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen) {
1523         return new Scrypt().scrypt(password, salt, n, r, p, outLen);
1524     }
1525 
nativeSidFromPasswordHandle(byte[] handle)1526     native long nativeSidFromPasswordHandle(byte[] handle);
1527 
toByteArrayList(byte[] data)1528     protected static ArrayList<Byte> toByteArrayList(byte[] data) {
1529         ArrayList<Byte> result = new ArrayList<Byte>(data.length);
1530         for (int i = 0; i < data.length; i++) {
1531             result.add(data[i]);
1532         }
1533         return result;
1534     }
1535 
fromByteArrayList(ArrayList<Byte> data)1536     protected static byte[] fromByteArrayList(ArrayList<Byte> data) {
1537         byte[] result = new byte[data.size()];
1538         for (int i = 0; i < data.size(); i++) {
1539             result[i] = data.get(i);
1540         }
1541         return result;
1542     }
1543 
1544     protected static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes();
bytesToHex(byte[] bytes)1545     private static byte[] bytesToHex(byte[] bytes) {
1546         if (bytes == null) {
1547             return "null".getBytes();
1548         }
1549         byte[] hexBytes = new byte[bytes.length * 2];
1550         for ( int j = 0; j < bytes.length; j++ ) {
1551             int v = bytes[j] & 0xFF;
1552             hexBytes[j * 2] = HEX_ARRAY[v >>> 4];
1553             hexBytes[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
1554         }
1555         return hexBytes;
1556     }
1557 
1558     /**
1559      * Migrate all existing SP keystore keys from uid 1000 app domain to LSS selinux domain
1560      */
migrateKeyNamespace()1561     public boolean migrateKeyNamespace() {
1562         boolean success = true;
1563         final Map<Integer, List<Long>> allHandles =
1564                 mStorage.listSyntheticPasswordHandlesForAllUsers(SP_BLOB_NAME);
1565         for (List<Long> userHandles : allHandles.values()) {
1566             for (long handle : userHandles) {
1567                 success &= SyntheticPasswordCrypto.migrateLockSettingsKey(getKeyName(handle));
1568             }
1569         }
1570         return success;
1571     }
1572 
1573     /** Register the given IWeakEscrowTokenRemovedListener. */
registerWeakEscrowTokenRemovedListener( IWeakEscrowTokenRemovedListener listener)1574     public boolean registerWeakEscrowTokenRemovedListener(
1575             IWeakEscrowTokenRemovedListener listener) {
1576         return mListeners.register(listener);
1577     }
1578 
1579     /** Unregister the given IWeakEscrowTokenRemovedListener. */
unregisterWeakEscrowTokenRemovedListener( IWeakEscrowTokenRemovedListener listener)1580     public boolean unregisterWeakEscrowTokenRemovedListener(
1581             IWeakEscrowTokenRemovedListener listener) {
1582         return mListeners.unregister(listener);
1583     }
1584 
notifyWeakEscrowTokenRemovedListeners(long handle, int userId)1585     private void notifyWeakEscrowTokenRemovedListeners(long handle, int userId) {
1586         int i = mListeners.beginBroadcast();
1587         try {
1588             while (i > 0) {
1589                 i--;
1590                 try {
1591                     mListeners.getBroadcastItem(i).onWeakEscrowTokenRemoved(handle, userId);
1592                 } catch (RemoteException e) {
1593                     Slog.e(TAG, "Exception while notifying WeakEscrowTokenRemovedListener.",
1594                             e);
1595                 }
1596             }
1597         } finally {
1598             mListeners.finishBroadcast();
1599         }
1600     }
1601 }
1602