1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
package android.security;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterDefs;
import java.security.InvalidKeyException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Collections;
import java.util.Set;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactorySpi;
import javax.crypto.spec.SecretKeySpec;
/**
* {@link SecretKeyFactorySpi} backed by Android KeyStore.
*
* @hide
*/
public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
private final KeyStore mKeyStore = KeyStore.getInstance();
@Override
protected KeySpec engineGetKeySpec(SecretKey key,
@SuppressWarnings("rawtypes") Class keySpecClass) throws InvalidKeySpecException {
if (keySpecClass == null) {
throw new InvalidKeySpecException("keySpecClass == null");
}
if (!(key instanceof KeyStoreSecretKey)) {
throw new InvalidKeySpecException("Only Android KeyStore secret keys supported: " +
((key != null) ? key.getClass().getName() : "null"));
}
if (SecretKeySpec.class.isAssignableFrom(keySpecClass)) {
throw new InvalidKeySpecException(
"Key material export of Android KeyStore keys is not supported");
}
if (!KeyStoreKeySpec.class.equals(keySpecClass)) {
throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
}
String keyAliasInKeystore = ((KeyStoreSecretKey) key).getAlias();
String entryAlias;
if (keyAliasInKeystore.startsWith(Credentials.USER_SECRET_KEY)) {
entryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length());
} else {
throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
}
KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
int errorCode =
mKeyStore.getKeyCharacteristics(keyAliasInKeystore, null, null, keyCharacteristics);
if (errorCode != KeyStore.NO_ERROR) {
throw new InvalidKeySpecException("Failed to obtain information about key."
+ " Keystore error: " + errorCode);
}
@KeyStoreKeyCharacteristics.OriginEnum Integer origin;
int keySize;
@KeyStoreKeyConstraints.PurposeEnum int purposes;
@KeyStoreKeyConstraints.AlgorithmEnum int algorithm;
@KeyStoreKeyConstraints.PaddingEnum Integer padding;
@KeyStoreKeyConstraints.DigestEnum Integer digest;
@KeyStoreKeyConstraints.BlockModeEnum Integer blockMode;
try {
origin = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_ORIGIN);
if (origin == null) {
throw new InvalidKeySpecException("Key origin not available");
}
origin = KeyStoreKeyCharacteristics.Origin.fromKeymaster(origin);
Integer keySizeInteger =
KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_KEY_SIZE);
if (keySizeInteger == null) {
throw new InvalidKeySpecException("Key size not available");
}
keySize = keySizeInteger;
purposes = KeyStoreKeyConstraints.Purpose.allFromKeymaster(
KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_PURPOSE));
Integer alg = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_ALGORITHM);
if (alg == null) {
throw new InvalidKeySpecException("Key algorithm not available");
}
algorithm = KeyStoreKeyConstraints.Algorithm.fromKeymaster(alg);
padding = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_PADDING);
if (padding != null) {
padding = KeyStoreKeyConstraints.Padding.fromKeymaster(padding);
}
digest = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_DIGEST);
if (digest != null) {
digest = KeyStoreKeyConstraints.Digest.fromKeymaster(digest);
}
blockMode = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_BLOCK_MODE);
if (blockMode != null) {
blockMode = KeyStoreKeyConstraints.BlockMode.fromKeymaster(blockMode);
}
} catch (IllegalArgumentException e) {
throw new InvalidKeySpecException("Unsupported key characteristic", e);
}
// TODO: Read user authentication IDs once the Keymaster API has stabilized
Set<Integer> userAuthenticators = Collections.emptySet();
Set<Integer> teeBackedUserAuthenticators = Collections.emptySet();
// Set<Integer> userAuthenticators = new HashSet<Integer>(
// getInts(keyCharacteristics, KeymasterDefs.KM_TAG_USER_AUTH_ID));
// Set<Integer> teeBackedUserAuthenticators = new HashSet<Integer>(
// keyCharacteristics.hwEnforced.getInts(KeymasterDefs.KM_TAG_USER_AUTH_ID));
return new KeyStoreKeySpec(entryAlias,
origin,
keySize,
KeymasterUtils.getDate(keyCharacteristics, KeymasterDefs.KM_TAG_ACTIVE_DATETIME),
KeymasterUtils.getDate(keyCharacteristics,
KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME),
KeymasterUtils.getDate(keyCharacteristics,
KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME),
purposes,
algorithm,
padding,
digest,
blockMode,
KeymasterUtils.getInt(keyCharacteristics,
KeymasterDefs.KM_TAG_MIN_SECONDS_BETWEEN_OPS),
KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_MAX_USES_PER_BOOT),
userAuthenticators,
teeBackedUserAuthenticators,
KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_AUTH_TIMEOUT));
}
@Override
protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException {
throw new UnsupportedOperationException(
"Key import into Android KeyStore is not supported");
}
@Override
protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException {
throw new UnsupportedOperationException(
"Key import into Android KeyStore is not supported");
}
}
|