Home | History | Annotate | Download | only in recovery
      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 
    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