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