* commit 'c48e8cf07a180e185948673579828d064e6efc7a': Refuse to reuse IV in encryption mode in AndroidKeyStore.
This commit is contained in:
@@ -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))) {
|
||||||
|
|||||||
Reference in New Issue
Block a user