Merge "Make NONEwithECDSA truncate input when necessary." into mnc-dev
This commit is contained in:
@@ -363,8 +363,9 @@ abstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreC
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
|
public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
|
||||||
byte[] additionalEntropy) throws KeyStoreException {
|
byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
|
||||||
byte[] output = mDelegate.doFinal(input, inputOffset, inputLength, additionalEntropy);
|
byte[] output = mDelegate.doFinal(input, inputOffset, inputLength, signature,
|
||||||
|
additionalEntropy);
|
||||||
if (output != null) {
|
if (output != null) {
|
||||||
try {
|
try {
|
||||||
mBufferedOutput.write(output);
|
mBufferedOutput.write(output);
|
||||||
@@ -425,7 +426,7 @@ abstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreC
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OperationResult finish(byte[] additionalEntropy) {
|
public OperationResult finish(byte[] signature, byte[] additionalEntropy) {
|
||||||
if ((additionalEntropy != null) && (additionalEntropy.length > 0)) {
|
if ((additionalEntropy != null) && (additionalEntropy.length > 0)) {
|
||||||
throw new ProviderException("AAD stream does not support additional entropy");
|
throw new ProviderException("AAD stream does not support additional entropy");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -353,6 +353,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor
|
|||||||
try {
|
try {
|
||||||
output = mAdditionalAuthenticationDataStreamer.doFinal(
|
output = mAdditionalAuthenticationDataStreamer.doFinal(
|
||||||
EmptyArray.BYTE, 0, 0,
|
EmptyArray.BYTE, 0, 0,
|
||||||
|
null, // no signature
|
||||||
null // no additional entropy needed flushing AAD
|
null // no additional entropy needed flushing AAD
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -469,7 +470,10 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor
|
|||||||
byte[] additionalEntropy =
|
byte[] additionalEntropy =
|
||||||
KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
|
KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
|
||||||
mRng, getAdditionalEntropyAmountForFinish());
|
mRng, getAdditionalEntropyAmountForFinish());
|
||||||
output = mMainDataStreamer.doFinal(input, inputOffset, inputLen, additionalEntropy);
|
output = mMainDataStreamer.doFinal(
|
||||||
|
input, inputOffset, inputLen,
|
||||||
|
null, // no signature involved
|
||||||
|
additionalEntropy);
|
||||||
} catch (KeyStoreException e) {
|
} catch (KeyStoreException e) {
|
||||||
switch (e.getErrorCode()) {
|
switch (e.getErrorCode()) {
|
||||||
case KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH:
|
case KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH:
|
||||||
|
|||||||
@@ -17,11 +17,16 @@
|
|||||||
package android.security.keystore;
|
package android.security.keystore;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
|
import android.os.IBinder;
|
||||||
import android.security.KeyStore;
|
import android.security.KeyStore;
|
||||||
|
import android.security.KeyStoreException;
|
||||||
import android.security.keymaster.KeyCharacteristics;
|
import android.security.keymaster.KeyCharacteristics;
|
||||||
import android.security.keymaster.KeymasterArguments;
|
import android.security.keymaster.KeymasterArguments;
|
||||||
import android.security.keymaster.KeymasterDefs;
|
import android.security.keymaster.KeymasterDefs;
|
||||||
|
|
||||||
|
import libcore.util.EmptyArray;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.SignatureSpi;
|
import java.security.SignatureSpi;
|
||||||
|
|
||||||
@@ -36,6 +41,71 @@ abstract class AndroidKeyStoreECDSASignatureSpi extends AndroidKeyStoreSignature
|
|||||||
public NONE() {
|
public NONE() {
|
||||||
super(KeymasterDefs.KM_DIGEST_NONE);
|
super(KeymasterDefs.KM_DIGEST_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected KeyStoreCryptoOperationStreamer createMainDataStreamer(KeyStore keyStore,
|
||||||
|
IBinder operationToken) {
|
||||||
|
return new TruncateToFieldSizeMessageStreamer(
|
||||||
|
super.createMainDataStreamer(keyStore, operationToken),
|
||||||
|
getGroupSizeBits());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Streamer which buffers all input, then truncates it to field size, and then sends it into
|
||||||
|
* KeyStore via the provided delegate streamer.
|
||||||
|
*/
|
||||||
|
private static class TruncateToFieldSizeMessageStreamer
|
||||||
|
implements KeyStoreCryptoOperationStreamer {
|
||||||
|
|
||||||
|
private final KeyStoreCryptoOperationStreamer mDelegate;
|
||||||
|
private final int mGroupSizeBits;
|
||||||
|
private final ByteArrayOutputStream mInputBuffer = new ByteArrayOutputStream();
|
||||||
|
private long mConsumedInputSizeBytes;
|
||||||
|
|
||||||
|
private TruncateToFieldSizeMessageStreamer(
|
||||||
|
KeyStoreCryptoOperationStreamer delegate,
|
||||||
|
int groupSizeBits) {
|
||||||
|
mDelegate = delegate;
|
||||||
|
mGroupSizeBits = groupSizeBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] update(byte[] input, int inputOffset, int inputLength)
|
||||||
|
throws KeyStoreException {
|
||||||
|
if (inputLength > 0) {
|
||||||
|
mInputBuffer.write(input, inputOffset, inputLength);
|
||||||
|
mConsumedInputSizeBytes += inputLength;
|
||||||
|
}
|
||||||
|
return EmptyArray.BYTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] signature,
|
||||||
|
byte[] additionalEntropy) throws KeyStoreException {
|
||||||
|
if (inputLength > 0) {
|
||||||
|
mConsumedInputSizeBytes += inputLength;
|
||||||
|
mInputBuffer.write(input, inputOffset, inputLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] bufferedInput = mInputBuffer.toByteArray();
|
||||||
|
mInputBuffer.reset();
|
||||||
|
// Truncate input at field size (bytes)
|
||||||
|
return mDelegate.doFinal(bufferedInput,
|
||||||
|
0,
|
||||||
|
Math.min(bufferedInput.length, ((mGroupSizeBits + 7) / 8)),
|
||||||
|
signature, additionalEntropy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getConsumedInputSizeBytes() {
|
||||||
|
return mConsumedInputSizeBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getProducedOutputSizeBytes() {
|
||||||
|
return mDelegate.getProducedOutputSizeBytes();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final static class SHA1 extends AndroidKeyStoreECDSASignatureSpi {
|
public final static class SHA1 extends AndroidKeyStoreECDSASignatureSpi {
|
||||||
@@ -70,7 +140,7 @@ abstract class AndroidKeyStoreECDSASignatureSpi extends AndroidKeyStoreSignature
|
|||||||
|
|
||||||
private final int mKeymasterDigest;
|
private final int mKeymasterDigest;
|
||||||
|
|
||||||
private int mGroupSizeBytes = -1;
|
private int mGroupSizeBits = -1;
|
||||||
|
|
||||||
AndroidKeyStoreECDSASignatureSpi(int keymasterDigest) {
|
AndroidKeyStoreECDSASignatureSpi(int keymasterDigest) {
|
||||||
mKeymasterDigest = keymasterDigest;
|
mKeymasterDigest = keymasterDigest;
|
||||||
@@ -95,14 +165,14 @@ abstract class AndroidKeyStoreECDSASignatureSpi extends AndroidKeyStoreSignature
|
|||||||
} else if (keySizeBits > Integer.MAX_VALUE) {
|
} else if (keySizeBits > Integer.MAX_VALUE) {
|
||||||
throw new InvalidKeyException("Key too large: " + keySizeBits + " bits");
|
throw new InvalidKeyException("Key too large: " + keySizeBits + " bits");
|
||||||
}
|
}
|
||||||
mGroupSizeBytes = (int) ((keySizeBits + 7) / 8);
|
mGroupSizeBits = (int) keySizeBits;
|
||||||
|
|
||||||
super.initKey(key);
|
super.initKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final void resetAll() {
|
protected final void resetAll() {
|
||||||
mGroupSizeBytes = -1;
|
mGroupSizeBits = -1;
|
||||||
super.resetAll();
|
super.resetAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,14 +182,21 @@ abstract class AndroidKeyStoreECDSASignatureSpi extends AndroidKeyStoreSignature
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addAlgorithmSpecificParametersToBegin(
|
protected final void addAlgorithmSpecificParametersToBegin(
|
||||||
@NonNull KeymasterArguments keymasterArgs) {
|
@NonNull KeymasterArguments keymasterArgs) {
|
||||||
keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_EC);
|
keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_EC);
|
||||||
keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
|
keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getAdditionalEntropyAmountForSign() {
|
protected final int getAdditionalEntropyAmountForSign() {
|
||||||
return mGroupSizeBytes;
|
return (mGroupSizeBits + 7) / 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final int getGroupSizeBits() {
|
||||||
|
if (mGroupSizeBits == -1) {
|
||||||
|
throw new IllegalStateException("Not initialized");
|
||||||
|
}
|
||||||
|
return mGroupSizeBits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,6 +234,7 @@ public abstract class AndroidKeyStoreHmacSpi extends MacSpi implements KeyStoreC
|
|||||||
try {
|
try {
|
||||||
result = mChunkedStreamer.doFinal(
|
result = mChunkedStreamer.doFinal(
|
||||||
null, 0, 0,
|
null, 0, 0,
|
||||||
|
null, // no signature provided -- this invocation will generate one
|
||||||
null // no additional entropy needed -- HMAC is deterministic
|
null // no additional entropy needed -- HMAC is deterministic
|
||||||
);
|
);
|
||||||
} catch (KeyStoreException e) {
|
} catch (KeyStoreException e) {
|
||||||
|
|||||||
@@ -150,8 +150,7 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
|
public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
|
||||||
byte[] additionalEntropy)
|
byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
|
||||||
throws KeyStoreException {
|
|
||||||
if (inputLength > 0) {
|
if (inputLength > 0) {
|
||||||
mConsumedInputSizeBytes += inputLength;
|
mConsumedInputSizeBytes += inputLength;
|
||||||
mInputBuffer.write(input, inputOffset, inputLength);
|
mInputBuffer.write(input, inputOffset, inputLength);
|
||||||
@@ -174,7 +173,8 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
|
|||||||
"Message size (" + bufferedInput.length + " bytes) must be smaller than"
|
"Message size (" + bufferedInput.length + " bytes) must be smaller than"
|
||||||
+ " modulus (" + mModulusSizeBytes + " bytes)");
|
+ " modulus (" + mModulusSizeBytes + " bytes)");
|
||||||
}
|
}
|
||||||
return mDelegate.doFinal(paddedInput, 0, paddedInput.length, additionalEntropy);
|
return mDelegate.doFinal(paddedInput, 0, paddedInput.length, signature,
|
||||||
|
additionalEntropy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ abstract class AndroidKeyStoreSignatureSpiBase extends SignatureSpi
|
|||||||
*/
|
*/
|
||||||
private IBinder mOperationToken;
|
private IBinder mOperationToken;
|
||||||
private long mOperationHandle;
|
private long mOperationHandle;
|
||||||
private KeyStoreCryptoOperationChunkedStreamer mMessageStreamer;
|
private KeyStoreCryptoOperationStreamer mMessageStreamer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encountered exception which could not be immediately thrown because it was encountered inside
|
* Encountered exception which could not be immediately thrown because it was encountered inside
|
||||||
@@ -229,9 +229,20 @@ abstract class AndroidKeyStoreSignatureSpiBase extends SignatureSpi
|
|||||||
throw new ProviderException("Keystore returned invalid operation handle");
|
throw new ProviderException("Keystore returned invalid operation handle");
|
||||||
}
|
}
|
||||||
|
|
||||||
mMessageStreamer = new KeyStoreCryptoOperationChunkedStreamer(
|
mMessageStreamer = createMainDataStreamer(mKeyStore, opResult.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a streamer which sends the message to be signed/verified into the provided KeyStore
|
||||||
|
*
|
||||||
|
* <p>This implementation returns a working streamer.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
|
||||||
|
KeyStore keyStore, IBinder operationToken) {
|
||||||
|
return new KeyStoreCryptoOperationChunkedStreamer(
|
||||||
new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
|
new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
|
||||||
mKeyStore, opResult.token));
|
keyStore, operationToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -314,7 +325,10 @@ abstract class AndroidKeyStoreSignatureSpiBase extends SignatureSpi
|
|||||||
byte[] additionalEntropy =
|
byte[] additionalEntropy =
|
||||||
KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
|
KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
|
||||||
appRandom, getAdditionalEntropyAmountForSign());
|
appRandom, getAdditionalEntropyAmountForSign());
|
||||||
signature = mMessageStreamer.doFinal(EmptyArray.BYTE, 0, 0, additionalEntropy);
|
signature = mMessageStreamer.doFinal(
|
||||||
|
EmptyArray.BYTE, 0, 0,
|
||||||
|
null, // no signature provided -- it'll be generated by this invocation
|
||||||
|
additionalEntropy);
|
||||||
} catch (InvalidKeyException | KeyStoreException e) {
|
} catch (InvalidKeyException | KeyStoreException e) {
|
||||||
throw new SignatureException(e);
|
throw new SignatureException(e);
|
||||||
}
|
}
|
||||||
@@ -329,31 +343,37 @@ abstract class AndroidKeyStoreSignatureSpiBase extends SignatureSpi
|
|||||||
throw new SignatureException(mCachedException);
|
throw new SignatureException(mCachedException);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean result;
|
|
||||||
try {
|
try {
|
||||||
ensureKeystoreOperationInitialized();
|
ensureKeystoreOperationInitialized();
|
||||||
mMessageStreamer.flush();
|
} catch (InvalidKeyException e) {
|
||||||
OperationResult opResult = mKeyStore.finish(mOperationToken, null, signature);
|
|
||||||
if (opResult == null) {
|
|
||||||
throw new KeyStoreConnectException();
|
|
||||||
}
|
|
||||||
switch (opResult.resultCode) {
|
|
||||||
case KeyStore.NO_ERROR:
|
|
||||||
result = true;
|
|
||||||
break;
|
|
||||||
case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
|
|
||||||
result = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new SignatureException(
|
|
||||||
KeyStore.getKeyStoreException(opResult.resultCode));
|
|
||||||
}
|
|
||||||
} catch (InvalidKeyException | KeyStoreException e) {
|
|
||||||
throw new SignatureException(e);
|
throw new SignatureException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean verified;
|
||||||
|
try {
|
||||||
|
byte[] output = mMessageStreamer.doFinal(
|
||||||
|
EmptyArray.BYTE, 0, 0,
|
||||||
|
signature,
|
||||||
|
null // no additional entropy needed -- verification is deterministic
|
||||||
|
);
|
||||||
|
if (output.length != 0) {
|
||||||
|
throw new ProviderException(
|
||||||
|
"Signature verification unexpected produced output: " + output.length
|
||||||
|
+ " bytes");
|
||||||
|
}
|
||||||
|
verified = true;
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
switch (e.getErrorCode()) {
|
||||||
|
case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
|
||||||
|
verified = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new SignatureException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resetWhilePreservingInitState();
|
resetWhilePreservingInitState();
|
||||||
return result;
|
return verified;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ import java.io.IOException;
|
|||||||
* amount of data in one go because the operations are marshalled via Binder. Secondly, the update
|
* amount of data in one go because the operations are marshalled via Binder. Secondly, the update
|
||||||
* operation may consume less data than provided, in which case the caller has to buffer the
|
* operation may consume less data than provided, in which case the caller has to buffer the
|
||||||
* remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
|
* remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
|
||||||
* {@link #doFinal(byte[], int, int, byte[]) doFinal} operations which can be used to conveniently
|
* {@link #doFinal(byte[], int, int, byte[], byte[]) doFinal} operations which can be used to
|
||||||
* implement various JCA crypto primitives.
|
* conveniently implement various JCA crypto primitives.
|
||||||
*
|
*
|
||||||
* <p>Bidirectional chunked streaming of data via a KeyStore crypto operation is abstracted away as
|
* <p>Bidirectional chunked streaming of data via a KeyStore crypto operation is abstracted away as
|
||||||
* a {@link Stream} to avoid having this class deal with operation tokens and occasional additional
|
* a {@link Stream} to avoid having this class deal with operation tokens and occasional additional
|
||||||
@@ -60,7 +60,7 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
|
|||||||
* Returns the result of the KeyStore {@code finish} operation or null if keystore couldn't
|
* Returns the result of the KeyStore {@code finish} operation or null if keystore couldn't
|
||||||
* be reached.
|
* be reached.
|
||||||
*/
|
*/
|
||||||
OperationResult finish(byte[] additionalEntropy);
|
OperationResult finish(byte[] siganture, byte[] additionalEntropy);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Binder buffer is about 1MB, but it's shared between all active transactions of the process.
|
// Binder buffer is about 1MB, but it's shared between all active transactions of the process.
|
||||||
@@ -201,8 +201,8 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] additionalEntropy)
|
public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
|
||||||
throws KeyStoreException {
|
byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
|
||||||
if (inputLength == 0) {
|
if (inputLength == 0) {
|
||||||
// No input provided -- simplify the rest of the code
|
// No input provided -- simplify the rest of the code
|
||||||
input = EmptyArray.BYTE;
|
input = EmptyArray.BYTE;
|
||||||
@@ -213,7 +213,7 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
|
|||||||
byte[] output = update(input, inputOffset, inputLength);
|
byte[] output = update(input, inputOffset, inputLength);
|
||||||
output = ArrayUtils.concat(output, flush());
|
output = ArrayUtils.concat(output, flush());
|
||||||
|
|
||||||
OperationResult opResult = mKeyStoreStream.finish(additionalEntropy);
|
OperationResult opResult = mKeyStoreStream.finish(signature, additionalEntropy);
|
||||||
if (opResult == null) {
|
if (opResult == null) {
|
||||||
throw new KeyStoreConnectException();
|
throw new KeyStoreConnectException();
|
||||||
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
|
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
|
||||||
@@ -286,8 +286,8 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OperationResult finish(byte[] additionalEntropy) {
|
public OperationResult finish(byte[] signature, byte[] additionalEntropy) {
|
||||||
return mKeyStore.finish(mOperationToken, null, null, additionalEntropy);
|
return mKeyStore.finish(mOperationToken, null, signature, additionalEntropy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,15 +28,15 @@ import android.security.KeyStoreException;
|
|||||||
* amount of data in one go because the operations are marshalled via Binder. Secondly, the update
|
* amount of data in one go because the operations are marshalled via Binder. Secondly, the update
|
||||||
* operation may consume less data than provided, in which case the caller has to buffer the
|
* operation may consume less data than provided, in which case the caller has to buffer the
|
||||||
* remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
|
* remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
|
||||||
* {@link #doFinal(byte[], int, int, byte[]) doFinal} operations which can be used to conveniently
|
* {@link #doFinal(byte[], int, int, byte[], byte[]) doFinal} operations which can be used to
|
||||||
* implement various JCA crypto primitives.
|
* conveniently implement various JCA crypto primitives.
|
||||||
*
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
interface KeyStoreCryptoOperationStreamer {
|
interface KeyStoreCryptoOperationStreamer {
|
||||||
byte[] update(byte[] input, int inputOffset, int inputLength) throws KeyStoreException;
|
byte[] update(byte[] input, int inputOffset, int inputLength) throws KeyStoreException;
|
||||||
byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] additionalEntropy)
|
byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] signature,
|
||||||
throws KeyStoreException;
|
byte[] additionalEntropy) throws KeyStoreException;
|
||||||
long getConsumedInputSizeBytes();
|
long getConsumedInputSizeBytes();
|
||||||
long getProducedOutputSizeBytes();
|
long getProducedOutputSizeBytes();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user