11ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root/*
21ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root * Copyright (C) 2012 The Android Open Source Project
31ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root *
41ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root * Licensed under the Apache License, Version 2.0 (the "License");
51ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root * you may not use this file except in compliance with the License.
61ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root * You may obtain a copy of the License at
71ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root *
81ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root *      http://www.apache.org/licenses/LICENSE-2.0
91ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root *
101ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root * Unless required by applicable law or agreed to in writing, software
111ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root * distributed under the License is distributed on an "AS IS" BASIS,
121ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root * See the License for the specific language governing permissions and
141ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root * limitations under the License.
151ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root */
161ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt;
181ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
193974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Rootimport java.io.IOException;
201ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.security.AlgorithmParameters;
211ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.security.InvalidAlgorithmParameterException;
221ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.security.InvalidKeyException;
231ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.security.InvalidParameterException;
241ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.security.Key;
251ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.security.KeyFactory;
261ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.security.NoSuchAlgorithmException;
271ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.security.SecureRandom;
281ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.security.spec.AlgorithmParameterSpec;
291ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.security.spec.InvalidKeySpecException;
301ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.security.spec.InvalidParameterSpecException;
311ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.security.spec.PKCS8EncodedKeySpec;
321ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.security.spec.X509EncodedKeySpec;
331ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.util.Arrays;
341ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport java.util.Locale;
351ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport javax.crypto.BadPaddingException;
361ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport javax.crypto.Cipher;
371ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport javax.crypto.CipherSpi;
381ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport javax.crypto.IllegalBlockSizeException;
391ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport javax.crypto.NoSuchPaddingException;
401ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport javax.crypto.SecretKey;
411ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport javax.crypto.ShortBufferException;
421ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport javax.crypto.spec.IvParameterSpec;
431ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootimport javax.crypto.spec.SecretKeySpec;
44c875a50c6c5152f31de58d726c69b93835203511Kenny Rootimport org.conscrypt.util.EmptyArray;
451ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
461ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootpublic abstract class OpenSSLCipher extends CipherSpi {
471ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
481ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    /**
491ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * Modes that a block cipher may support.
501ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     */
511ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected static enum Mode {
521ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        CBC,
531ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        CFB, CFB1, CFB8, CFB128,
541ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        CTR,
551ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        CTS,
561ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        ECB,
571ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        OFB, OFB64, OFB128,
581ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        PCBC,
591ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
601ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
611ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    /**
621ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * Paddings that a block cipher may support.
631ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     */
641ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected static enum Padding {
651ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        NOPADDING,
661ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        PKCS5PADDING,
671ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        ISO10126PADDING,
681ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
691ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
701ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    /**
711ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * Native pointer for the OpenSSL EVP_CIPHER context.
721ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     */
731ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    private OpenSSLCipherContext cipherCtx = new OpenSSLCipherContext(
741ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            NativeCrypto.EVP_CIPHER_CTX_new());
751ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
761ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    /**
771ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * The current cipher mode.
781ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     */
791ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    private Mode mode = Mode.ECB;
801ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
811ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    /**
821ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * The current cipher padding.
831ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     */
841ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    private Padding padding = Padding.PKCS5PADDING;
851ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
861ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    /**
87a749c0d351216be38879600ee8ed01c6793aa256Kenny Root     * May be used when reseting the cipher instance after calling
88a749c0d351216be38879600ee8ed01c6793aa256Kenny Root     * {@code doFinal}.
89a749c0d351216be38879600ee8ed01c6793aa256Kenny Root     */
90a749c0d351216be38879600ee8ed01c6793aa256Kenny Root    private byte[] encodedKey;
91a749c0d351216be38879600ee8ed01c6793aa256Kenny Root
92a749c0d351216be38879600ee8ed01c6793aa256Kenny Root    /**
931ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * The Initial Vector (IV) used for the current cipher.
941ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     */
951ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    private byte[] iv;
961ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
971ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    /**
981ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * Current cipher mode: encrypting or decrypting.
991ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     */
1001ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    private boolean encrypting;
1011ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
1021ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    /**
1031ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * The block size of the current cipher.
1041ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     */
1051ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    private int blockSize;
1061ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
1071ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    /**
1081ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * The block size of the current mode.
1091ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     */
1101ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    private int modeBlockSize;
1111ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
112f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root    /**
113f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root     * Whether the cipher has processed any data yet. OpenSSL doesn't like
114f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root     * calling "doFinal()" in decryption mode without processing any updates.
115f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root     */
116f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root    private boolean calledUpdate;
117f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root
1181ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected OpenSSLCipher() {
1191ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
1201ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
1211ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected OpenSSLCipher(Mode mode, Padding padding) {
1221ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        this.mode = mode;
1231ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        this.padding = padding;
1241ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        blockSize = getCipherBlockSize();
1251ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
1261ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
1271ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    /**
1283974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root     * Returns the standard name for the particular algorithm.
1293974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root     */
1303974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root    protected abstract String getBaseCipherName();
1313974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root
1323974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root    /**
1331ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * Returns the OpenSSL cipher name for the particular {@code keySize} and
1341ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * cipher {@code mode}.
1351ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     */
1361ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected abstract String getCipherName(int keySize, Mode mode);
1371ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
1381ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    /**
1391ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * Checks whether the cipher supports this particular {@code keySize} (in
1401ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * bytes) and throws {@code InvalidKeyException} if it doesn't.
1411ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     */
1421ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected abstract void checkSupportedKeySize(int keySize) throws InvalidKeyException;
1431ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
1441ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    /**
1451ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * Checks whether the cipher supports this particular cipher {@code mode}
1461ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * and throws {@code NoSuchAlgorithmException} if it doesn't.
1471ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     */
1481ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected abstract void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException;
1491ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
1501ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    /**
1511ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * Checks whether the cipher supports this particular cipher {@code padding}
1521ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * and throws {@code NoSuchPaddingException} if it doesn't.
1531ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     */
1541ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected abstract void checkSupportedPadding(Padding padding) throws NoSuchPaddingException;
1551ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
1561ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected abstract int getCipherBlockSize();
1571ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
158ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root    protected boolean supportsVariableSizeKey() {
159ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        return false;
160ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root    }
161ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root
1621ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
1631ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected void engineSetMode(String modeStr) throws NoSuchAlgorithmException {
1641ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        final Mode mode;
1651ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        try {
1661ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            mode = Mode.valueOf(modeStr.toUpperCase(Locale.US));
1671ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } catch (IllegalArgumentException e) {
1681ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            NoSuchAlgorithmException newE = new NoSuchAlgorithmException("No such mode: "
1691ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                    + modeStr);
1701ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            newE.initCause(e);
1711ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throw newE;
1721ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
1731ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        checkSupportedMode(mode);
1741ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        this.mode = mode;
1751ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
1761ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
1771ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
1781ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected void engineSetPadding(String paddingStr) throws NoSuchPaddingException {
1791ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        final String paddingStrUpper = paddingStr.toUpperCase(Locale.US);
1801ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        final Padding padding;
1811ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        try {
1821ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            padding = Padding.valueOf(paddingStrUpper);
1831ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } catch (IllegalArgumentException e) {
1841ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            NoSuchPaddingException newE = new NoSuchPaddingException("No such padding: "
1851ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                    + paddingStr);
1861ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            newE.initCause(e);
1871ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throw newE;
1881ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
1891ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        checkSupportedPadding(padding);
1901ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        this.padding = padding;
1911ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
1921ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
1931ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
1941ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected int engineGetBlockSize() {
1951ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        return blockSize;
1961ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
1971ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
1981ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    /**
1991ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * The size of output if {@code doFinal()} is called with this
2001ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * {@code inputLen}. If padding is enabled and the size of the input puts it
2011ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     * right at the block size, it will add another block for the padding.
2021ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root     */
203f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root    private int getOutputSize(int inputLen) {
204987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root        if (modeBlockSize == 1) {
205f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root            return inputLen;
2061ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } else {
207f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root            final int buffered = NativeCrypto.get_EVP_CIPHER_CTX_buf_len(cipherCtx.getContext());
208c6e1f2f39cabbcddca3751faba6960359d8b1ed8Kenny Root            if (padding == Padding.NOPADDING) {
209f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root                return buffered + inputLen;
210f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root            } else {
211f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root                final int totalLen = inputLen + buffered + modeBlockSize;
212f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root                return totalLen - (totalLen % modeBlockSize);
213f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root            }
2141ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
2151ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
2161ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
2171ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
2181ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected int engineGetOutputSize(int inputLen) {
219f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root        return getOutputSize(inputLen);
2201ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
2211ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
2221ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
2231ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected byte[] engineGetIV() {
2241ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        return iv;
2251ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
2261ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
2271ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
2281ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected AlgorithmParameters engineGetParameters() {
2293974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root        if (iv != null && iv.length > 0) {
2303974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root            try {
2313974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root                AlgorithmParameters params = AlgorithmParameters.getInstance(getBaseCipherName());
2323974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root                params.init(iv);
2333974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root                return params;
2343974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root            } catch (NoSuchAlgorithmException e) {
2353974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root                return null;
2363974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root            } catch (IOException e) {
2373974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root                return null;
2383974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root            }
2393974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root        }
2401ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        return null;
2411ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
2421ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
2433974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root    private void engineInitInternal(int opmode, Key key, byte[] iv, SecureRandom random)
2443974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root            throws InvalidKeyException, InvalidAlgorithmParameterException {
2451ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) {
2461ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            encrypting = true;
2471ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE) {
2481ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            encrypting = false;
2491ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } else {
2501ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throw new InvalidParameterException("Unsupported opmode " + opmode);
2511ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
2521ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
2531ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        if (!(key instanceof SecretKey)) {
2541ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throw new InvalidKeyException("Only SecretKey is supported");
2551ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
2561ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
2571ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        final byte[] encodedKey = key.getEncoded();
2581ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        if (encodedKey == null) {
2591ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throw new InvalidKeyException("key.getEncoded() == null");
2601ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
2611ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        checkSupportedKeySize(encodedKey.length);
262a749c0d351216be38879600ee8ed01c6793aa256Kenny Root        this.encodedKey = encodedKey;
2631ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
26438c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        final long cipherType = NativeCrypto.EVP_get_cipherbyname(getCipherName(encodedKey.length,
2651ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                mode));
2661ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        if (cipherType == 0) {
2671ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throw new InvalidAlgorithmParameterException("Cannot find name for key length = "
2681ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                    + (encodedKey.length * 8) + " and mode = " + mode);
2691ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
2701ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
2711ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        final int ivLength = NativeCrypto.EVP_CIPHER_iv_length(cipherType);
2723974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root        if (iv == null && ivLength != 0) {
2731ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            iv = new byte[ivLength];
2743974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root            if (encrypting) {
2753974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root                if (random == null) {
2763974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root                    random = new SecureRandom();
2773974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root                }
2783974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root                random.nextBytes(iv);
2793974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root            }
2803974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root        } else if (iv != null && iv.length != ivLength) {
2811ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throw new InvalidAlgorithmParameterException("expected IV length of " + ivLength);
2821ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
2831ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
2841ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        this.iv = iv;
2851ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
286ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        if (supportsVariableSizeKey()) {
287ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root            NativeCrypto.EVP_CipherInit_ex(cipherCtx.getContext(), cipherType, null, null,
288ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root                    encrypting);
289ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root            NativeCrypto.EVP_CIPHER_CTX_set_key_length(cipherCtx.getContext(), encodedKey.length);
290ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root            NativeCrypto.EVP_CipherInit_ex(cipherCtx.getContext(), 0, encodedKey, iv, encrypting);
291ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        } else {
292ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root            NativeCrypto.EVP_CipherInit_ex(cipherCtx.getContext(), cipherType, encodedKey, iv,
293ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root                    encrypting);
294ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        }
2951ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
2961ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        // OpenSSL only supports PKCS5 Padding.
2971ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        NativeCrypto.EVP_CIPHER_CTX_set_padding(cipherCtx.getContext(),
2981ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                padding == Padding.PKCS5PADDING);
2991ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        modeBlockSize = NativeCrypto.EVP_CIPHER_CTX_block_size(cipherCtx.getContext());
300f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root        calledUpdate = false;
3011ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
3021ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
3031ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
3041ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
3051ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        try {
3063974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root            engineInitInternal(opmode, key, null, random);
3071ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } catch (InvalidAlgorithmParameterException e) {
3081ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throw new RuntimeException(e);
3091ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
3101ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
3111ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
3121ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
3131ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
3141ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
3151ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        final byte[] iv;
3161ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        if (params instanceof IvParameterSpec) {
3171ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            IvParameterSpec ivParams = (IvParameterSpec) params;
3181ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            iv = ivParams.getIV();
3191ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } else {
3201ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            iv = null;
3211ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
3221ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
3233974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root        engineInitInternal(opmode, key, iv, random);
3241ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
3251ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
3261ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
3271ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)
3281ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throws InvalidKeyException, InvalidAlgorithmParameterException {
3291ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        final AlgorithmParameterSpec spec;
3300ec06644b9846b4a80d62fd1adf46299cdbd6518Kenny Root        if (params != null) {
3310ec06644b9846b4a80d62fd1adf46299cdbd6518Kenny Root            try {
3320ec06644b9846b4a80d62fd1adf46299cdbd6518Kenny Root                spec = params.getParameterSpec(IvParameterSpec.class);
3330ec06644b9846b4a80d62fd1adf46299cdbd6518Kenny Root            } catch (InvalidParameterSpecException e) {
3340ec06644b9846b4a80d62fd1adf46299cdbd6518Kenny Root                throw new InvalidAlgorithmParameterException(e);
3350ec06644b9846b4a80d62fd1adf46299cdbd6518Kenny Root            }
3360ec06644b9846b4a80d62fd1adf46299cdbd6518Kenny Root        } else {
3370ec06644b9846b4a80d62fd1adf46299cdbd6518Kenny Root            spec = null;
3381ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
3391ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
3401ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        engineInit(opmode, key, spec, random);
3411ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
3421ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
3431ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    private final int updateInternal(byte[] input, int inputOffset, int inputLen, byte[] output,
344f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root            int outputOffset, int maximumLen) throws ShortBufferException {
3451ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        final int intialOutputOffset = outputOffset;
3461ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
347987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root        final int bytesLeft = output.length - outputOffset;
348f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root        if (bytesLeft < maximumLen) {
349987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root            throw new ShortBufferException("output buffer too small during update: " + bytesLeft
35026bbd7b835f8677fb9a2cb67c07e8b659fe9635cKenny Root                    + " < " + maximumLen);
3511ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
3521ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
353987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root        outputOffset += NativeCrypto.EVP_CipherUpdate(cipherCtx.getContext(), output, outputOffset,
354987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root                input, inputOffset, inputLen);
3551ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
356f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root        calledUpdate = true;
357f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root
358987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root        return outputOffset - intialOutputOffset;
359987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root    }
3601ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
3611ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
3621ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
363f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root        final int maximumLen = getOutputSize(inputLen);
3641ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
3651ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        /* See how large our output buffer would need to be. */
3661ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        final byte[] output;
367987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root        if (maximumLen > 0) {
368987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root            output = new byte[maximumLen];
3691ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } else {
3701ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            output = EmptyArray.BYTE;
3711ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
3721ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
373987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root        final int bytesWritten;
3741ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        try {
375f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root            bytesWritten = updateInternal(input, inputOffset, inputLen, output, 0, maximumLen);
3761ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } catch (ShortBufferException e) {
3771ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            /* This shouldn't happen. */
378987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root            throw new RuntimeException("calculated buffer size was wrong: " + maximumLen);
3791ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
3801ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
381987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root        if (output.length == bytesWritten) {
382987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root            return output;
383987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root        } else if (bytesWritten == 0) {
384987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root            return EmptyArray.BYTE;
385987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root        } else {
386987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root            return Arrays.copyOfRange(output, 0, bytesWritten);
387987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root        }
3881ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
3891ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
3901ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
3911ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output,
3921ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            int outputOffset) throws ShortBufferException {
393f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root        final int maximumLen = getOutputSize(inputLen);
394f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root        return updateInternal(input, inputOffset, inputLen, output, outputOffset, maximumLen);
3951ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
3961ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
397f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root    /**
398f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root     * Reset this Cipher instance state to process a new chunk of data.
399f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root     */
400f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root    private void reset() {
401a749c0d351216be38879600ee8ed01c6793aa256Kenny Root        NativeCrypto.EVP_CipherInit_ex(cipherCtx.getContext(), 0, encodedKey, iv, encrypting);
402f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root        calledUpdate = false;
403f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root    }
404f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root
4051ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    private int doFinalInternal(byte[] input, int inputOffset, int inputLen, byte[] output,
406f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root            int outputOffset, int maximumLen) throws IllegalBlockSizeException,
407f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root            BadPaddingException, ShortBufferException {
4081ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        /* Remember this so we can tell how many characters were written. */
4091ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        final int initialOutputOffset = outputOffset;
4101ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
4111ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        if (inputLen > 0) {
4121ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            final int updateBytesWritten = updateInternal(input, inputOffset, inputLen, output,
413f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root                    outputOffset, maximumLen);
4141ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            outputOffset += updateBytesWritten;
415f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root            maximumLen -= updateBytesWritten;
4161ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
4171ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
418f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root        /*
419f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root         * If we're decrypting and haven't had any input, we should return null.
420f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root         * Otherwise OpenSSL will complain if we call final.
421f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root         */
422f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root        if (!encrypting && !calledUpdate) {
423f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root            return 0;
424f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root        }
425f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root
4261ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        /* Allow OpenSSL to pad if necessary and clean up state. */
4271ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        final int bytesLeft = output.length - outputOffset;
4281ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        final int writtenBytes;
429f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root        if (bytesLeft >= maximumLen) {
4301ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            writtenBytes = NativeCrypto.EVP_CipherFinal_ex(cipherCtx.getContext(), output,
4311ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                    outputOffset);
4321ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } else {
433f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root            final byte[] lastBlock = new byte[maximumLen];
434987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root            writtenBytes = NativeCrypto.EVP_CipherFinal_ex(cipherCtx.getContext(), lastBlock, 0);
4351ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            if (writtenBytes > bytesLeft) {
4361ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                throw new ShortBufferException("buffer is too short: " + writtenBytes + " > "
4371ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                        + bytesLeft);
4381ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            } else if (writtenBytes > 0) {
439987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root                System.arraycopy(lastBlock, 0, output, outputOffset, writtenBytes);
4401ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            }
4411ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
4421ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        outputOffset += writtenBytes;
4431ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
444f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root        reset();
4451ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
4461ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        return outputOffset - initialOutputOffset;
4471ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
4481ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
4491ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
4501ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
4511ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throws IllegalBlockSizeException, BadPaddingException {
452f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root        /*
453f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root         * Other implementations return null if we've never called update()
454f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root         * while decrypting.
455f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root         */
456f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root        if (!encrypting && !calledUpdate && inputLen == 0) {
457f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root            reset();
458f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root            return null;
459f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root        }
460f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root
461f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root        final int maximumLen = getOutputSize(inputLen);
4621ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        /* Assume that we'll output exactly on a byte boundary. */
463c6e1f2f39cabbcddca3751faba6960359d8b1ed8Kenny Root        final byte[] output = new byte[maximumLen];
4641ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        final int bytesWritten;
4651ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        try {
466f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root            bytesWritten = doFinalInternal(input, inputOffset, inputLen, output, 0, maximumLen);
4671ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } catch (ShortBufferException e) {
4681ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            /* This should not happen since we sized our own buffer. */
4691ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throw new RuntimeException("our calculated buffer was too small", e);
4701ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
4711ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
4721ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        if (bytesWritten == output.length) {
4731ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            return output;
474f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root        } else if (bytesWritten == 0) {
475f57c83839e949081fb3beabece3db4ec5671cc94Kenny Root            return EmptyArray.BYTE;
4761ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } else {
4771ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            return Arrays.copyOfRange(output, 0, bytesWritten);
4781ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
4791ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
4801ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
4811ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
4821ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
4831ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
4841ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            BadPaddingException {
4851ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        if (output == null) {
4861ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throw new NullPointerException("output == null");
4871ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
4881ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
489f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root        final int maximumLen = getOutputSize(inputLen);
490f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root        return doFinalInternal(input, inputOffset, inputLen, output, outputOffset, maximumLen);
4911ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
4921ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
4931ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
4941ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException {
4951ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        try {
4961ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            byte[] encoded = key.getEncoded();
4971ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            return engineDoFinal(encoded, 0, encoded.length);
4981ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } catch (BadPaddingException e) {
4991ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            IllegalBlockSizeException newE = new IllegalBlockSizeException();
5001ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            newE.initCause(e);
5011ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throw newE;
5021ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
5031ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
5041ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
5051ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    @Override
5061ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)
5071ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throws InvalidKeyException, NoSuchAlgorithmException {
5081ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        try {
5091ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            byte[] encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
5101ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            if (wrappedKeyType == Cipher.PUBLIC_KEY) {
5111ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
5121ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                return keyFactory.generatePublic(new X509EncodedKeySpec(encoded));
5131ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            } else if (wrappedKeyType == Cipher.PRIVATE_KEY) {
5141ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
5151ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encoded));
5161ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            } else if (wrappedKeyType == Cipher.SECRET_KEY) {
5171ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
5181ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            } else {
5191ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                throw new UnsupportedOperationException("wrappedKeyType == " + wrappedKeyType);
5201ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            }
5211ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } catch (IllegalBlockSizeException e) {
5221ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throw new InvalidKeyException(e);
5231ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } catch (BadPaddingException e) {
5241ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throw new InvalidKeyException(e);
5251ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        } catch (InvalidKeySpecException e) {
5261ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            throw new InvalidKeyException(e);
5271ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
5281ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
5291ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
5301ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    public static class AES extends OpenSSLCipher {
5311ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        private static final int AES_BLOCK_SIZE = 16;
5321ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
5331ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        protected AES(Mode mode, Padding padding) {
5341ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            super(mode, padding);
5351ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
5361ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
5371ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        public static class CBC extends AES {
5381ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            public CBC(Padding padding) {
5391ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                super(Mode.CBC, padding);
5401ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            }
5411ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
5421ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            public static class NoPadding extends CBC {
5431ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                public NoPadding() {
5441ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                    super(Padding.NOPADDING);
5451ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                }
5461ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            }
5471ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
5481ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            public static class PKCS5Padding extends CBC {
5491ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                public PKCS5Padding() {
5501ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                    super(Padding.PKCS5PADDING);
5511ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                }
5521ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            }
5531ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
5541ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
5551ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        public static class CFB extends AES {
5560a47f2ba654ef74f98a4aa263ac091979e88d6f5Kenny Root            public CFB() {
5570a47f2ba654ef74f98a4aa263ac091979e88d6f5Kenny Root                super(Mode.CFB, Padding.NOPADDING);
5581ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            }
5591ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
5601ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
5611ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        public static class CTR extends AES {
5620a47f2ba654ef74f98a4aa263ac091979e88d6f5Kenny Root            public CTR() {
5630a47f2ba654ef74f98a4aa263ac091979e88d6f5Kenny Root                super(Mode.CTR, Padding.NOPADDING);
5641ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            }
5651ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
5661ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
5671ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        public static class ECB extends AES {
5681ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            public ECB(Padding padding) {
5691ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                super(Mode.ECB, padding);
5701ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            }
5711ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
5721ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            public static class NoPadding extends ECB {
5731ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                public NoPadding() {
5741ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                    super(Padding.NOPADDING);
5751ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                }
5761ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            }
5771ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
5781ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            public static class PKCS5Padding extends ECB {
5791ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                public PKCS5Padding() {
5801ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                    super(Padding.PKCS5PADDING);
5811ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                }
5821ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            }
5831ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
5841ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
5851ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        public static class OFB extends AES {
5860a47f2ba654ef74f98a4aa263ac091979e88d6f5Kenny Root            public OFB() {
5870a47f2ba654ef74f98a4aa263ac091979e88d6f5Kenny Root                super(Mode.OFB, Padding.NOPADDING);
5881ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            }
5891ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
5901ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
5911ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        @Override
5921ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        protected void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
5931ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            switch (keyLength) {
5941ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                case 16: // AES 128
5951ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                case 24: // AES 192
5961ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                case 32: // AES 256
5971ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                    return;
5981ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                default:
5991ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                    throw new InvalidKeyException("Unsupported key size: " + keyLength + " bytes");
6001ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            }
6011ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
6021ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
6031ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        @Override
6041ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        protected void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
6051ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            switch (mode) {
6061ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                case CBC:
6071ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                case CFB:
6081ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                case CFB1:
6091ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                case CFB8:
6101ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                case CFB128:
6111ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                case CTR:
6121ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                case ECB:
6131ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                case OFB:
6141ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                    return;
6151ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                default:
6161ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                    throw new NoSuchAlgorithmException("Unsupported mode " + mode.toString());
6171ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            }
6181ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
6191ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
6201ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        @Override
6211ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        protected void checkSupportedPadding(Padding padding) throws NoSuchPaddingException {
6221ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            switch (padding) {
6231ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                case NOPADDING:
6241ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                case PKCS5PADDING:
6251ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                    return;
6261ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                default:
6271ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root                    throw new NoSuchPaddingException("Unsupported padding " + padding.toString());
6281ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            }
6291ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
6301ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
6311ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        @Override
6323974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root        protected String getBaseCipherName() {
6333974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root            return "AES";
6343974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root        }
6353974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root
6363974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root        @Override
6371ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        protected String getCipherName(int keyLength, Mode mode) {
6381ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            return "aes-" + (keyLength * 8) + "-" + mode.toString().toLowerCase(Locale.US);
6391ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
6401ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root
6411ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        @Override
6421ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        protected int getCipherBlockSize() {
6431ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root            return AES_BLOCK_SIZE;
6441ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root        }
6451ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root    }
646a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
647a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root    public static class DESEDE extends OpenSSLCipher {
648a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        private static int DES_BLOCK_SIZE = 8;
649a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
650a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        public DESEDE(Mode mode, Padding padding) {
651a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            super(mode, padding);
652a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        }
653a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
654a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        public static class CBC extends DESEDE {
655a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            public CBC(Padding padding) {
656a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                super(Mode.CBC, padding);
657a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            }
658a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
659a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            public static class NoPadding extends CBC {
660a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                public NoPadding() {
661a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                    super(Padding.NOPADDING);
662a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                }
663a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            }
664a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
665a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            public static class PKCS5Padding extends CBC {
666a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                public PKCS5Padding() {
667a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                    super(Padding.PKCS5PADDING);
668a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                }
669a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            }
670a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        }
671a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
672a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        public static class CFB extends DESEDE {
6730a47f2ba654ef74f98a4aa263ac091979e88d6f5Kenny Root            public CFB() {
6740a47f2ba654ef74f98a4aa263ac091979e88d6f5Kenny Root                super(Mode.CFB, Padding.NOPADDING);
675a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            }
676a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        }
677a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
678a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        public static class ECB extends DESEDE {
679a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            public ECB(Padding padding) {
680a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                super(Mode.ECB, padding);
681a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            }
682a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
683a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            public static class NoPadding extends ECB {
684a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                public NoPadding() {
685a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                    super(Padding.NOPADDING);
686a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                }
687a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            }
688a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
689a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            public static class PKCS5Padding extends ECB {
690a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                public PKCS5Padding() {
691a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                    super(Padding.PKCS5PADDING);
692a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                }
693a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            }
694a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        }
695a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
696a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        public static class OFB extends DESEDE {
6970a47f2ba654ef74f98a4aa263ac091979e88d6f5Kenny Root            public OFB() {
6980a47f2ba654ef74f98a4aa263ac091979e88d6f5Kenny Root                super(Mode.OFB, Padding.NOPADDING);
699a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            }
700a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        }
701a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
702a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        @Override
7033974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root        protected String getBaseCipherName() {
7043974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root            return "DESede";
7053974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root        }
7063974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root
7073974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root        @Override
708a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        protected String getCipherName(int keySize, Mode mode) {
709f6efe05285dfd12f6ab043cb66e9aec842d90e3aKenny Root            final String baseCipherName;
710f6efe05285dfd12f6ab043cb66e9aec842d90e3aKenny Root            if (keySize == 16) {
711f6efe05285dfd12f6ab043cb66e9aec842d90e3aKenny Root                baseCipherName = "des-ede";
712f6efe05285dfd12f6ab043cb66e9aec842d90e3aKenny Root            } else {
713f6efe05285dfd12f6ab043cb66e9aec842d90e3aKenny Root                baseCipherName = "des-ede3";
714f6efe05285dfd12f6ab043cb66e9aec842d90e3aKenny Root            }
715f6efe05285dfd12f6ab043cb66e9aec842d90e3aKenny Root
716a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            if (mode == Mode.ECB) {
717f6efe05285dfd12f6ab043cb66e9aec842d90e3aKenny Root                return baseCipherName;
718a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            } else {
719f6efe05285dfd12f6ab043cb66e9aec842d90e3aKenny Root                return baseCipherName + "-" + mode.toString().toLowerCase(Locale.US);
720a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            }
721a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        }
722a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
723a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        @Override
724a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        protected void checkSupportedKeySize(int keySize) throws InvalidKeyException {
725a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            if (keySize != 16 && keySize != 24) {
726a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                throw new InvalidKeyException("key size must be 128 or 192 bits");
727a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            }
728a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        }
729a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
730a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        @Override
731a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        protected void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
732a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            switch (mode) {
733a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                case CBC:
734a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                case CFB:
735a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                case CFB1:
736a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                case CFB8:
737a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                case ECB:
738a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                case OFB:
739a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                    return;
740a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                default:
741a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                    throw new NoSuchAlgorithmException("Unsupported mode " + mode.toString());
742a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            }
743a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        }
744a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
745a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        @Override
746a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        protected void checkSupportedPadding(Padding padding) throws NoSuchPaddingException {
747a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            switch (padding) {
748a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                case NOPADDING:
749a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                case PKCS5PADDING:
750a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                    return;
751a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                default:
752a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root                    throw new NoSuchPaddingException("Unsupported padding " + padding.toString());
753a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            }
754a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        }
755a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root
756a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        @Override
757a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        protected int getCipherBlockSize() {
758a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root            return DES_BLOCK_SIZE;
759a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root        }
760a31a304e93764c9b9a9e408ccc79c2ca6cad4fe1Kenny Root    }
761ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root
762ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root    public static class ARC4 extends OpenSSLCipher {
763ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        public ARC4() {
764ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        }
765ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root
766ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        @Override
7673974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root        protected String getBaseCipherName() {
7683974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root            return "ARCFOUR";
7693974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root        }
7703974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root
7713974cacc0af4d6c5e19bf290ea4cdbdc2887fe56Kenny Root        @Override
772ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        protected String getCipherName(int keySize, Mode mode) {
773ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root            return "rc4";
774ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        }
775ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root
776ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        @Override
777ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        protected void checkSupportedKeySize(int keySize) throws InvalidKeyException {
778ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        }
779ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root
780ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        @Override
781ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        protected void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
782ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root            throw new NoSuchAlgorithmException("ARC4 does not support modes");
783ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        }
784ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root
785ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        @Override
786ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        protected void checkSupportedPadding(Padding padding) throws NoSuchPaddingException {
787ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root            throw new NoSuchPaddingException("ARC4 does not support padding");
788ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        }
789ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root
790ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        @Override
791ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        protected int getCipherBlockSize() {
792ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root            return 0;
793ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        }
794ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root
795ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        @Override
796ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        protected boolean supportsVariableSizeKey() {
797ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root            return true;
798ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root        }
799ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root    }
8001ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root}
801