diff options
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; + } + } } |