100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin/* 200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * Copyright (C) 2015 The Android Open Source Project 300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * 400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * Licensed under the Apache License, Version 2.0 (the "License"); 500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * you may not use this file except in compliance with the License. 600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * You may obtain a copy of the License at 700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * 800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * http://www.apache.org/licenses/LICENSE-2.0 900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * 1000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * Unless required by applicable law or agreed to in writing, software 1100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * distributed under the License is distributed on an "AS IS" BASIS, 1200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * See the License for the specific language governing permissions and 1400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * limitations under the License. 1500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin */ 1600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 1700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinpackage android.security.keystore; 1800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 1900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport android.annotation.NonNull; 2000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport android.annotation.Nullable; 2100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport android.os.IBinder; 2200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport android.security.KeyStore; 2300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport android.security.KeyStoreException; 2400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport android.security.keymaster.KeymasterArguments; 2500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport android.security.keymaster.KeymasterDefs; 2600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport android.security.keymaster.OperationResult; 2700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.Stream; 2800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 2900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport libcore.util.EmptyArray; 3000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 3100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport java.io.ByteArrayOutputStream; 3200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport java.io.IOException; 3300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport java.security.AlgorithmParameters; 3400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport java.security.InvalidAlgorithmParameterException; 3500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport java.security.InvalidKeyException; 3600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport java.security.Key; 3700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport java.security.NoSuchAlgorithmException; 3800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport java.security.ProviderException; 3900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport java.security.spec.AlgorithmParameterSpec; 4000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport java.security.spec.InvalidParameterSpecException; 4100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport java.util.Arrays; 4200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 4300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport javax.crypto.CipherSpi; 4400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinimport javax.crypto.spec.GCMParameterSpec; 4500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 4600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin/** 4700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * Base class for Android Keystore authenticated AES {@link CipherSpi} implementations. 4800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * 4900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * @hide 5000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin */ 5100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubinabstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase { 5200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 5300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin abstract static class GCM extends AndroidKeyStoreAuthenticatedAESCipherSpi { 54a95550f8016bbb0dba086dbd73eec63e6cdbbe98Alex Klyubin static final int MIN_SUPPORTED_TAG_LENGTH_BITS = 96; 5500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private static final int MAX_SUPPORTED_TAG_LENGTH_BITS = 128; 5600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private static final int DEFAULT_TAG_LENGTH_BITS = 128; 5700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private static final int IV_LENGTH_BYTES = 12; 5800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 5900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private int mTagLengthBits = DEFAULT_TAG_LENGTH_BITS; 6000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 6100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin GCM(int keymasterPadding) { 6200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin super(KeymasterDefs.KM_MODE_GCM, keymasterPadding); 6300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 6400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 6500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 6600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final void resetAll() { 6700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mTagLengthBits = DEFAULT_TAG_LENGTH_BITS; 6800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin super.resetAll(); 6900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 7000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 7100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 7200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final void resetWhilePreservingInitState() { 7300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin super.resetWhilePreservingInitState(); 7400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 7500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 7600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 7700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final void initAlgorithmSpecificParameters() throws InvalidKeyException { 7800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (!isEncrypting()) { 7900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new InvalidKeyException("IV required when decrypting" 8000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin + ". Use IvParameterSpec or AlgorithmParameters to provide it."); 8100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 8200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 8300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 8400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 8500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final void initAlgorithmSpecificParameters(AlgorithmParameterSpec params) 8600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throws InvalidAlgorithmParameterException { 8700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin // IV is used 8800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (params == null) { 8900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (!isEncrypting()) { 9000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin // IV must be provided by the caller 9100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new InvalidAlgorithmParameterException( 9200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin "GCMParameterSpec must be provided when decrypting"); 9300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 9400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return; 9500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 9600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (!(params instanceof GCMParameterSpec)) { 9700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new InvalidAlgorithmParameterException("Only GCMParameterSpec supported"); 9800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 9900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin GCMParameterSpec spec = (GCMParameterSpec) params; 10000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin byte[] iv = spec.getIV(); 10100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (iv == null) { 10200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new InvalidAlgorithmParameterException("Null IV in GCMParameterSpec"); 10300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } else if (iv.length != IV_LENGTH_BYTES) { 10400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new InvalidAlgorithmParameterException("Unsupported IV length: " 10500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin + iv.length + " bytes. Only " + IV_LENGTH_BYTES 10600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin + " bytes long IV supported"); 10700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 10800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin int tagLengthBits = spec.getTLen(); 10900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if ((tagLengthBits < MIN_SUPPORTED_TAG_LENGTH_BITS) 11000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin || (tagLengthBits > MAX_SUPPORTED_TAG_LENGTH_BITS) 11100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin || ((tagLengthBits % 8) != 0)) { 11200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new InvalidAlgorithmParameterException( 11300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin "Unsupported tag length: " + tagLengthBits + " bits" 11400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin + ". Supported lengths: 96, 104, 112, 120, 128"); 11500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 11600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin setIv(iv); 11700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mTagLengthBits = tagLengthBits; 11800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 11900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 12000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 12100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final void initAlgorithmSpecificParameters(AlgorithmParameters params) 12200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throws InvalidAlgorithmParameterException { 12300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (params == null) { 12400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (!isEncrypting()) { 12500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin // IV must be provided by the caller 12600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new InvalidAlgorithmParameterException("IV required when decrypting" 12700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin + ". Use GCMParameterSpec or GCM AlgorithmParameters to provide it."); 12800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 12900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return; 13000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 13100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 1325c38e7918aea36ee8f516793d5641b05a8de710eAlex Klyubin if (!"GCM".equalsIgnoreCase(params.getAlgorithm())) { 1335c38e7918aea36ee8f516793d5641b05a8de710eAlex Klyubin throw new InvalidAlgorithmParameterException( 1345c38e7918aea36ee8f516793d5641b05a8de710eAlex Klyubin "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm() 1355c38e7918aea36ee8f516793d5641b05a8de710eAlex Klyubin + ". Supported: GCM"); 1365c38e7918aea36ee8f516793d5641b05a8de710eAlex Klyubin } 1375c38e7918aea36ee8f516793d5641b05a8de710eAlex Klyubin 13800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin GCMParameterSpec spec; 13900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin try { 14000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin spec = params.getParameterSpec(GCMParameterSpec.class); 14100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } catch (InvalidParameterSpecException e) { 14200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (!isEncrypting()) { 14300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin // IV must be provided by the caller 14400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new InvalidAlgorithmParameterException("IV and tag length required when" 14500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin + " decrypting, but not found in parameters: " + params, e); 14600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 14700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin setIv(null); 14800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return; 14900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 15000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin initAlgorithmSpecificParameters(spec); 15100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 15200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 15300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Nullable 15400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 15500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final AlgorithmParameters engineGetParameters() { 15600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin byte[] iv = getIv(); 15700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if ((iv != null) && (iv.length > 0)) { 15800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin try { 15900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin AlgorithmParameters params = AlgorithmParameters.getInstance("GCM"); 16000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin params.init(new GCMParameterSpec(mTagLengthBits, iv)); 16100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return params; 16200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } catch (NoSuchAlgorithmException e) { 16300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new ProviderException( 16400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin "Failed to obtain GCM AlgorithmParameters", e); 16500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } catch (InvalidParameterSpecException e) { 16600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new ProviderException( 16700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin "Failed to initialize GCM AlgorithmParameters", e); 16800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 16900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 17000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return null; 17100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 17200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 17300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @NonNull 17400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 17500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected KeyStoreCryptoOperationStreamer createMainDataStreamer( 17600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin KeyStore keyStore, IBinder operationToken) { 17700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin KeyStoreCryptoOperationStreamer streamer = new KeyStoreCryptoOperationChunkedStreamer( 17800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin new KeyStoreCryptoOperationChunkedStreamer.MainDataStream( 17900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin keyStore, operationToken)); 18000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (isEncrypting()) { 18100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return streamer; 18200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } else { 18300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin // When decrypting, to avoid leaking unauthenticated plaintext, do not return any 18400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin // plaintext before ciphertext is authenticated by KeyStore.finish. 18500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return new BufferAllOutputUntilDoFinalStreamer(streamer); 18600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 18700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 18800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 18900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @NonNull 19000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 19100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final KeyStoreCryptoOperationStreamer createAdditionalAuthenticationDataStreamer( 19200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin KeyStore keyStore, IBinder operationToken) { 19300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return new KeyStoreCryptoOperationChunkedStreamer( 19400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin new AdditionalAuthenticationDataStream(keyStore, operationToken)); 19500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 19600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 19700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 19800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final int getAdditionalEntropyAmountForBegin() { 19900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if ((getIv() == null) && (isEncrypting())) { 20000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin // IV will need to be generated 20100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return IV_LENGTH_BYTES; 20200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 20300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 20400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return 0; 20500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 20600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 20700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 20800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final int getAdditionalEntropyAmountForFinish() { 20900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return 0; 21000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 21100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 21200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 21300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final void addAlgorithmSpecificParametersToBegin( 21400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @NonNull KeymasterArguments keymasterArgs) { 21500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin super.addAlgorithmSpecificParametersToBegin(keymasterArgs); 216ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin keymasterArgs.addUnsignedInt(KeymasterDefs.KM_TAG_MAC_LENGTH, mTagLengthBits); 21700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 21800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 21900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final int getTagLengthBits() { 22000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return mTagLengthBits; 22100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 22200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 22300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin public static final class NoPadding extends GCM { 22400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin public NoPadding() { 22500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin super(KeymasterDefs.KM_PAD_NONE); 22600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 22700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 22800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 22900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final int engineGetOutputSize(int inputLen) { 23000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin int tagLengthBytes = (getTagLengthBits() + 7) / 8; 23100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin long result; 23200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (isEncrypting()) { 23300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin result = getConsumedInputSizeBytes() - getProducedOutputSizeBytes() + inputLen 23400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin + tagLengthBytes; 23500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } else { 23600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin result = getConsumedInputSizeBytes() - getProducedOutputSizeBytes() + inputLen 23700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin - tagLengthBytes; 23800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 23900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (result < 0) { 24000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return 0; 24100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } else if (result > Integer.MAX_VALUE) { 24200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return Integer.MAX_VALUE; 24300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 24400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return (int) result; 24500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 24600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 24700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 24800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 24900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private static final int BLOCK_SIZE_BYTES = 16; 25000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 25100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private final int mKeymasterBlockMode; 25200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private final int mKeymasterPadding; 25300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 25400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private byte[] mIv; 25500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 25600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */ 25700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private boolean mIvHasBeenUsed; 25800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 25900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin AndroidKeyStoreAuthenticatedAESCipherSpi( 26000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin int keymasterBlockMode, 26100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin int keymasterPadding) { 26200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mKeymasterBlockMode = keymasterBlockMode; 26300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mKeymasterPadding = keymasterPadding; 26400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 26500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 26600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 26700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected void resetAll() { 26800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mIv = null; 26900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mIvHasBeenUsed = false; 27000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin super.resetAll(); 27100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 27200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 27300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 27400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final void initKey(int opmode, Key key) throws InvalidKeyException { 27500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (!(key instanceof AndroidKeyStoreSecretKey)) { 27600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new InvalidKeyException( 27700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null")); 27800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 27900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (!KeyProperties.KEY_ALGORITHM_AES.equalsIgnoreCase(key.getAlgorithm())) { 28000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new InvalidKeyException( 28100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin "Unsupported key algorithm: " + key.getAlgorithm() + ". Only " + 28200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin KeyProperties.KEY_ALGORITHM_AES + " supported"); 28300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 28400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin setKey((AndroidKeyStoreSecretKey) key); 28500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 28600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 28700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 28800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected void addAlgorithmSpecificParametersToBegin( 28900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @NonNull KeymasterArguments keymasterArgs) { 29000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if ((isEncrypting()) && (mIvHasBeenUsed)) { 29100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin // IV is being reused for encryption: this violates security best practices. 29200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new IllegalStateException( 29300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin "IV has already been used. Reusing IV in encryption mode violates security best" 29400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin + " practices."); 29500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 29600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 297ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES); 298ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin keymasterArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode); 299ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding); 30000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (mIv != null) { 301ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin keymasterArgs.addBytes(KeymasterDefs.KM_TAG_NONCE, mIv); 30200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 30300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 30400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 30500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 30600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final void loadAlgorithmSpecificParametersFromBeginResult( 30700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @NonNull KeymasterArguments keymasterArgs) { 30800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mIvHasBeenUsed = true; 30900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 31000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin // NOTE: Keymaster doesn't always return an IV, even if it's used. 311ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin byte[] returnedIv = keymasterArgs.getBytes(KeymasterDefs.KM_TAG_NONCE, null); 31200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if ((returnedIv != null) && (returnedIv.length == 0)) { 31300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin returnedIv = null; 31400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 31500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 31600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (mIv == null) { 31700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mIv = returnedIv; 31800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) { 31900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new ProviderException("IV in use differs from provided IV"); 32000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 32100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 32200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 32300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 32400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final int engineGetBlockSize() { 32500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return BLOCK_SIZE_BYTES; 32600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 32700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 32800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 32900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected final byte[] engineGetIV() { 33000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return ArrayUtils.cloneIfNotEmpty(mIv); 33100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 33200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 33300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected void setIv(byte[] iv) { 33400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mIv = iv; 33500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 33600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 33700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin protected byte[] getIv() { 33800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return mIv; 33900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 34000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 34100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin /** 34200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * {@link KeyStoreCryptoOperationStreamer} which buffers all output until {@code doFinal} from 34300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * which it returns all output in one go, provided {@code doFinal} succeeds. 34400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin */ 34500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private static class BufferAllOutputUntilDoFinalStreamer 34600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin implements KeyStoreCryptoOperationStreamer { 34700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 34800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private final KeyStoreCryptoOperationStreamer mDelegate; 34900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private ByteArrayOutputStream mBufferedOutput = new ByteArrayOutputStream(); 35000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private long mProducedOutputSizeBytes; 35100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 35200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private BufferAllOutputUntilDoFinalStreamer(KeyStoreCryptoOperationStreamer delegate) { 35300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mDelegate = delegate; 35400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 35500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 35600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 35700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin public byte[] update(byte[] input, int inputOffset, int inputLength) 35800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throws KeyStoreException { 35900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin byte[] output = mDelegate.update(input, inputOffset, inputLength); 36000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (output != null) { 36100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin try { 36200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mBufferedOutput.write(output); 36300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } catch (IOException e) { 36400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new ProviderException("Failed to buffer output", e); 36500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 36600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 36700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return EmptyArray.BYTE; 36800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 36900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 37000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 37100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin public byte[] doFinal(byte[] input, int inputOffset, int inputLength, 372d23dc502b0a1952887d4453cba98aa2e3d2f5009Alex Klyubin byte[] signature, byte[] additionalEntropy) throws KeyStoreException { 373d23dc502b0a1952887d4453cba98aa2e3d2f5009Alex Klyubin byte[] output = mDelegate.doFinal(input, inputOffset, inputLength, signature, 374d23dc502b0a1952887d4453cba98aa2e3d2f5009Alex Klyubin additionalEntropy); 37500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (output != null) { 37600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin try { 37700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mBufferedOutput.write(output); 37800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } catch (IOException e) { 37900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new ProviderException("Failed to buffer output", e); 38000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 38100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 38200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin byte[] result = mBufferedOutput.toByteArray(); 38300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mBufferedOutput.reset(); 38400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mProducedOutputSizeBytes += result.length; 38500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return result; 38600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 38700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 38800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 38900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin public long getConsumedInputSizeBytes() { 39000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return mDelegate.getConsumedInputSizeBytes(); 39100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 39200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 39300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 39400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin public long getProducedOutputSizeBytes() { 39500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return mProducedOutputSizeBytes; 39600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 39700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 39800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 39900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin /** 40000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * Additional Authentication Data (AAD) stream via a KeyStore streaming operation. This stream 40100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin * sends AAD into the KeyStore. 40200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin */ 40300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private static class AdditionalAuthenticationDataStream implements Stream { 40400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 40500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private final KeyStore mKeyStore; 40600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private final IBinder mOperationToken; 40700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 40800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin private AdditionalAuthenticationDataStream(KeyStore keyStore, IBinder operationToken) { 40900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mKeyStore = keyStore; 41000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mOperationToken = operationToken; 41100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 41200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 41300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 41400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin public OperationResult update(byte[] input) { 41500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin KeymasterArguments keymasterArgs = new KeymasterArguments(); 416ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin keymasterArgs.addBytes(KeymasterDefs.KM_TAG_ASSOCIATED_DATA, input); 41700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 41800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin // KeyStore does not reflect AAD in inputConsumed, but users of Stream rely on this 41900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin // field. We fix this discrepancy here. KeyStore.update contract is that all of AAD 42000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin // has been consumed if the method succeeds. 42100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin OperationResult result = mKeyStore.update(mOperationToken, keymasterArgs, null); 42200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if (result.resultCode == KeyStore.NO_ERROR) { 42300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin result = new OperationResult( 42400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin result.resultCode, 42500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin result.token, 42600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin result.operationHandle, 42700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin input.length, // inputConsumed 42800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin result.output, 42900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin result.outParams); 43000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 43100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return result; 43200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 43300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 43400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin @Override 435d23dc502b0a1952887d4453cba98aa2e3d2f5009Alex Klyubin public OperationResult finish(byte[] signature, byte[] additionalEntropy) { 43600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin if ((additionalEntropy != null) && (additionalEntropy.length > 0)) { 43700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin throw new ProviderException("AAD stream does not support additional entropy"); 43800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 43900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin return new OperationResult( 44000af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin KeyStore.NO_ERROR, 44100af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin mOperationToken, 44200af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 0, // operation handle -- nobody cares about this being returned from finish 44300af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin 0, // inputConsumed 44400af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin EmptyArray.BYTE, // output 44500af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin new KeymasterArguments() // additional params returned by finish 44600af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin ); 44700af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 44800af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin } 44900af27b7d9010eb41e45959dab7c4ff6de119897Alex Klyubin}