am c48e8cf0: am edd0e6c0: Merge "Refuse to reuse IV in encryption mode in AndroidKeyStore."

* commit 'c48e8cf07a180e185948673579828d064e6efc7a':
  Refuse to reuse IV in encryption mode in AndroidKeyStore.
This commit is contained in:
Alex Klyubin
2015-04-08 22:03:51 +00:00
committed by Android Git Automerger

View File

@@ -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.
@@ -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
@@ -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
@@ -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"));
@@ -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;
@@ -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);
@@ -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));
@@ -298,7 +328,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
} }
} }
reset(); resetWhilePreservingInitState();
return output; return output;
} }
@@ -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)) {
@@ -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);
} }
@@ -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);
} }
@@ -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;
} }
@@ -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
@@ -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);
} }
} }
@@ -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))) {