diff options
Diffstat (limited to 'keystore/java')
4 files changed, 143 insertions, 83 deletions
diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java index afa0c8e..bd601bc 100644 --- a/keystore/java/android/security/KeyStoreCipherSpi.java +++ b/keystore/java/android/security/KeyStoreCipherSpi.java @@ -27,6 +27,7 @@ import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; @@ -315,15 +316,15 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry } else if (e instanceof InvalidAlgorithmParameterException) { throw (InvalidAlgorithmParameterException) e; } else { - throw new RuntimeException("Unexpected exception type", e); + throw new ProviderException("Unexpected exception type", e); } } if (mOperationToken == null) { - throw new IllegalStateException("Keystore returned null operation token"); + throw new ProviderException("Keystore returned null operation token"); } if (mOperationHandle == 0) { - throw new IllegalStateException("Keystore returned invalid operation handle"); + throw new ProviderException("Keystore returned invalid operation handle"); } loadAlgorithmSpecificParametersFromBeginResult(keymasterOutputArgs); @@ -499,9 +500,9 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry params.init(new IvParameterSpec(mIv)); return params; } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("Failed to obtain AES AlgorithmParameters", e); + throw new ProviderException("Failed to obtain AES AlgorithmParameters", e); } catch (InvalidParameterSpecException e) { - throw new RuntimeException( + throw new ProviderException( "Failed to initialize AES AlgorithmParameters with an IV", e); } } @@ -668,11 +669,11 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry if (mIv == null) { mIv = returnedIv; } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) { - throw new IllegalStateException("IV in use differs from provided IV"); + throw new ProviderException("IV in use differs from provided IV"); } } else { if (returnedIv != null) { - throw new IllegalStateException( + throw new ProviderException( "IV in use despite IV not being used by this transformation"); } } diff --git a/keystore/java/android/security/KeyStoreConnectException.java b/keystore/java/android/security/KeyStoreConnectException.java index 1aa3aec..885f1f7 100644 --- a/keystore/java/android/security/KeyStoreConnectException.java +++ b/keystore/java/android/security/KeyStoreConnectException.java @@ -16,12 +16,14 @@ package android.security; +import java.security.ProviderException; + /** * Indicates a communications error with keystore service. * * @hide */ -public class KeyStoreConnectException extends IllegalStateException { +public class KeyStoreConnectException extends ProviderException { public KeyStoreConnectException() { super("Failed to communicate with keystore service"); } diff --git a/keystore/java/android/security/KeyStoreHmacSpi.java b/keystore/java/android/security/KeyStoreHmacSpi.java index 0dbe788..5089a25 100644 --- a/keystore/java/android/security/KeyStoreHmacSpi.java +++ b/keystore/java/android/security/KeyStoreHmacSpi.java @@ -24,6 +24,7 @@ import android.security.keymaster.OperationResult; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; +import java.security.ProviderException; import java.security.spec.AlgorithmParameterSpec; import javax.crypto.MacSpi; @@ -185,10 +186,10 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp } if (mOperationToken == null) { - throw new IllegalStateException("Keystore returned null operation token"); + throw new ProviderException("Keystore returned null operation token"); } if (mOperationHandle == 0) { - throw new IllegalStateException("Keystore returned invalid operation handle"); + throw new ProviderException("Keystore returned invalid operation handle"); } mChunkedStreamer = new KeyStoreCryptoOperationChunkedStreamer( @@ -206,17 +207,17 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp try { ensureKeystoreOperationInitialized(); } catch (InvalidKeyException e) { - throw new IllegalStateException("Failed to reinitialize MAC", e); + throw new ProviderException("Failed to reinitialize MAC", e); } byte[] output; try { output = mChunkedStreamer.update(input, offset, len); } catch (KeyStoreException e) { - throw new IllegalStateException("Keystore operation failed", e); + throw new ProviderException("Keystore operation failed", e); } if ((output != null) && (output.length != 0)) { - throw new IllegalStateException("Update operation unexpectedly produced output"); + throw new ProviderException("Update operation unexpectedly produced output"); } } @@ -225,14 +226,14 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp try { ensureKeystoreOperationInitialized(); } catch (InvalidKeyException e) { - throw new IllegalStateException("Failed to reinitialize MAC", e); + throw new ProviderException("Failed to reinitialize MAC", e); } byte[] result; try { result = mChunkedStreamer.doFinal(null, 0, 0); } catch (KeyStoreException e) { - throw new IllegalStateException("Keystore operation failed", e); + throw new ProviderException("Keystore operation failed", e); } resetWhilePreservingInitState(); diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java index c265c46..4b914c2 100644 --- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java @@ -21,6 +21,7 @@ import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterDefs; import java.security.InvalidAlgorithmParameterException; +import java.security.ProviderException; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.util.Date; @@ -39,6 +40,17 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { public AES() { super(KeymasterDefs.KM_ALGORITHM_AES, 128); } + + @Override + protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException { + super.engineInit(params, random); + if ((mKeySizeBits != 128) && (mKeySizeBits != 192) && (mKeySizeBits != 256)) { + throw new InvalidAlgorithmParameterException( + "Unsupported key size: " + mKeySizeBits + + ". Supported: 128, 192, 256."); + } + } } protected static abstract class HmacBase extends KeyStoreKeyGeneratorSpi { @@ -87,6 +99,11 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { private KeyGeneratorSpec mSpec; private SecureRandom mRng; + protected int mKeySizeBits; + private int[] mKeymasterPurposes; + private int[] mKeymasterBlockModes; + private int[] mKeymasterPaddings; + protected KeyStoreKeyGeneratorSpi( int keymasterAlgorithm, int defaultKeySizeBits) { @@ -100,6 +117,97 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { mKeymasterAlgorithm = keymasterAlgorithm; mKeymasterDigest = keymasterDigest; mDefaultKeySizeBits = defaultKeySizeBits; + if (mDefaultKeySizeBits <= 0) { + throw new IllegalArgumentException("Default key size must be positive"); + } + + if ((mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) && (mKeymasterDigest == -1)) { + throw new IllegalArgumentException( + "Digest algorithm must be specified for HMAC key"); + } + } + + @Override + protected void engineInit(SecureRandom random) { + throw new UnsupportedOperationException("Cannot initialize without an " + + KeyGeneratorSpec.class.getName() + " parameter"); + } + + @Override + protected void engineInit(int keySize, SecureRandom random) { + throw new UnsupportedOperationException("Cannot initialize without a " + + KeyGeneratorSpec.class.getName() + " parameter"); + } + + @Override + protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException { + resetAll(); + + boolean success = false; + try { + if ((params == null) || (!(params instanceof KeyGeneratorSpec))) { + throw new InvalidAlgorithmParameterException("Cannot initialize without an " + + KeyGeneratorSpec.class.getName() + " parameter"); + } + KeyGeneratorSpec spec = (KeyGeneratorSpec) params; + if (spec.getKeystoreAlias() == null) { + throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided"); + } + + mRng = random; + mSpec = spec; + + mKeySizeBits = (spec.getKeySize() != -1) ? spec.getKeySize() : mDefaultKeySizeBits; + if (mKeySizeBits <= 0) { + throw new InvalidAlgorithmParameterException( + "Key size must be positive: " + mKeySizeBits); + } else if ((mKeySizeBits % 8) != 0) { + throw new InvalidAlgorithmParameterException( + "Key size in must be a multiple of 8: " + mKeySizeBits); + } + + try { + mKeymasterPurposes = + KeyStoreKeyProperties.Purpose.allToKeymaster(spec.getPurposes()); + mKeymasterPaddings = KeyStoreKeyProperties.EncryptionPadding.allToKeymaster( + spec.getEncryptionPaddings()); + mKeymasterBlockModes = + KeyStoreKeyProperties.BlockMode.allToKeymaster(spec.getBlockModes()); + if (((spec.getPurposes() & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0) + && (spec.isRandomizedEncryptionRequired())) { + for (int keymasterBlockMode : mKeymasterBlockModes) { + if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible( + keymasterBlockMode)) { + throw new InvalidAlgorithmParameterException( + "Randomized encryption (IND-CPA) required but may be violated" + + " by block mode: " + + KeyStoreKeyProperties.BlockMode.fromKeymaster( + keymasterBlockMode) + + ". See " + KeyGeneratorSpec.class.getName() + + " documentation."); + } + } + } + } catch (IllegalArgumentException e) { + throw new InvalidAlgorithmParameterException(e); + } + + success = true; + } finally { + if (!success) { + resetAll(); + } + } + } + + private void resetAll() { + mSpec = null; + mRng = null; + mKeySizeBits = -1; + mKeymasterPurposes = null; + mKeymasterPaddings = null; + mKeymasterBlockModes = null; } @Override @@ -117,42 +225,14 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { } KeymasterArguments args = new KeymasterArguments(); + args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits); args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm); if (mKeymasterDigest != -1) { args.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest); } - if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) { - if (mKeymasterDigest == -1) { - throw new IllegalStateException("Digest algorithm must be specified for HMAC key"); - } - } - int keySizeBits = (spec.getKeySize() != -1) ? spec.getKeySize() : mDefaultKeySizeBits; - args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keySizeBits); - @KeyStoreKeyProperties.PurposeEnum int purposes = spec.getPurposes(); - int[] keymasterBlockModes = - KeyStoreKeyProperties.BlockMode.allToKeymaster(spec.getBlockModes()); - if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0) - && (spec.isRandomizedEncryptionRequired())) { - for (int keymasterBlockMode : keymasterBlockModes) { - if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible(keymasterBlockMode)) { - throw new IllegalStateException( - "Randomized encryption (IND-CPA) required but may be violated by block" - + " mode: " - + KeyStoreKeyProperties.BlockMode.fromKeymaster(keymasterBlockMode) - + ". See KeyGeneratorSpec documentation."); - } - } - } - - for (int keymasterPurpose : - KeyStoreKeyProperties.Purpose.allToKeymaster(purposes)) { - args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose); - } - args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes); - args.addInts( - KeymasterDefs.KM_TAG_PADDING, - KeyStoreKeyProperties.EncryptionPadding.allToKeymaster( - spec.getEncryptionPaddings())); + args.addInts(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes); + args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes); + args.addInts(KeymasterDefs.KM_TAG_PADDING, mKeymasterPaddings); KeymasterUtils.addUserAuthArgs(args, spec.getContext(), spec.isUserAuthenticationRequired(), @@ -167,7 +247,7 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { (spec.getKeyValidityForConsumptionEnd() != null) ? spec.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE)); - if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0) + if (((spec.getPurposes() & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0) && (!spec.isRandomizedEncryptionRequired())) { // Permit caller-provided IV when encrypting with this key args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE); @@ -175,47 +255,23 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { byte[] additionalEntropy = KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng( - mRng, (keySizeBits + 7) / 8); - + mRng, (mKeySizeBits + 7) / 8); int flags = spec.getFlags(); String keyAliasInKeystore = Credentials.USER_SECRET_KEY + spec.getKeystoreAlias(); + KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics(); int errorCode = mKeyStore.generateKey( - keyAliasInKeystore, args, additionalEntropy, flags, new KeyCharacteristics()); + keyAliasInKeystore, args, additionalEntropy, flags, resultingKeyCharacteristics); if (errorCode != KeyStore.NO_ERROR) { - throw new IllegalStateException( + throw new ProviderException( "Keystore operation failed", KeyStore.getKeyStoreException(errorCode)); } - @KeyStoreKeyProperties.AlgorithmEnum String keyAlgorithmJCA = - KeyStoreKeyProperties.Algorithm.fromKeymasterSecretKeyAlgorithm( - mKeymasterAlgorithm, mKeymasterDigest); - return new KeyStoreSecretKey(keyAliasInKeystore, keyAlgorithmJCA); - } - - @Override - protected void engineInit(SecureRandom random) { - throw new UnsupportedOperationException("Cannot initialize without an " - + KeyGeneratorSpec.class.getName() + " parameter"); - } - - @Override - protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) - throws InvalidAlgorithmParameterException { - if ((params == null) || (!(params instanceof KeyGeneratorSpec))) { - throw new InvalidAlgorithmParameterException("Cannot initialize without an " - + KeyGeneratorSpec.class.getName() + " parameter"); - } - KeyGeneratorSpec spec = (KeyGeneratorSpec) params; - if (spec.getKeystoreAlias() == null) { - throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided"); + String keyAlgorithmJCA; + try { + keyAlgorithmJCA = KeyStoreKeyProperties.Algorithm.fromKeymasterSecretKeyAlgorithm( + mKeymasterAlgorithm, mKeymasterDigest); + } catch (IllegalArgumentException e) { + throw new ProviderException("Failed to obtain JCA secret key algorithm name", e); } - - mSpec = spec; - mRng = random; - } - - @Override - protected void engineInit(int keySize, SecureRandom random) { - throw new UnsupportedOperationException("Cannot initialize without a " - + KeyGeneratorSpec.class.getName() + " parameter"); + return new KeyStoreSecretKey(keyAliasInKeystore, keyAlgorithmJCA); } } |