Loading keystore/java/android/security/KeyStoreCipherSpi.java +44 −14 Original line number Original line Diff line number Diff line Loading @@ -111,7 +111,9 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockMode; private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockMode; private final @KeyStoreKeyConstraints.PaddingEnum int mPadding; private final @KeyStoreKeyConstraints.PaddingEnum int mPadding; private final int mBlockSizeBytes; private final int mBlockSizeBytes; private final boolean mIvUsed; /** Whether this transformation requires an IV. */ private final boolean mIvRequired; // Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after // Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after // doFinal finishes. // doFinal finishes. Loading @@ -119,10 +121,13 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry private KeyStoreSecretKey mKey; private KeyStoreSecretKey mKey; private SecureRandom mRng; private SecureRandom mRng; private boolean mFirstOperationInitiated; private boolean mFirstOperationInitiated; byte[] mIv; private byte[] mIv; /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */ private boolean mIvHasBeenUsed; // Fields below must be reset // Fields below must be reset after doFinal private byte[] mAdditionalEntropyForBegin; private byte[] mAdditionalEntropyForBegin; /** /** * Token referencing this operation inside keystore service. It is initialized by * Token referencing this operation inside keystore service. It is initialized by * {@code engineInit} and is invalidated when {@code engineDoFinal} succeeds and one some * {@code engineInit} and is invalidated when {@code engineDoFinal} succeeds and one some Loading @@ -143,7 +148,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry mBlockMode = blockMode; mBlockMode = blockMode; mPadding = padding; mPadding = padding; mBlockSizeBytes = blockSizeBytes; mBlockSizeBytes = blockSizeBytes; mIvUsed = ivUsed; mIvRequired = ivUsed; } } @Override @Override Loading @@ -170,7 +175,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry } } private void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { private void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { reset(); resetAll(); if (!(key instanceof KeyStoreSecretKey)) { if (!(key instanceof KeyStoreSecretKey)) { throw new InvalidKeyException( throw new InvalidKeyException( "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null")); "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null")); Loading @@ -187,7 +192,25 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry mEncrypting = opmode == Cipher.ENCRYPT_MODE; mEncrypting = opmode == Cipher.ENCRYPT_MODE; } } private void reset() { private void resetAll() { IBinder operationToken = mOperationToken; if (operationToken != null) { mOperationToken = null; mKeyStore.abort(operationToken); } mEncrypting = false; mKey = null; mRng = null; mFirstOperationInitiated = false; mIv = null; mIvHasBeenUsed = false; mAdditionalEntropyForBegin = null; mOperationToken = null; mOperationHandle = null; mMainDataStreamer = null; } private void resetWhilePreservingInitState() { IBinder operationToken = mOperationToken; IBinder operationToken = mOperationToken; if (operationToken != null) { if (operationToken != null) { mOperationToken = null; mOperationToken = null; Loading @@ -205,6 +228,12 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry if (mKey == null) { if (mKey == null) { throw new IllegalStateException("Not initialized"); throw new IllegalStateException("Not initialized"); } } if ((mEncrypting) && (mIvRequired) && (mIvHasBeenUsed)) { // IV is being reused for encryption: this violates security best practices. throw new IllegalStateException( "IV has already been used. Reusing IV in encryption mode violates security best" + " practices."); } KeymasterArguments keymasterInputArgs = new KeymasterArguments(); KeymasterArguments keymasterInputArgs = new KeymasterArguments(); keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mAlgorithm); keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mAlgorithm); Loading Loading @@ -234,6 +263,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry mOperationHandle = opResult.operationHandle; mOperationHandle = opResult.operationHandle; loadAlgorithmSpecificParametersFromBeginResult(keymasterOutputArgs); loadAlgorithmSpecificParametersFromBeginResult(keymasterOutputArgs); mFirstOperationInitiated = true; mFirstOperationInitiated = true; mIvHasBeenUsed = true; mMainDataStreamer = new KeyStoreCryptoOperationChunkedStreamer( mMainDataStreamer = new KeyStoreCryptoOperationChunkedStreamer( new KeyStoreCryptoOperationChunkedStreamer.MainDataStream( new KeyStoreCryptoOperationChunkedStreamer.MainDataStream( mKeyStore, opResult.token)); mKeyStore, opResult.token)); Loading Loading @@ -298,7 +328,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry } } } } reset(); resetWhilePreservingInitState(); return output; return output; } } Loading Loading @@ -376,7 +406,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry */ */ @Override @Override protected AlgorithmParameters engineGetParameters() { protected AlgorithmParameters engineGetParameters() { if (!mIvUsed) { if (!mIvRequired) { return null; return null; } } if ((mIv != null) && (mIv.length > 0)) { if ((mIv != null) && (mIv.length > 0)) { Loading Loading @@ -408,7 +438,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry */ */ protected void initAlgorithmSpecificParameters(AlgorithmParameterSpec params) protected void initAlgorithmSpecificParameters(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { throws InvalidAlgorithmParameterException { if (!mIvUsed) { if (!mIvRequired) { if (params != null) { if (params != null) { throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params); throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params); } } Loading Loading @@ -447,7 +477,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry */ */ protected void initAlgorithmSpecificParameters(AlgorithmParameters params) protected void initAlgorithmSpecificParameters(AlgorithmParameters params) throws InvalidAlgorithmParameterException { throws InvalidAlgorithmParameterException { if (!mIvUsed) { if (!mIvRequired) { if (params != null) { if (params != null) { throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params); throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params); } } Loading Loading @@ -492,7 +522,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry * and thus {@code Cipher.init} needs to be invoked with explicitly provided parameters. * and thus {@code Cipher.init} needs to be invoked with explicitly provided parameters. */ */ protected void initAlgorithmSpecificParameters() throws InvalidKeyException { protected void initAlgorithmSpecificParameters() throws InvalidKeyException { if (!mIvUsed) { if (!mIvRequired) { return; return; } } Loading @@ -515,7 +545,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry if (!mFirstOperationInitiated) { if (!mFirstOperationInitiated) { // First begin operation -- see if we need to provide additional entropy for IV // First begin operation -- see if we need to provide additional entropy for IV // generation. // generation. if (mIvUsed) { if (mIvRequired) { // IV is needed // IV is needed if ((mIv == null) && (mEncrypting)) { if ((mIv == null) && (mEncrypting)) { // TODO: Switch to keymaster-generated IV code below once keymaster supports // TODO: Switch to keymaster-generated IV code below once keymaster supports Loading @@ -534,7 +564,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry } } } } if ((mIvUsed) && (mIv != null)) { if ((mIvRequired) && (mIv != null)) { keymasterArgs.addBlob(KeymasterDefs.KM_TAG_NONCE, mIv); keymasterArgs.addBlob(KeymasterDefs.KM_TAG_NONCE, mIv); } } } } Loading @@ -557,7 +587,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry returnedIv = null; returnedIv = null; } } if (mIvUsed) { if (mIvRequired) { if (mIv == null) { if (mIv == null) { mIv = returnedIv; mIv = returnedIv; } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) { } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) { Loading Loading
keystore/java/android/security/KeyStoreCipherSpi.java +44 −14 Original line number Original line Diff line number Diff line Loading @@ -111,7 +111,9 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockMode; private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockMode; private final @KeyStoreKeyConstraints.PaddingEnum int mPadding; private final @KeyStoreKeyConstraints.PaddingEnum int mPadding; private final int mBlockSizeBytes; private final int mBlockSizeBytes; private final boolean mIvUsed; /** Whether this transformation requires an IV. */ private final boolean mIvRequired; // Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after // Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after // doFinal finishes. // doFinal finishes. Loading @@ -119,10 +121,13 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry private KeyStoreSecretKey mKey; private KeyStoreSecretKey mKey; private SecureRandom mRng; private SecureRandom mRng; private boolean mFirstOperationInitiated; private boolean mFirstOperationInitiated; byte[] mIv; private byte[] mIv; /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */ private boolean mIvHasBeenUsed; // Fields below must be reset // Fields below must be reset after doFinal private byte[] mAdditionalEntropyForBegin; private byte[] mAdditionalEntropyForBegin; /** /** * Token referencing this operation inside keystore service. It is initialized by * Token referencing this operation inside keystore service. It is initialized by * {@code engineInit} and is invalidated when {@code engineDoFinal} succeeds and one some * {@code engineInit} and is invalidated when {@code engineDoFinal} succeeds and one some Loading @@ -143,7 +148,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry mBlockMode = blockMode; mBlockMode = blockMode; mPadding = padding; mPadding = padding; mBlockSizeBytes = blockSizeBytes; mBlockSizeBytes = blockSizeBytes; mIvUsed = ivUsed; mIvRequired = ivUsed; } } @Override @Override Loading @@ -170,7 +175,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry } } private void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { private void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { reset(); resetAll(); if (!(key instanceof KeyStoreSecretKey)) { if (!(key instanceof KeyStoreSecretKey)) { throw new InvalidKeyException( throw new InvalidKeyException( "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null")); "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null")); Loading @@ -187,7 +192,25 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry mEncrypting = opmode == Cipher.ENCRYPT_MODE; mEncrypting = opmode == Cipher.ENCRYPT_MODE; } } private void reset() { private void resetAll() { IBinder operationToken = mOperationToken; if (operationToken != null) { mOperationToken = null; mKeyStore.abort(operationToken); } mEncrypting = false; mKey = null; mRng = null; mFirstOperationInitiated = false; mIv = null; mIvHasBeenUsed = false; mAdditionalEntropyForBegin = null; mOperationToken = null; mOperationHandle = null; mMainDataStreamer = null; } private void resetWhilePreservingInitState() { IBinder operationToken = mOperationToken; IBinder operationToken = mOperationToken; if (operationToken != null) { if (operationToken != null) { mOperationToken = null; mOperationToken = null; Loading @@ -205,6 +228,12 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry if (mKey == null) { if (mKey == null) { throw new IllegalStateException("Not initialized"); throw new IllegalStateException("Not initialized"); } } if ((mEncrypting) && (mIvRequired) && (mIvHasBeenUsed)) { // IV is being reused for encryption: this violates security best practices. throw new IllegalStateException( "IV has already been used. Reusing IV in encryption mode violates security best" + " practices."); } KeymasterArguments keymasterInputArgs = new KeymasterArguments(); KeymasterArguments keymasterInputArgs = new KeymasterArguments(); keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mAlgorithm); keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mAlgorithm); Loading Loading @@ -234,6 +263,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry mOperationHandle = opResult.operationHandle; mOperationHandle = opResult.operationHandle; loadAlgorithmSpecificParametersFromBeginResult(keymasterOutputArgs); loadAlgorithmSpecificParametersFromBeginResult(keymasterOutputArgs); mFirstOperationInitiated = true; mFirstOperationInitiated = true; mIvHasBeenUsed = true; mMainDataStreamer = new KeyStoreCryptoOperationChunkedStreamer( mMainDataStreamer = new KeyStoreCryptoOperationChunkedStreamer( new KeyStoreCryptoOperationChunkedStreamer.MainDataStream( new KeyStoreCryptoOperationChunkedStreamer.MainDataStream( mKeyStore, opResult.token)); mKeyStore, opResult.token)); Loading Loading @@ -298,7 +328,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry } } } } reset(); resetWhilePreservingInitState(); return output; return output; } } Loading Loading @@ -376,7 +406,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry */ */ @Override @Override protected AlgorithmParameters engineGetParameters() { protected AlgorithmParameters engineGetParameters() { if (!mIvUsed) { if (!mIvRequired) { return null; return null; } } if ((mIv != null) && (mIv.length > 0)) { if ((mIv != null) && (mIv.length > 0)) { Loading Loading @@ -408,7 +438,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry */ */ protected void initAlgorithmSpecificParameters(AlgorithmParameterSpec params) protected void initAlgorithmSpecificParameters(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { throws InvalidAlgorithmParameterException { if (!mIvUsed) { if (!mIvRequired) { if (params != null) { if (params != null) { throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params); throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params); } } Loading Loading @@ -447,7 +477,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry */ */ protected void initAlgorithmSpecificParameters(AlgorithmParameters params) protected void initAlgorithmSpecificParameters(AlgorithmParameters params) throws InvalidAlgorithmParameterException { throws InvalidAlgorithmParameterException { if (!mIvUsed) { if (!mIvRequired) { if (params != null) { if (params != null) { throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params); throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params); } } Loading Loading @@ -492,7 +522,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry * and thus {@code Cipher.init} needs to be invoked with explicitly provided parameters. * and thus {@code Cipher.init} needs to be invoked with explicitly provided parameters. */ */ protected void initAlgorithmSpecificParameters() throws InvalidKeyException { protected void initAlgorithmSpecificParameters() throws InvalidKeyException { if (!mIvUsed) { if (!mIvRequired) { return; return; } } Loading @@ -515,7 +545,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry if (!mFirstOperationInitiated) { if (!mFirstOperationInitiated) { // First begin operation -- see if we need to provide additional entropy for IV // First begin operation -- see if we need to provide additional entropy for IV // generation. // generation. if (mIvUsed) { if (mIvRequired) { // IV is needed // IV is needed if ((mIv == null) && (mEncrypting)) { if ((mIv == null) && (mEncrypting)) { // TODO: Switch to keymaster-generated IV code below once keymaster supports // TODO: Switch to keymaster-generated IV code below once keymaster supports Loading @@ -534,7 +564,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry } } } } if ((mIvUsed) && (mIv != null)) { if ((mIvRequired) && (mIv != null)) { keymasterArgs.addBlob(KeymasterDefs.KM_TAG_NONCE, mIv); keymasterArgs.addBlob(KeymasterDefs.KM_TAG_NONCE, mIv); } } } } Loading @@ -557,7 +587,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry returnedIv = null; returnedIv = null; } } if (mIvUsed) { if (mIvRequired) { if (mIv == null) { if (mIv == null) { mIv = returnedIv; mIv = returnedIv; } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) { } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) { Loading