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 android.security.keystore.recovery;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.SystemApi;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 import java.util.Arrays;
28 import java.util.Objects;
29 
30 /**
31  * A {@link KeyChainSnapshot} is protected with a key derived from the user's lock screen. This
32  * class wraps all the data necessary to derive the same key on a recovering device:
33  *
34  * <ul>
35  *     <li>UI parameters for the user's lock screen - so that if e.g., the user was using a pattern,
36  *         the recovering device can display the pattern UI to the user when asking them to enter
37  *         the lock screen from their previous device.
38  *     <li>The algorithm used to derive a key from the user's lock screen, e.g. SHA-256 with a salt.
39  * </ul>
40  *
41  * <p>As such, this data is sent along with the {@link KeyChainSnapshot} when syncing the current
42  * version of the keychain.
43  *
44  * <p>For now, the recoverable keychain only supports a single layer of protection, which is the
45  * user's lock screen. In the future, the keychain will support multiple layers of protection
46  * (e.g. an additional keychain password, along with the lock screen).
47  *
48  * @hide
49  */
50 @SystemApi
51 public final class KeyChainProtectionParams implements Parcelable {
52 
53     // IMPORTANT! PLEASE READ!
54     // -----------------------
55     // If you edit this file (e.g., to add new fields), please MAKE SURE to also do the following:
56     // - Update the #writeToParcel(Parcel) method below
57     // - Update the #(Parcel) constructor below
58     // - Update android.security.keystore.recovery.KeyChainSnapshotTest to make sure nobody
59     //     accidentally breaks your fields in the Parcel in the future.
60     // - Update com.android.server.locksettings.recoverablekeystore.serialization
61     //     .KeyChainSnapshotSerializer to correctly serialize your new field
62     // - Update com.android.server.locksettings.recoverablekeystore.serialization
63     //     .KeyChainSnapshotSerializer to correctly deserialize your new field
64     // - Update com.android.server.locksettings.recoverablekeystore.serialization
65     //     .KeychainSnapshotSerializerTest to make sure nobody breaks serialization of your field
66     //     in the future.
67 
68     /** @hide */
69     @Retention(RetentionPolicy.SOURCE)
70     @IntDef(prefix = {"TYPE_"}, value = {TYPE_LOCKSCREEN})
71     public @interface UserSecretType {
72     }
73 
74     /**
75      * Lockscreen secret is required to recover KeyStore.
76      */
77     public static final int TYPE_LOCKSCREEN = 100;
78 
79     /** @hide */
80     @Retention(RetentionPolicy.SOURCE)
81     @IntDef(prefix = {"UI_FORMAT_"}, value = {UI_FORMAT_PIN, UI_FORMAT_PASSWORD, UI_FORMAT_PATTERN})
82     public @interface LockScreenUiFormat {
83     }
84 
85     /**
86      * Pin with digits only.
87      */
88     public static final int UI_FORMAT_PIN = 1;
89 
90     /**
91      * Password. String with latin-1 characters only.
92      */
93     public static final int UI_FORMAT_PASSWORD = 2;
94 
95     /**
96      * Pattern with 3 by 3 grid.
97      */
98     public static final int UI_FORMAT_PATTERN = 3;
99 
100     @UserSecretType
101     private Integer mUserSecretType;
102 
103     @LockScreenUiFormat
104     private Integer mLockScreenUiFormat;
105 
106     /**
107      * Parameters of the key derivation function, including algorithm, difficulty, salt.
108      */
109     private KeyDerivationParams mKeyDerivationParams;
110     private byte[] mSecret; // Derived from user secret. The field must have limited visibility.
111 
KeyChainProtectionParams()112     private KeyChainProtectionParams() {
113 
114     }
115 
116     /**
117      * @see TYPE_LOCKSCREEN
118      */
getUserSecretType()119     public @UserSecretType int getUserSecretType() {
120         return mUserSecretType;
121     }
122 
123     /**
124      * Specifies UX shown to user during recovery.
125      * Default value is {@code UI_FORMAT_LOCKSCREEN}
126      *
127      * @see UI_FORMAT_PIN
128      * @see UI_FORMAT_PASSWORD
129      * @see UI_FORMAT_PATTERN
130      */
getLockScreenUiFormat()131     public @LockScreenUiFormat int getLockScreenUiFormat() {
132         return mLockScreenUiFormat;
133     }
134 
135     /**
136      * Specifies function used to derive symmetric key from user input
137      * Format is defined in separate util class.
138      */
getKeyDerivationParams()139     public @NonNull KeyDerivationParams getKeyDerivationParams() {
140         return mKeyDerivationParams;
141     }
142 
143     /**
144      * Secret derived from user input.
145      * Default value is empty array
146      *
147      * @return secret or empty array
148      */
getSecret()149     public @NonNull byte[] getSecret() {
150         return mSecret;
151     }
152 
153     /**
154      * Builder for creating {@link KeyChainProtectionParams}.
155      */
156     public static class Builder {
157         private KeyChainProtectionParams mInstance = new KeyChainProtectionParams();
158 
159         /**
160          * Sets user secret type.
161          * Default value is {@link TYPE_LOCKSCREEN}.
162          *
163          * @see TYPE_LOCKSCREEN
164          * @param userSecretType The secret type
165          * @return This builder.
166          */
setUserSecretType(@serSecretType int userSecretType)167         public @NonNull Builder setUserSecretType(@UserSecretType int userSecretType) {
168             mInstance.mUserSecretType = userSecretType;
169             return this;
170         }
171 
172         /**
173          * Sets UI format.
174          *
175          * @see UI_FORMAT_PIN
176          * @see UI_FORMAT_PASSWORD
177          * @see UI_FORMAT_PATTERN
178          * @param lockScreenUiFormat The UI format
179          * @return This builder.
180          */
setLockScreenUiFormat(@ockScreenUiFormat int lockScreenUiFormat)181         public @NonNull Builder setLockScreenUiFormat(@LockScreenUiFormat int lockScreenUiFormat) {
182             mInstance.mLockScreenUiFormat = lockScreenUiFormat;
183             return this;
184         }
185 
186         /**
187          * Sets parameters of the key derivation function.
188          *
189          * @param keyDerivationParams Key derivation parameters
190          * @return This builder.
191          */
setKeyDerivationParams(@onNull KeyDerivationParams keyDerivationParams)192         public @NonNull Builder setKeyDerivationParams(@NonNull KeyDerivationParams
193                 keyDerivationParams) {
194             mInstance.mKeyDerivationParams = keyDerivationParams;
195             return this;
196         }
197 
198         /**
199          * Secret derived from user input, or empty array.
200          *
201          * @param secret The secret.
202          * @return This builder.
203          */
setSecret(@onNull byte[] secret)204         public @NonNull Builder setSecret(@NonNull byte[] secret) {
205             mInstance.mSecret = secret;
206             return this;
207         }
208 
209 
210         /**
211          * Creates a new {@link KeyChainProtectionParams} instance.
212          * The instance will include default values, if {@link #setSecret}
213          * or {@link #setUserSecretType} were not called.
214          *
215          * @return new instance
216          * @throws NullPointerException if some required fields were not set.
217          */
build()218         public @NonNull KeyChainProtectionParams build() {
219             if (mInstance.mUserSecretType == null) {
220                 mInstance.mUserSecretType = TYPE_LOCKSCREEN;
221             }
222             Objects.requireNonNull(mInstance.mLockScreenUiFormat);
223             Objects.requireNonNull(mInstance.mKeyDerivationParams);
224             if (mInstance.mSecret == null) {
225                 mInstance.mSecret = new byte[]{};
226             }
227             return mInstance;
228         }
229     }
230 
231     /**
232      * Fills secret with zeroes.
233      */
clearSecret()234     public void clearSecret() {
235         Arrays.fill(mSecret, (byte) 0);
236     }
237 
238     public static final @NonNull Parcelable.Creator<KeyChainProtectionParams> CREATOR =
239             new Parcelable.Creator<KeyChainProtectionParams>() {
240         public KeyChainProtectionParams createFromParcel(Parcel in) {
241             return new KeyChainProtectionParams(in);
242         }
243 
244         public KeyChainProtectionParams[] newArray(int length) {
245             return new KeyChainProtectionParams[length];
246         }
247     };
248 
249     @Override
writeToParcel(Parcel out, int flags)250     public void writeToParcel(Parcel out, int flags) {
251         out.writeInt(mUserSecretType);
252         out.writeInt(mLockScreenUiFormat);
253         out.writeTypedObject(mKeyDerivationParams, flags);
254         out.writeByteArray(mSecret);
255     }
256 
257     /**
258      * @hide
259      */
KeyChainProtectionParams(Parcel in)260     protected KeyChainProtectionParams(Parcel in) {
261         mUserSecretType = in.readInt();
262         mLockScreenUiFormat = in.readInt();
263         mKeyDerivationParams = in.readTypedObject(KeyDerivationParams.CREATOR);
264         mSecret = in.createByteArray();
265     }
266 
267     @Override
describeContents()268     public int describeContents() {
269         return 0;
270     }
271 }
272