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