KeyChainProtectionParams.java revision 52c15f1699e60c0701cc21a69847a005efe87bc9
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
17package android.security.keystore.recovery;
18
19import android.annotation.IntDef;
20import android.annotation.NonNull;
21import android.annotation.SystemApi;
22import android.os.Parcel;
23import android.os.Parcelable;
24
25import com.android.internal.util.Preconditions;
26
27import java.lang.annotation.Retention;
28import java.lang.annotation.RetentionPolicy;
29import 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
52public 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
113    private KeyChainProtectionParams() {
114
115    }
116
117    /**
118     * @see TYPE_LOCKSCREEN
119     */
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     */
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     */
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     */
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         */
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         */
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         */
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         */
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         */
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     */
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
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     */
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
269    public int describeContents() {
270        return 0;
271    }
272}
273