blob: d1abe12d6353ff06902b937087479ba164a3a9fc [file] [log] [blame]
Alex Klyubincc21bb32015-03-31 16:50:37 -07001/*
2 * Copyright (C) 2015 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
Alex Klyubind23a1f72015-03-27 14:39:28 -070017package android.security;
18
19import android.security.keymaster.KeyCharacteristics;
20import android.security.keymaster.KeymasterArguments;
21import android.security.keymaster.KeymasterDefs;
22
23import java.security.InvalidAlgorithmParameterException;
24import java.security.SecureRandom;
25import java.security.spec.AlgorithmParameterSpec;
Alex Klyubin5045b712015-03-31 20:19:54 -070026import java.util.Date;
Alex Klyubind23a1f72015-03-27 14:39:28 -070027
28import javax.crypto.KeyGeneratorSpi;
29import javax.crypto.SecretKey;
30
31/**
32 * {@link KeyGeneratorSpi} backed by Android KeyStore.
33 *
34 * @hide
35 */
36public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
37
38 public static class AES extends KeyStoreKeyGeneratorSpi {
39 public AES() {
Alex Klyubin5927c9f2015-04-10 13:28:03 -070040 super(KeymasterDefs.KM_ALGORITHM_AES, 128);
Alex Klyubind23a1f72015-03-27 14:39:28 -070041 }
42 }
43
Alex Klyubin70376a72015-04-08 14:15:57 -070044 protected static abstract class HmacBase extends KeyStoreKeyGeneratorSpi {
Alex Klyubin5927c9f2015-04-10 13:28:03 -070045 protected HmacBase(int keymasterDigest) {
46 super(KeymasterDefs.KM_ALGORITHM_HMAC,
47 keymasterDigest,
48 KeymasterUtils.getDigestOutputSizeBytes(keymasterDigest) * 8);
Alex Klyubin70376a72015-04-08 14:15:57 -070049 }
50 }
51
52 public static class HmacSHA1 extends HmacBase {
53 public HmacSHA1() {
Alex Klyubin5927c9f2015-04-10 13:28:03 -070054 super(KeymasterDefs.KM_DIGEST_SHA1);
Alex Klyubin70376a72015-04-08 14:15:57 -070055 }
56 }
57
58 public static class HmacSHA224 extends HmacBase {
59 public HmacSHA224() {
Alex Klyubin5927c9f2015-04-10 13:28:03 -070060 super(KeymasterDefs.KM_DIGEST_SHA_2_224);
Alex Klyubin70376a72015-04-08 14:15:57 -070061 }
62 }
63
64 public static class HmacSHA256 extends HmacBase {
65 public HmacSHA256() {
Alex Klyubin5927c9f2015-04-10 13:28:03 -070066 super(KeymasterDefs.KM_DIGEST_SHA_2_256);
Alex Klyubin70376a72015-04-08 14:15:57 -070067 }
68 }
69
70 public static class HmacSHA384 extends HmacBase {
71 public HmacSHA384() {
Alex Klyubin5927c9f2015-04-10 13:28:03 -070072 super(KeymasterDefs.KM_DIGEST_SHA_2_384);
Alex Klyubin70376a72015-04-08 14:15:57 -070073 }
74 }
75
76 public static class HmacSHA512 extends HmacBase {
77 public HmacSHA512() {
Alex Klyubin5927c9f2015-04-10 13:28:03 -070078 super(KeymasterDefs.KM_DIGEST_SHA_2_512);
Alex Klyubind23a1f72015-03-27 14:39:28 -070079 }
80 }
81
82 private final KeyStore mKeyStore = KeyStore.getInstance();
Alex Klyubin5927c9f2015-04-10 13:28:03 -070083 private final int mKeymasterAlgorithm;
84 private final int mKeymasterDigest;
Alex Klyubind23a1f72015-03-27 14:39:28 -070085 private final int mDefaultKeySizeBits;
86
87 private KeyGeneratorSpec mSpec;
88 private SecureRandom mRng;
89
90 protected KeyStoreKeyGeneratorSpi(
Alex Klyubin5927c9f2015-04-10 13:28:03 -070091 int keymasterAlgorithm,
Alex Klyubind23a1f72015-03-27 14:39:28 -070092 int defaultKeySizeBits) {
Alex Klyubin5927c9f2015-04-10 13:28:03 -070093 this(keymasterAlgorithm, -1, defaultKeySizeBits);
Alex Klyubind23a1f72015-03-27 14:39:28 -070094 }
95
96 protected KeyStoreKeyGeneratorSpi(
Alex Klyubin5927c9f2015-04-10 13:28:03 -070097 int keymasterAlgorithm,
98 int keymasterDigest,
Alex Klyubind23a1f72015-03-27 14:39:28 -070099 int defaultKeySizeBits) {
Alex Klyubin5927c9f2015-04-10 13:28:03 -0700100 mKeymasterAlgorithm = keymasterAlgorithm;
101 mKeymasterDigest = keymasterDigest;
Alex Klyubind23a1f72015-03-27 14:39:28 -0700102 mDefaultKeySizeBits = defaultKeySizeBits;
103 }
104
105 @Override
106 protected SecretKey engineGenerateKey() {
107 KeyGeneratorSpec spec = mSpec;
108 if (spec == null) {
109 throw new IllegalStateException("Not initialized");
110 }
111
112 if ((spec.isEncryptionRequired())
113 && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
114 throw new IllegalStateException(
115 "Android KeyStore must be in initialized and unlocked state if encryption is"
116 + " required");
117 }
118
119 KeymasterArguments args = new KeymasterArguments();
Alex Klyubin5927c9f2015-04-10 13:28:03 -0700120 args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
121 if (mKeymasterDigest != -1) {
122 args.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
123 int digestOutputSizeBytes =
124 KeymasterUtils.getDigestOutputSizeBytes(mKeymasterDigest);
125 if (digestOutputSizeBytes != -1) {
Alex Klyubin4ab8ea42015-03-27 16:53:44 -0700126 // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
127 // TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
128 args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
129 }
130 }
Alex Klyubin5927c9f2015-04-10 13:28:03 -0700131 if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
132 if (mKeymasterDigest == -1) {
133 throw new IllegalStateException("Digest algorithm must be specified for HMAC key");
Alex Klyubinb406f242015-03-31 13:39:38 -0700134 }
135 }
Alex Klyubin9b3e0052015-04-13 11:12:57 -0700136 int keySizeBits = (spec.getKeySize() != -1) ? spec.getKeySize() : mDefaultKeySizeBits;
Alex Klyubind23a1f72015-03-27 14:39:28 -0700137 args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keySizeBits);
Alex Klyubin5927c9f2015-04-10 13:28:03 -0700138 @KeyStoreKeyProperties.PurposeEnum int purposes = spec.getPurposes();
139 int[] keymasterBlockModes = KeymasterUtils.getKeymasterBlockModesFromJcaBlockModes(
140 spec.getBlockModes());
141 if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
Alex Klyubinf853f642015-04-08 13:36:22 -0700142 && (spec.isRandomizedEncryptionRequired())) {
Alex Klyubin5927c9f2015-04-10 13:28:03 -0700143 for (int keymasterBlockMode : keymasterBlockModes) {
144 if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible(keymasterBlockMode)) {
145 throw new IllegalStateException(
146 "Randomized encryption (IND-CPA) required but may be violated by block"
147 + " mode: "
148 + KeymasterUtils.getJcaBlockModeFromKeymasterBlockMode(
149 keymasterBlockMode)
150 + ". See KeyGeneratorSpec documentation.");
151 }
Alex Klyubinf853f642015-04-08 13:36:22 -0700152 }
153 }
154
Alex Klyubind23a1f72015-03-27 14:39:28 -0700155 for (int keymasterPurpose :
Alex Klyubin5927c9f2015-04-10 13:28:03 -0700156 KeyStoreKeyProperties.Purpose.allToKeymaster(purposes)) {
Alex Klyubind23a1f72015-03-27 14:39:28 -0700157 args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose);
158 }
Alex Klyubin5927c9f2015-04-10 13:28:03 -0700159 args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
160 args.addInts(
161 KeymasterDefs.KM_TAG_PADDING,
162 KeymasterUtils.getKeymasterPaddingsFromJcaEncryptionPaddings(
163 spec.getEncryptionPaddings()));
Alex Klyubinc46e9e72015-04-06 15:36:25 -0700164 if (spec.getUserAuthenticators() == 0) {
Alex Klyubind23a1f72015-03-27 14:39:28 -0700165 args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
166 } else {
Alex Klyubinc8e55742015-03-31 19:50:13 -0700167 args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
Alex Klyubin5927c9f2015-04-10 13:28:03 -0700168 KeyStoreKeyProperties.UserAuthenticator.allToKeymaster(
Alex Klyubinc8e55742015-03-31 19:50:13 -0700169 spec.getUserAuthenticators()));
Alex Klyubin10a9f172015-04-16 13:41:19 -0700170 long secureUserId = GateKeeper.getSecureUserId();
171 if (secureUserId == 0) {
172 throw new IllegalStateException("Secure lock screen must be enabled"
173 + " to generate keys requiring user authentication");
174 }
175 args.addLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, secureUserId);
Alex Klyubind23a1f72015-03-27 14:39:28 -0700176 }
Alex Klyubin2ea13d42015-04-01 14:41:28 -0700177 if (spec.isInvalidatedOnNewFingerprintEnrolled()) {
178 // TODO: Add the invalidate on fingerprint enrolled constraint once Keymaster supports
179 // that.
180 }
Alex Klyubinc46e9e72015-04-06 15:36:25 -0700181 if (spec.getUserAuthenticationValidityDurationSeconds() != -1) {
Alex Klyubind23a1f72015-03-27 14:39:28 -0700182 args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
183 spec.getUserAuthenticationValidityDurationSeconds());
184 }
Alex Klyubin5045b712015-03-31 20:19:54 -0700185 args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
186 (spec.getKeyValidityStart() != null)
187 ? spec.getKeyValidityStart() : new Date(0));
188 args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
189 (spec.getKeyValidityForOriginationEnd() != null)
190 ? spec.getKeyValidityForOriginationEnd() : new Date(Long.MAX_VALUE));
191 args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
192 (spec.getKeyValidityForConsumptionEnd() != null)
193 ? spec.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE));
Alex Klyubind23a1f72015-03-27 14:39:28 -0700194
Alex Klyubin5927c9f2015-04-10 13:28:03 -0700195 if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
Alex Klyubinf853f642015-04-08 13:36:22 -0700196 && (!spec.isRandomizedEncryptionRequired())) {
197 // Permit caller-provided IV when encrypting with this key
Alex Klyubind23a1f72015-03-27 14:39:28 -0700198 args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
199 }
200
201 byte[] additionalEntropy = null;
202 SecureRandom rng = mRng;
203 if (rng != null) {
204 additionalEntropy = new byte[(keySizeBits + 7) / 8];
205 rng.nextBytes(additionalEntropy);
206 }
207
208 int flags = spec.getFlags();
209 String keyAliasInKeystore = Credentials.USER_SECRET_KEY + spec.getKeystoreAlias();
210 int errorCode = mKeyStore.generateKey(
211 keyAliasInKeystore, args, additionalEntropy, flags, new KeyCharacteristics());
212 if (errorCode != KeyStore.NO_ERROR) {
Alex Klyubinb4834ae2015-04-02 15:53:46 -0700213 throw KeyStore.getCryptoOperationException(errorCode);
Alex Klyubind23a1f72015-03-27 14:39:28 -0700214 }
215 String keyAlgorithmJCA =
Alex Klyubin5927c9f2015-04-10 13:28:03 -0700216 KeymasterUtils.getJcaSecretKeyAlgorithm(mKeymasterAlgorithm, mKeymasterDigest);
Alex Klyubind23a1f72015-03-27 14:39:28 -0700217 return new KeyStoreSecretKey(keyAliasInKeystore, keyAlgorithmJCA);
218 }
219
220 @Override
221 protected void engineInit(SecureRandom random) {
222 throw new UnsupportedOperationException("Cannot initialize without an "
223 + KeyGeneratorSpec.class.getName() + " parameter");
224 }
225
226 @Override
227 protected void engineInit(AlgorithmParameterSpec params, SecureRandom random)
228 throws InvalidAlgorithmParameterException {
229 if ((params == null) || (!(params instanceof KeyGeneratorSpec))) {
230 throw new InvalidAlgorithmParameterException("Cannot initialize without an "
231 + KeyGeneratorSpec.class.getName() + " parameter");
232 }
233 KeyGeneratorSpec spec = (KeyGeneratorSpec) params;
234 if (spec.getKeystoreAlias() == null) {
235 throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
236 }
237
238 mSpec = spec;
239 mRng = random;
240 }
241
242 @Override
243 protected void engineInit(int keySize, SecureRandom random) {
244 throw new UnsupportedOperationException("Cannot initialize without a "
245 + KeyGeneratorSpec.class.getName() + " parameter");
246 }
247}