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