diff options
author | Alex Klyubin <klyubin@google.com> | 2015-07-16 16:32:23 -0700 |
---|---|---|
committer | Alex Klyubin <klyubin@google.com> | 2015-07-16 16:52:51 -0700 |
commit | a95550f8016bbb0dba086dbd73eec63e6cdbbe98 (patch) | |
tree | e6912c5fdb0fc66d6a5fc7fe48d3e8c640270877 /keystore/java | |
parent | f7592b234acde62f0f0a93dad77284f12ca9980a (diff) | |
download | frameworks_base-a95550f8016bbb0dba086dbd73eec63e6cdbbe98.zip frameworks_base-a95550f8016bbb0dba086dbd73eec63e6cdbbe98.tar.gz frameworks_base-a95550f8016bbb0dba086dbd73eec63e6cdbbe98.tar.bz2 |
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
Diffstat (limited to 'keystore/java')
4 files changed, 55 insertions, 2 deletions
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java index 5459bea..441ee66 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java @@ -51,7 +51,7 @@ import javax.crypto.spec.GCMParameterSpec; abstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase { abstract static class GCM extends AndroidKeyStoreAuthenticatedAESCipherSpi { - private static final int MIN_SUPPORTED_TAG_LENGTH_BITS = 96; + static final int MIN_SUPPORTED_TAG_LENGTH_BITS = 96; private static final int MAX_SUPPORTED_TAG_LENGTH_BITS = 128; private static final int DEFAULT_TAG_LENGTH_BITS = 128; private static final int IV_LENGTH_BYTES = 12; diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java index fd014eb..4c174f1 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java @@ -171,7 +171,7 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { "Key size must be positive: " + mKeySizeBits); } else if ((mKeySizeBits % 8) != 0) { throw new InvalidAlgorithmParameterException( - "Key size in must be a multiple of 8: " + mKeySizeBits); + "Key size must be a multiple of 8: " + mKeySizeBits); } try { @@ -272,6 +272,11 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { KeymasterUtils.addUserAuthArgs(args, spec.isUserAuthenticationRequired(), spec.getUserAuthenticationValidityDurationSeconds()); + KeymasterUtils.addMinMacLengthAuthorizationIfNecessary( + args, + mKeymasterAlgorithm, + mKeymasterBlockModes, + mKeymasterDigests); args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart()); args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, spec.getKeyValidityForOriginationEnd()); diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java index 88858de..915d86f 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java @@ -672,6 +672,11 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { KeymasterUtils.addUserAuthArgs(args, params.isUserAuthenticationRequired(), params.getUserAuthenticationValidityDurationSeconds()); + KeymasterUtils.addMinMacLengthAuthorizationIfNecessary( + args, + keymasterAlgorithm, + keymasterBlockModes, + keymasterDigests); args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, params.getKeyValidityStart()); args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java index 92d636c..feafbfa 100644 --- a/keystore/java/android/security/keystore/KeymasterUtils.java +++ b/keystore/java/android/security/keystore/KeymasterUtils.java @@ -22,6 +22,8 @@ import android.security.KeyStore; import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterDefs; +import java.security.ProviderException; + /** * @hide */ @@ -133,4 +135,45 @@ public abstract class KeymasterUtils { userAuthenticationValidityDurationSeconds); } } + + /** + * Adds {@code KM_TAG_MIN_MAC_LENGTH} tag, if necessary, to the keymaster arguments for + * generating or importing a key. This tag may only be needed for symmetric keys (e.g., HMAC, + * AES-GCM). + */ + public static void addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args, + int keymasterAlgorithm, + int[] keymasterBlockModes, + int[] keymasterDigests) { + switch (keymasterAlgorithm) { + case KeymasterDefs.KM_ALGORITHM_AES: + if (com.android.internal.util.ArrayUtils.contains( + keymasterBlockModes, KeymasterDefs.KM_MODE_GCM)) { + // AES GCM key needs the minimum length of AEAD tag specified. + args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, + AndroidKeyStoreAuthenticatedAESCipherSpi.GCM + .MIN_SUPPORTED_TAG_LENGTH_BITS); + } + break; + case KeymasterDefs.KM_ALGORITHM_HMAC: + // HMAC key needs the minimum length of MAC set to the output size of the associated + // digest. This is because we do not offer a way to generate shorter MACs and + // don't offer a way to verify MACs (other than by generating them). + if (keymasterDigests.length != 1) { + throw new ProviderException( + "Unsupported number of authorized digests for HMAC key: " + + keymasterDigests.length + + ". Exactly one digest must be authorized"); + } + int keymasterDigest = keymasterDigests[0]; + int digestOutputSizeBits = getDigestOutputSizeBits(keymasterDigest); + if (digestOutputSizeBits == -1) { + throw new ProviderException( + "HMAC key authorized for unsupported digest: " + + KeyProperties.Digest.fromKeymaster(keymasterDigest)); + } + args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits); + break; + } + } } |