Skip to content

Commit a95550f

Browse files
author
Alex Klyubin
committed
Add KM_MIN_MAC_LENGTH tag to HMAC and AES-GCM keys.
This makes Android Keystore add the KM_MIN_MAC_LENGTH tag to generated and imported HMAC and AES-GCM keys. This tag specifies the minimum length of the MAC/authentication tag authorized to be used for the key. For HMAC keys the minimum MAC length is set to the length of the digest associated with the key (HMAC keys are authorized for exactly one digest). For AES keys the minimum authetication tag length is set to 96 bit. This is the minimum supported by Android Keystore's AES-GCM implementation. Bug: 22337277 Change-Id: Ic6e47cf084734d1592788dc58088889f7fff74eb
1 parent f7592b2 commit a95550f

5 files changed

Lines changed: 61 additions & 2 deletions

File tree

core/java/android/security/keymaster/KeymasterDefs.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ private KeymasterDefs() {}
5151
public static final int KM_TAG_DIGEST = KM_ENUM_REP | 5;
5252
public static final int KM_TAG_PADDING = KM_ENUM_REP | 6;
5353
public static final int KM_TAG_CALLER_NONCE = KM_BOOL | 7;
54+
public static final int KM_TAG_MIN_MAC_LENGTH = KM_UINT | 8;
5455

5556
public static final int KM_TAG_RESCOPING_ADD = KM_ENUM_REP | 101;
5657
public static final int KM_TAG_RESCOPING_DEL = KM_ENUM_REP | 102;
@@ -194,6 +195,9 @@ private KeymasterDefs() {}
194195
public static final int KM_ERROR_KEY_RATE_LIMIT_EXCEEDED = -54;
195196
public static final int KM_ERROR_CALLER_NONCE_PROHIBITED = -55;
196197
public static final int KM_ERROR_KEY_MAX_OPS_EXCEEDED = -56;
198+
public static final int KM_ERROR_INVALID_MAC_LENGTH = -57;
199+
public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58;
200+
public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59;
197201
public static final int KM_ERROR_UNIMPLEMENTED = -100;
198202
public static final int KM_ERROR_VERSION_MISMATCH = -101;
199203
public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
@@ -237,6 +241,8 @@ private KeymasterDefs() {}
237241
sErrorCodeToString.put(KM_ERROR_INVALID_NONCE, "Invalid IV");
238242
sErrorCodeToString.put(KM_ERROR_CALLER_NONCE_PROHIBITED,
239243
"Caller-provided IV not permitted");
244+
sErrorCodeToString.put(KM_ERROR_INVALID_MAC_LENGTH,
245+
"Invalid MAC or authentication tag length");
240246
sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
241247
sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
242248
}

keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
abstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase {
5252

5353
abstract static class GCM extends AndroidKeyStoreAuthenticatedAESCipherSpi {
54-
private static final int MIN_SUPPORTED_TAG_LENGTH_BITS = 96;
54+
static final int MIN_SUPPORTED_TAG_LENGTH_BITS = 96;
5555
private static final int MAX_SUPPORTED_TAG_LENGTH_BITS = 128;
5656
private static final int DEFAULT_TAG_LENGTH_BITS = 128;
5757
private static final int IV_LENGTH_BYTES = 12;

keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ protected void engineInit(AlgorithmParameterSpec params, SecureRandom random)
171171
"Key size must be positive: " + mKeySizeBits);
172172
} else if ((mKeySizeBits % 8) != 0) {
173173
throw new InvalidAlgorithmParameterException(
174-
"Key size in must be a multiple of 8: " + mKeySizeBits);
174+
"Key size must be a multiple of 8: " + mKeySizeBits);
175175
}
176176

177177
try {
@@ -272,6 +272,11 @@ protected SecretKey engineGenerateKey() {
272272
KeymasterUtils.addUserAuthArgs(args,
273273
spec.isUserAuthenticationRequired(),
274274
spec.getUserAuthenticationValidityDurationSeconds());
275+
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
276+
args,
277+
mKeymasterAlgorithm,
278+
mKeymasterBlockModes,
279+
mKeymasterDigests);
275280
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart());
276281
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
277282
spec.getKeyValidityForOriginationEnd());

keystore/java/android/security/keystore/AndroidKeyStoreSpi.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,11 @@ private void setSecretKeyEntry(String entryAlias, SecretKey key,
672672
KeymasterUtils.addUserAuthArgs(args,
673673
params.isUserAuthenticationRequired(),
674674
params.getUserAuthenticationValidityDurationSeconds());
675+
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
676+
args,
677+
keymasterAlgorithm,
678+
keymasterBlockModes,
679+
keymasterDigests);
675680
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
676681
params.getKeyValidityStart());
677682
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,

keystore/java/android/security/keystore/KeymasterUtils.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import android.security.keymaster.KeymasterArguments;
2323
import android.security.keymaster.KeymasterDefs;
2424

25+
import java.security.ProviderException;
26+
2527
/**
2628
* @hide
2729
*/
@@ -133,4 +135,45 @@ public static void addUserAuthArgs(KeymasterArguments args,
133135
userAuthenticationValidityDurationSeconds);
134136
}
135137
}
138+
139+
/**
140+
* Adds {@code KM_TAG_MIN_MAC_LENGTH} tag, if necessary, to the keymaster arguments for
141+
* generating or importing a key. This tag may only be needed for symmetric keys (e.g., HMAC,
142+
* AES-GCM).
143+
*/
144+
public static void addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args,
145+
int keymasterAlgorithm,
146+
int[] keymasterBlockModes,
147+
int[] keymasterDigests) {
148+
switch (keymasterAlgorithm) {
149+
case KeymasterDefs.KM_ALGORITHM_AES:
150+
if (com.android.internal.util.ArrayUtils.contains(
151+
keymasterBlockModes, KeymasterDefs.KM_MODE_GCM)) {
152+
// AES GCM key needs the minimum length of AEAD tag specified.
153+
args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH,
154+
AndroidKeyStoreAuthenticatedAESCipherSpi.GCM
155+
.MIN_SUPPORTED_TAG_LENGTH_BITS);
156+
}
157+
break;
158+
case KeymasterDefs.KM_ALGORITHM_HMAC:
159+
// HMAC key needs the minimum length of MAC set to the output size of the associated
160+
// digest. This is because we do not offer a way to generate shorter MACs and
161+
// don't offer a way to verify MACs (other than by generating them).
162+
if (keymasterDigests.length != 1) {
163+
throw new ProviderException(
164+
"Unsupported number of authorized digests for HMAC key: "
165+
+ keymasterDigests.length
166+
+ ". Exactly one digest must be authorized");
167+
}
168+
int keymasterDigest = keymasterDigests[0];
169+
int digestOutputSizeBits = getDigestOutputSizeBits(keymasterDigest);
170+
if (digestOutputSizeBits == -1) {
171+
throw new ProviderException(
172+
"HMAC key authorized for unsupported digest: "
173+
+ KeyProperties.Digest.fromKeymaster(keymasterDigest));
174+
}
175+
args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits);
176+
break;
177+
}
178+
}
136179
}

0 commit comments

Comments
 (0)