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.Objects; 28 29 /** 30 * Collection of parameters which define a key derivation function. 31 * Currently only supports salted SHA-256. 32 * 33 * @hide 34 */ 35 @SystemApi 36 public final class KeyDerivationParams implements Parcelable { 37 38 // IMPORTANT! PLEASE READ! 39 // ----------------------- 40 // If you edit this file (e.g., to add new fields), please MAKE SURE to also do the following: 41 // - Update the #writeToParcel(Parcel) method below 42 // - Update the #(Parcel) constructor below 43 // - Update android.security.keystore.recovery.KeyChainSnapshotTest to make sure nobody 44 // accidentally breaks your fields in the Parcel in the future. 45 // - Update com.android.server.locksettings.recoverablekeystore.serialization 46 // .KeyChainSnapshotSerializer to correctly serialize your new field 47 // - Update com.android.server.locksettings.recoverablekeystore.serialization 48 // .KeyChainSnapshotSerializer to correctly deserialize your new field 49 // - Update com.android.server.locksettings.recoverablekeystore.serialization 50 // .KeychainSnapshotSerializerTest to make sure nobody breaks serialization of your field 51 // in the future. 52 53 private final int mAlgorithm; 54 private final byte[] mSalt; 55 private final int mMemoryDifficulty; 56 57 /** @hide */ 58 @Retention(RetentionPolicy.SOURCE) 59 @IntDef(prefix = {"ALGORITHM_"}, value = {ALGORITHM_SHA256, ALGORITHM_SCRYPT}) 60 public @interface KeyDerivationAlgorithm { 61 } 62 63 /** 64 * Salted SHA256. 65 */ 66 public static final int ALGORITHM_SHA256 = 1; 67 68 /** 69 * SCRYPT. 70 */ 71 public static final int ALGORITHM_SCRYPT = 2; 72 73 /** 74 * Creates instance of the class to to derive keys using salted SHA256 hash. 75 * 76 * <p>The salted SHA256 hash is computed over the concatenation of four byte strings, salt_len + 77 * salt + key_material_len + key_material, where salt_len and key_material_len are 4-byte, and 78 * denote the number of bytes for salt and key_material, respectively. 79 */ createSha256Params(@onNull byte[] salt)80 public static @NonNull KeyDerivationParams createSha256Params(@NonNull byte[] salt) { 81 return new KeyDerivationParams(ALGORITHM_SHA256, salt); 82 } 83 84 /** 85 * Creates instance of the class to to derive keys using the password hashing algorithm SCRYPT. 86 * 87 * <p>We expose only one tuning parameter of SCRYPT, which is the memory cost parameter (i.e. N 88 * in <a href="https://www.tarsnap.com/scrypt/scrypt.pdf">the SCRYPT paper</a>). Regular/default 89 * values are used for the other parameters, to keep the overall running time low. Specifically, 90 * the parallelization parameter p is 1, the block size parameter r is 8, and the hashing output 91 * length is 32-byte. 92 */ createScryptParams( @onNull byte[] salt, int memoryDifficulty)93 public static @NonNull KeyDerivationParams createScryptParams( 94 @NonNull byte[] salt, int memoryDifficulty) { 95 return new KeyDerivationParams(ALGORITHM_SCRYPT, salt, memoryDifficulty); 96 } 97 98 /** 99 * @hide 100 */ KeyDerivationParams(@eyDerivationAlgorithm int algorithm, @NonNull byte[] salt)101 private KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) { 102 this(algorithm, salt, /*memoryDifficulty=*/ -1); 103 } 104 105 /** 106 * @hide 107 */ KeyDerivationParams(@eyDerivationAlgorithm int algorithm, @NonNull byte[] salt, int memoryDifficulty)108 private KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt, 109 int memoryDifficulty) { 110 mAlgorithm = algorithm; 111 mSalt = Objects.requireNonNull(salt); 112 mMemoryDifficulty = memoryDifficulty; 113 } 114 115 /** 116 * Gets algorithm. 117 */ getAlgorithm()118 public @KeyDerivationAlgorithm int getAlgorithm() { 119 return mAlgorithm; 120 } 121 122 /** 123 * Gets salt. 124 */ getSalt()125 public @NonNull byte[] getSalt() { 126 return mSalt; 127 } 128 129 /** 130 * Gets the memory difficulty parameter for the hashing algorithm. 131 * 132 * <p>The effect of this parameter depends on the algorithm in use. For example, please see 133 * {@link #createScryptParams(byte[], int)} for choosing the parameter for SCRYPT. 134 * 135 * <p>If the specific algorithm does not support such a memory difficulty parameter, its value 136 * should be -1. 137 */ getMemoryDifficulty()138 public int getMemoryDifficulty() { 139 return mMemoryDifficulty; 140 } 141 142 public static final @NonNull Parcelable.Creator<KeyDerivationParams> CREATOR = 143 new Parcelable.Creator<KeyDerivationParams>() { 144 public KeyDerivationParams createFromParcel(Parcel in) { 145 return new KeyDerivationParams(in); 146 } 147 148 public KeyDerivationParams[] newArray(int length) { 149 return new KeyDerivationParams[length]; 150 } 151 }; 152 153 @Override writeToParcel(Parcel out, int flags)154 public void writeToParcel(Parcel out, int flags) { 155 out.writeInt(mAlgorithm); 156 out.writeByteArray(mSalt); 157 out.writeInt(mMemoryDifficulty); 158 } 159 160 /** 161 * @hide 162 */ KeyDerivationParams(Parcel in)163 protected KeyDerivationParams(Parcel in) { 164 mAlgorithm = in.readInt(); 165 mSalt = in.createByteArray(); 166 mMemoryDifficulty = in.readInt(); 167 } 168 169 @Override describeContents()170 public int describeContents() { 171 return 0; 172 } 173 } 174