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