AndroidKeyStoreHmacSpi.java revision 058de02073a129301d391c22b050f2d65adadb0f
1cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin/*
2cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin * Copyright (C) 2015 The Android Open Source Project
3cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin *
4cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin * Licensed under the Apache License, Version 2.0 (the "License");
5cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin * you may not use this file except in compliance with the License.
6cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin * You may obtain a copy of the License at
7cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin *
8cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin *      http://www.apache.org/licenses/LICENSE-2.0
9cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin *
10cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin * Unless required by applicable law or agreed to in writing, software
11cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin * distributed under the License is distributed on an "AS IS" BASIS,
12cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin * See the License for the specific language governing permissions and
14cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin * limitations under the License.
15cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin */
16cc21bb3a56915842b545a577d3481047005b1764Alex Klyubin
174ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubinpackage android.security;
184ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
194ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubinimport android.os.IBinder;
204ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubinimport android.security.keymaster.KeymasterArguments;
214ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubinimport android.security.keymaster.KeymasterDefs;
224ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubinimport android.security.keymaster.OperationResult;
234ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
244ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubinimport java.security.InvalidAlgorithmParameterException;
254ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubinimport java.security.InvalidKeyException;
264ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubinimport java.security.Key;
274ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubinimport java.security.spec.AlgorithmParameterSpec;
284ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
294ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubinimport javax.crypto.MacSpi;
304ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
314ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin/**
324ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin * {@link MacSpi} which provides HMAC implementations backed by Android KeyStore.
334ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin *
344ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin * @hide
354ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin */
3652886ca77d4d93f6faf5d2a6836625a421e32403Alex Klyubinpublic abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOperation {
374ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
3870376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin    public static class HmacSHA1 extends KeyStoreHmacSpi {
3970376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin        public HmacSHA1() {
405927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin            super(KeymasterDefs.KM_DIGEST_SHA1);
4170376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin        }
4270376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin    }
4370376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin
4470376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin    public static class HmacSHA224 extends KeyStoreHmacSpi {
4570376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin        public HmacSHA224() {
465927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin            super(KeymasterDefs.KM_DIGEST_SHA_2_224);
4770376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin        }
4870376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin    }
4970376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin
504ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    public static class HmacSHA256 extends KeyStoreHmacSpi {
514ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        public HmacSHA256() {
525927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin            super(KeymasterDefs.KM_DIGEST_SHA_2_256);
5370376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin        }
5470376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin    }
5570376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin
5670376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin    public static class HmacSHA384 extends KeyStoreHmacSpi {
5770376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin        public HmacSHA384() {
585927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin            super(KeymasterDefs.KM_DIGEST_SHA_2_384);
5970376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin        }
6070376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin    }
6170376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin
6270376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin    public static class HmacSHA512 extends KeyStoreHmacSpi {
6370376a77280551791dae62586a6bb0c77ed9429aAlex Klyubin        public HmacSHA512() {
645927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin            super(KeymasterDefs.KM_DIGEST_SHA_2_512);
654ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        }
664ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    }
674ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
684ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    private final KeyStore mKeyStore = KeyStore.getInstance();
695927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin    private final int mKeymasterDigest;
704ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    private final int mMacSizeBytes;
714ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
726c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin    // Fields below are populated by engineInit and should be preserved after engineDoFinal.
736c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin    private KeyStoreSecretKey mKey;
744ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
756c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin    // Fields below are reset when engineDoFinal succeeds.
764ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    private KeyStoreCryptoOperationChunkedStreamer mChunkedStreamer;
774ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    private IBinder mOperationToken;
7852886ca77d4d93f6faf5d2a6836625a421e32403Alex Klyubin    private Long mOperationHandle;
794ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
805927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin    protected KeyStoreHmacSpi(int keymasterDigest) {
815927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin        mKeymasterDigest = keymasterDigest;
825927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin        mMacSizeBytes = KeymasterUtils.getDigestOutputSizeBytes(keymasterDigest);
834ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    }
844ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
854ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    @Override
864ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    protected int engineGetMacLength() {
874ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        return mMacSizeBytes;
884ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    }
894ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
904ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    @Override
914ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    protected void engineInit(Key key, AlgorithmParameterSpec params) throws InvalidKeyException,
924ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin            InvalidAlgorithmParameterException {
936c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        resetAll();
946c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin
956c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        boolean success = false;
966c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        try {
976c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin            init(key, params);
986c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin            ensureKeystoreOperationInitialized();
996c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin            success = true;
1006c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        } finally {
1016c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin            if (!success) {
1026c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin                resetAll();
1036c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin            }
1046c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        }
1056c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin    }
1066c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin
1076c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin    private void init(Key key, AlgorithmParameterSpec params) throws InvalidKeyException,
1086c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        InvalidAlgorithmParameterException {
1094ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        if (key == null) {
1104ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin            throw new InvalidKeyException("key == null");
1114ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        } else if (!(key instanceof KeyStoreSecretKey)) {
1124ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin            throw new InvalidKeyException(
1134ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin                    "Only Android KeyStore secret keys supported. Key: " + key);
1144ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        }
1156c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        mKey = (KeyStoreSecretKey) key;
1164ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
1174ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        if (params != null) {
1184ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin            throw new InvalidAlgorithmParameterException(
1194ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin                    "Unsupported algorithm parameters: " + params);
1204ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        }
1214ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
1226c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin    }
1236c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin
1246c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin    private void resetAll() {
1256c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        mKey = null;
1266c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        IBinder operationToken = mOperationToken;
1276c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        if (operationToken != null) {
1286c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin            mOperationToken = null;
1296c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin            mKeyStore.abort(operationToken);
130a80eee052dd729c2898829fab42a5584d6f5eaf0Alex Klyubin        }
1316c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        mOperationHandle = null;
1326c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        mChunkedStreamer = null;
1334ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    }
1344ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
1356c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin    private void resetWhilePreservingInitState() {
1364ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        IBinder operationToken = mOperationToken;
1374ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        if (operationToken != null) {
1384ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin            mOperationToken = null;
1394ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin            mKeyStore.abort(operationToken);
1404ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        }
14152886ca77d4d93f6faf5d2a6836625a421e32403Alex Klyubin        mOperationHandle = null;
1424ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        mChunkedStreamer = null;
143a80eee052dd729c2898829fab42a5584d6f5eaf0Alex Klyubin    }
144a80eee052dd729c2898829fab42a5584d6f5eaf0Alex Klyubin
1456c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin    @Override
1466c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin    protected void engineReset() {
1476c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        resetWhilePreservingInitState();
1486c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin    }
1496c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin
150ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin    private void ensureKeystoreOperationInitialized() throws InvalidKeyException {
151a80eee052dd729c2898829fab42a5584d6f5eaf0Alex Klyubin        if (mChunkedStreamer != null) {
152a80eee052dd729c2898829fab42a5584d6f5eaf0Alex Klyubin            return;
153a80eee052dd729c2898829fab42a5584d6f5eaf0Alex Klyubin        }
1546c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        if (mKey == null) {
155a80eee052dd729c2898829fab42a5584d6f5eaf0Alex Klyubin            throw new IllegalStateException("Not initialized");
156a80eee052dd729c2898829fab42a5584d6f5eaf0Alex Klyubin        }
1574ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
1584ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        KeymasterArguments keymasterArgs = new KeymasterArguments();
1595927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin        keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_HMAC);
1605927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin        keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
1614ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
1626c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        OperationResult opResult = mKeyStore.begin(
1636c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin                mKey.getAlias(),
1644ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin                KeymasterDefs.KM_PURPOSE_SIGN,
1654ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin                true,
1664ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin                keymasterArgs,
1674ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin                null,
1684ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin                new KeymasterArguments());
1694ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        if (opResult == null) {
1704ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin            throw new KeyStoreConnectException();
171058de02073a129301d391c22b050f2d65adadb0fAlex Klyubin        } else if ((opResult.resultCode != KeyStore.NO_ERROR)
172058de02073a129301d391c22b050f2d65adadb0fAlex Klyubin                && (opResult.resultCode != KeyStore.OP_AUTH_NEEDED)) {
173708fc9404501ac42b6cac925fe3e10801b5f633bAlex Klyubin            throw mKeyStore.getInvalidKeyException(mKey.getAlias(), opResult.resultCode);
1744ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        }
175058de02073a129301d391c22b050f2d65adadb0fAlex Klyubin
176a80eee052dd729c2898829fab42a5584d6f5eaf0Alex Klyubin        if (opResult.token == null) {
177ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin            throw new IllegalStateException("Keystore returned null operation token");
1784ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        }
179058de02073a129301d391c22b050f2d65adadb0fAlex Klyubin        // The operation handle/token is now either valid for use immediately or needs to be
180058de02073a129301d391c22b050f2d65adadb0fAlex Klyubin        // authorized through user authentication (if the error code was OP_AUTH_NEEDED).
181a80eee052dd729c2898829fab42a5584d6f5eaf0Alex Klyubin        mOperationToken = opResult.token;
18252886ca77d4d93f6faf5d2a6836625a421e32403Alex Klyubin        mOperationHandle = opResult.operationHandle;
1834ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        mChunkedStreamer = new KeyStoreCryptoOperationChunkedStreamer(
184b406f242911fa4d910a4cf915a61e39aeace1e1bAlex Klyubin                new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
185b406f242911fa4d910a4cf915a61e39aeace1e1bAlex Klyubin                        mKeyStore, mOperationToken));
1864ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    }
1874ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
1884ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    @Override
1894ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    protected void engineUpdate(byte input) {
1904ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        engineUpdate(new byte[] {input}, 0, 1);
1914ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    }
1924ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
1934ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    @Override
1944ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    protected void engineUpdate(byte[] input, int offset, int len) {
195ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin        try {
196ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin            ensureKeystoreOperationInitialized();
197ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin        } catch (InvalidKeyException e) {
198ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin            throw new IllegalStateException("Failed to reinitialize MAC", e);
199ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin        }
2004ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
2014ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        byte[] output;
2024ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        try {
2034ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin            output = mChunkedStreamer.update(input, offset, len);
204b4834ae3fa09e8013f7ab743a12def063ae999e3Alex Klyubin        } catch (KeyStoreException e) {
205ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin            throw new IllegalStateException("Keystore operation failed", e);
2064ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        }
2074ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        if ((output != null) && (output.length != 0)) {
208ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin            throw new IllegalStateException("Update operation unexpectedly produced output");
2094ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        }
2104ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    }
2114ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
2124ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    @Override
2134ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    protected byte[] engineDoFinal() {
214ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin        try {
215ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin            ensureKeystoreOperationInitialized();
216ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin        } catch (InvalidKeyException e) {
217ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin            throw new IllegalStateException("Failed to reinitialize MAC", e);
218ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin        }
2194ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
2204ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        byte[] result;
2214ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        try {
2224ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin            result = mChunkedStreamer.doFinal(null, 0, 0);
223b4834ae3fa09e8013f7ab743a12def063ae999e3Alex Klyubin        } catch (KeyStoreException e) {
224ad9ba10ecda10c14e46d00f40fc3e431cc2d9bc2Alex Klyubin            throw new IllegalStateException("Keystore operation failed", e);
2254ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        }
2264ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
2276c4a842129db70a9d50b9c0a38cda107ddb943ddAlex Klyubin        resetWhilePreservingInitState();
2284ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        return result;
2294ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    }
2304ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin
2314ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    @Override
2324ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    public void finalize() throws Throwable {
2334ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        try {
2344ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin            IBinder operationToken = mOperationToken;
2354ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin            if (operationToken != null) {
2364ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin                mKeyStore.abort(operationToken);
2374ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin            }
2384ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        } finally {
2394ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin            super.finalize();
2404ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin        }
2414ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin    }
24252886ca77d4d93f6faf5d2a6836625a421e32403Alex Klyubin
24352886ca77d4d93f6faf5d2a6836625a421e32403Alex Klyubin    @Override
24452886ca77d4d93f6faf5d2a6836625a421e32403Alex Klyubin    public Long getOperationHandle() {
24552886ca77d4d93f6faf5d2a6836625a421e32403Alex Klyubin        return mOperationHandle;
24652886ca77d4d93f6faf5d2a6836625a421e32403Alex Klyubin    }
2474ab8ea4498aa25eafdbaadd238fed6eab3f6ee59Alex Klyubin}
248