1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.conscrypt;
18
19import java.io.IOException;
20import java.lang.reflect.Constructor;
21import java.lang.reflect.InvocationTargetException;
22import java.security.AlgorithmParameters;
23import java.security.InvalidAlgorithmParameterException;
24import java.security.InvalidKeyException;
25import java.security.InvalidParameterException;
26import java.security.Key;
27import java.security.KeyFactory;
28import java.security.NoSuchAlgorithmException;
29import java.security.SecureRandom;
30import java.security.spec.AlgorithmParameterSpec;
31import java.security.spec.InvalidKeySpecException;
32import java.security.spec.InvalidParameterSpecException;
33import java.security.spec.PKCS8EncodedKeySpec;
34import java.security.spec.X509EncodedKeySpec;
35import java.util.Arrays;
36import java.util.Locale;
37import javax.crypto.BadPaddingException;
38import javax.crypto.Cipher;
39import javax.crypto.CipherSpi;
40import javax.crypto.IllegalBlockSizeException;
41import javax.crypto.NoSuchPaddingException;
42import javax.crypto.SecretKey;
43import javax.crypto.ShortBufferException;
44import javax.crypto.spec.IvParameterSpec;
45import javax.crypto.spec.SecretKeySpec;
46import org.conscrypt.NativeRef.EVP_CIPHER_CTX;
47
48/**
49 * An implementation of {@link Cipher} using BoringSSL as the backing library.
50 *
51 * @hide
52 */
53@Internal
54public abstract class OpenSSLCipher extends CipherSpi {
55
56    /**
57     * Modes that a block cipher may support.
58     */
59    enum Mode {
60        CBC,
61        CTR,
62        ECB,
63        GCM,
64    }
65
66    /**
67     * Paddings that a block cipher may support.
68     */
69    enum Padding {
70        NOPADDING,
71        PKCS5PADDING,
72        ISO10126PADDING,
73    }
74
75    /**
76     * The current cipher mode.
77     */
78    Mode mode = Mode.ECB;
79
80    /**
81     * The current cipher padding.
82     */
83    private Padding padding = Padding.PKCS5PADDING;
84
85    /**
86     * May be used when reseting the cipher instance after calling
87     * {@code doFinal}.
88     */
89    byte[] encodedKey;
90
91    /**
92     * The Initial Vector (IV) used for the current cipher.
93     */
94    byte[] iv;
95
96    /**
97     * Current cipher mode: encrypting or decrypting.
98     */
99    private boolean encrypting;
100
101    /**
102     * The block size of the current cipher.
103     */
104    private int blockSize;
105
106    OpenSSLCipher() {
107    }
108
109    OpenSSLCipher(Mode mode, Padding padding) {
110        this.mode = mode;
111        this.padding = padding;
112        blockSize = getCipherBlockSize();
113    }
114
115    /**
116     * API-specific implementation of initializing the cipher. The
117     * {@link #isEncrypting()} function will tell whether it should be
118     * initialized for encryption or decryption. The {@code encodedKey} will be
119     * the bytes of a supported key size.
120     */
121    abstract void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params,
122            SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException;
123
124    /**
125     * API-specific implementation of updating the cipher. The
126     * {@code maximumLen} will be the maximum length of the output as returned
127     * by {@link #getOutputSizeForUpdate(int)}. The return value must be the
128     * number of bytes processed and placed into {@code output}. On error, an
129     * exception must be thrown.
130     */
131    abstract int updateInternal(byte[] input, int inputOffset, int inputLen,
132            byte[] output, int outputOffset, int maximumLen) throws ShortBufferException;
133
134    /**
135     * API-specific implementation of the final block. The {@code maximumLen}
136     * will be the maximum length of the possible output as returned by
137     * {@link #getOutputSizeForFinal(int)}. The return value must be the number
138     * of bytes processed and placed into {@code output}. On error, an exception
139     * must be thrown.
140     */
141    abstract int doFinalInternal(byte[] output, int outputOffset, int maximumLen)
142            throws IllegalBlockSizeException, BadPaddingException, ShortBufferException;
143
144    /**
145     * Returns the standard name for the particular algorithm.
146     */
147    abstract String getBaseCipherName();
148
149    /**
150     * Checks whether the cipher supports this particular {@code keySize} (in
151     * bytes) and throws {@code InvalidKeyException} if it doesn't.
152     */
153    abstract void checkSupportedKeySize(int keySize) throws InvalidKeyException;
154
155    /**
156     * Checks whether the cipher supports this particular cipher {@code mode}
157     * and throws {@code NoSuchAlgorithmException} if it doesn't.
158     */
159    abstract void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException;
160
161    /**
162     * Checks whether the cipher supports this particular cipher {@code padding}
163     * and throws {@code NoSuchPaddingException} if it doesn't.
164     */
165    abstract void checkSupportedPadding(Padding padding) throws NoSuchPaddingException;
166
167    abstract int getCipherBlockSize();
168
169    boolean supportsVariableSizeKey() {
170        return false;
171    }
172
173    boolean supportsVariableSizeIv() {
174        return false;
175    }
176
177    @Override
178    protected void engineSetMode(String modeStr) throws NoSuchAlgorithmException {
179        final Mode mode;
180        try {
181            mode = Mode.valueOf(modeStr.toUpperCase(Locale.US));
182        } catch (IllegalArgumentException e) {
183            NoSuchAlgorithmException newE = new NoSuchAlgorithmException("No such mode: " + modeStr);
184            newE.initCause(e);
185            throw newE;
186        }
187        checkSupportedMode(mode);
188        this.mode = mode;
189    }
190
191    @Override
192    protected void engineSetPadding(String paddingStr) throws NoSuchPaddingException {
193        final String paddingStrUpper = paddingStr.toUpperCase(Locale.US);
194        final Padding padding;
195        try {
196            padding = Padding.valueOf(paddingStrUpper);
197        } catch (IllegalArgumentException e) {
198            NoSuchPaddingException newE = new NoSuchPaddingException("No such padding: "
199                    + paddingStr);
200            newE.initCause(e);
201            throw newE;
202        }
203        checkSupportedPadding(padding);
204        this.padding = padding;
205    }
206
207    /**
208     * Returns the padding type for which this cipher is initialized.
209     */
210    Padding getPadding() {
211        return padding;
212    }
213
214    @Override
215    protected int engineGetBlockSize() {
216        return blockSize;
217    }
218
219    /**
220     * The size of output if {@code doFinal()} is called with this
221     * {@code inputLen}. If padding is enabled and the size of the input puts it
222     * right at the block size, it will add another block for the padding.
223     */
224    abstract int getOutputSizeForFinal(int inputLen);
225
226    /**
227     * The size of output if {@code update()} is called with this
228     * {@code inputLen}. If padding is enabled and the size of the input puts it
229     * right at the block size, it will add another block for the padding.
230     */
231    abstract int getOutputSizeForUpdate(int inputLen);
232
233    @Override
234    protected int engineGetOutputSize(int inputLen) {
235        return getOutputSizeForFinal(inputLen);
236    }
237
238    @Override
239    protected byte[] engineGetIV() {
240        return iv;
241    }
242
243    @Override
244    protected AlgorithmParameters engineGetParameters() {
245        if (iv != null && iv.length > 0) {
246            try {
247                AlgorithmParameters params = AlgorithmParameters.getInstance(getBaseCipherName());
248                params.init(iv);
249                return params;
250            } catch (NoSuchAlgorithmException e) {
251                return null;
252            } catch (IOException e) {
253                return null;
254            }
255        }
256        return null;
257    }
258
259    @Override
260    protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
261        checkAndSetEncodedKey(opmode, key);
262        try {
263            engineInitInternal(this.encodedKey, null, random);
264        } catch (InvalidAlgorithmParameterException e) {
265            // This can't actually happen since we pass in null.
266            throw new RuntimeException(e);
267        }
268    }
269
270    @Override
271    protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
272            SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
273        checkAndSetEncodedKey(opmode, key);
274        engineInitInternal(this.encodedKey, params, random);
275    }
276
277    @Override
278    protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)
279            throws InvalidKeyException, InvalidAlgorithmParameterException {
280        AlgorithmParameterSpec spec;
281        if (params != null) {
282            try {
283                spec = params.getParameterSpec(IvParameterSpec.class);
284            } catch (InvalidParameterSpecException e) {
285                throw new InvalidAlgorithmParameterException(
286                        "Params must be convertible to IvParameterSpec", e);
287            }
288        } else {
289            spec = null;
290        }
291
292        engineInit(opmode, key, spec, random);
293    }
294
295    @Override
296    protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
297        final int maximumLen = getOutputSizeForUpdate(inputLen);
298
299        /* See how large our output buffer would need to be. */
300        final byte[] output;
301        if (maximumLen > 0) {
302            output = new byte[maximumLen];
303        } else {
304            output = EmptyArray.BYTE;
305        }
306
307        final int bytesWritten;
308        try {
309            bytesWritten = updateInternal(input, inputOffset, inputLen, output, 0, maximumLen);
310        } catch (ShortBufferException e) {
311            /* This shouldn't happen. */
312            throw new RuntimeException("calculated buffer size was wrong: " + maximumLen);
313        }
314
315        if (output.length == bytesWritten) {
316            return output;
317        } else if (bytesWritten == 0) {
318            return EmptyArray.BYTE;
319        } else {
320            return Arrays.copyOfRange(output, 0, bytesWritten);
321        }
322    }
323
324    @Override
325    protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output,
326            int outputOffset) throws ShortBufferException {
327        final int maximumLen = getOutputSizeForUpdate(inputLen);
328        return updateInternal(input, inputOffset, inputLen, output, outputOffset, maximumLen);
329    }
330
331    @Override
332    protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
333            throws IllegalBlockSizeException, BadPaddingException {
334        final int maximumLen = getOutputSizeForFinal(inputLen);
335        /* Assume that we'll output exactly on a byte boundary. */
336        final byte[] output = new byte[maximumLen];
337
338        int bytesWritten;
339        if (inputLen > 0) {
340            try {
341                bytesWritten = updateInternal(input, inputOffset, inputLen, output, 0, maximumLen);
342            } catch (ShortBufferException e) {
343                /* This should not happen since we sized our own buffer. */
344                throw new RuntimeException("our calculated buffer was too small", e);
345            }
346        } else {
347            bytesWritten = 0;
348        }
349
350        try {
351            bytesWritten += doFinalInternal(output, bytesWritten, maximumLen - bytesWritten);
352        } catch (ShortBufferException e) {
353            /* This should not happen since we sized our own buffer. */
354            throw new RuntimeException("our calculated buffer was too small", e);
355        }
356
357        if (bytesWritten == output.length) {
358            return output;
359        } else if (bytesWritten == 0) {
360            return EmptyArray.BYTE;
361        } else {
362            return Arrays.copyOfRange(output, 0, bytesWritten);
363        }
364    }
365
366    @Override
367    protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
368            int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
369            BadPaddingException {
370        if (output == null) {
371            throw new NullPointerException("output == null");
372        }
373
374        int maximumLen = getOutputSizeForFinal(inputLen);
375
376        final int bytesWritten;
377        if (inputLen > 0) {
378            bytesWritten = updateInternal(input, inputOffset, inputLen, output, outputOffset,
379                    maximumLen);
380            outputOffset += bytesWritten;
381            maximumLen -= bytesWritten;
382        } else {
383            bytesWritten = 0;
384        }
385
386        return bytesWritten + doFinalInternal(output, outputOffset, maximumLen);
387    }
388
389    @Override
390    protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException {
391        try {
392            byte[] encoded = key.getEncoded();
393            return engineDoFinal(encoded, 0, encoded.length);
394        } catch (BadPaddingException e) {
395            IllegalBlockSizeException newE = new IllegalBlockSizeException();
396            newE.initCause(e);
397            throw newE;
398        }
399    }
400
401    @Override
402    protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)
403            throws InvalidKeyException, NoSuchAlgorithmException {
404        try {
405            byte[] encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
406            if (wrappedKeyType == Cipher.PUBLIC_KEY) {
407                KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
408                return keyFactory.generatePublic(new X509EncodedKeySpec(encoded));
409            } else if (wrappedKeyType == Cipher.PRIVATE_KEY) {
410                KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
411                return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encoded));
412            } else if (wrappedKeyType == Cipher.SECRET_KEY) {
413                return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
414            } else {
415                throw new UnsupportedOperationException("wrappedKeyType == " + wrappedKeyType);
416            }
417        } catch (IllegalBlockSizeException e) {
418            throw new InvalidKeyException(e);
419        } catch (BadPaddingException e) {
420            throw new InvalidKeyException(e);
421        } catch (InvalidKeySpecException e) {
422            throw new InvalidKeyException(e);
423        }
424    }
425
426    private byte[] checkAndSetEncodedKey(int opmode, Key key) throws InvalidKeyException {
427        if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) {
428            encrypting = true;
429        } else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE) {
430            encrypting = false;
431        } else {
432            throw new InvalidParameterException("Unsupported opmode " + opmode);
433        }
434
435        if (!(key instanceof SecretKey)) {
436            throw new InvalidKeyException("Only SecretKey is supported");
437        }
438
439        final byte[] encodedKey = key.getEncoded();
440        if (encodedKey == null) {
441            throw new InvalidKeyException("key.getEncoded() == null");
442        }
443        checkSupportedKeySize(encodedKey.length);
444        this.encodedKey = encodedKey;
445        return encodedKey;
446    }
447
448    boolean isEncrypting() {
449        return encrypting;
450    }
451
452    public static abstract class EVP_CIPHER extends OpenSSLCipher {
453        /**
454         * Native pointer for the OpenSSL EVP_CIPHER context.
455         */
456        private final EVP_CIPHER_CTX cipherCtx = new EVP_CIPHER_CTX(
457                NativeCrypto.EVP_CIPHER_CTX_new());
458
459        /**
460         * Whether the cipher has processed any data yet. EVP_CIPHER doesn't
461         * like calling "doFinal()" in decryption mode without processing any
462         * updates.
463         */
464        boolean calledUpdate;
465
466        /**
467         * The block size of the current mode.
468         */
469        private int modeBlockSize;
470
471        public EVP_CIPHER(Mode mode, Padding padding) {
472            super(mode, padding);
473        }
474
475        @Override
476        void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params,
477                SecureRandom random) throws InvalidKeyException,
478                InvalidAlgorithmParameterException {
479            byte[] iv;
480            if (params instanceof IvParameterSpec) {
481                IvParameterSpec ivParams = (IvParameterSpec) params;
482                iv = ivParams.getIV();
483            } else {
484                iv = null;
485            }
486
487            final long cipherType = NativeCrypto.EVP_get_cipherbyname(getCipherName(
488                    encodedKey.length, mode));
489            if (cipherType == 0) {
490                throw new InvalidAlgorithmParameterException("Cannot find name for key length = "
491                        + (encodedKey.length * 8) + " and mode = " + mode);
492            }
493
494            final boolean encrypting = isEncrypting();
495
496            final int expectedIvLength = NativeCrypto.EVP_CIPHER_iv_length(cipherType);
497            if (iv == null && expectedIvLength != 0) {
498                if (!encrypting) {
499                    throw new InvalidAlgorithmParameterException("IV must be specified in " + mode
500                            + " mode");
501                }
502
503                iv = new byte[expectedIvLength];
504                if (random != null) {
505                    random.nextBytes(iv);
506                } else {
507                    NativeCrypto.RAND_bytes(iv);
508                }
509            } else if (expectedIvLength == 0 && iv != null) {
510                throw new InvalidAlgorithmParameterException("IV not used in " + mode + " mode");
511            } else if (iv != null && iv.length != expectedIvLength) {
512                throw new InvalidAlgorithmParameterException("expected IV length of "
513                        + expectedIvLength + " but was " + iv.length);
514            }
515
516            this.iv = iv;
517
518            if (supportsVariableSizeKey()) {
519                NativeCrypto.EVP_CipherInit_ex(cipherCtx, cipherType, null, null, encrypting);
520                NativeCrypto.EVP_CIPHER_CTX_set_key_length(cipherCtx, encodedKey.length);
521                NativeCrypto.EVP_CipherInit_ex(cipherCtx, 0, encodedKey, iv, isEncrypting());
522            } else {
523                NativeCrypto.EVP_CipherInit_ex(cipherCtx, cipherType, encodedKey, iv, encrypting);
524            }
525
526            // OpenSSL only supports PKCS5 Padding.
527            NativeCrypto
528                    .EVP_CIPHER_CTX_set_padding(cipherCtx, getPadding() == Padding.PKCS5PADDING);
529            modeBlockSize = NativeCrypto.EVP_CIPHER_CTX_block_size(cipherCtx);
530            calledUpdate = false;
531        }
532
533        @Override
534        int updateInternal(byte[] input, int inputOffset, int inputLen, byte[] output,
535                int outputOffset, int maximumLen) throws ShortBufferException {
536            final int intialOutputOffset = outputOffset;
537
538            final int bytesLeft = output.length - outputOffset;
539            if (bytesLeft < maximumLen) {
540                throw new ShortBufferException("output buffer too small during update: "
541                        + bytesLeft + " < " + maximumLen);
542            }
543
544            outputOffset += NativeCrypto.EVP_CipherUpdate(cipherCtx, output, outputOffset, input,
545                    inputOffset, inputLen);
546
547            calledUpdate = true;
548
549            return outputOffset - intialOutputOffset;
550        }
551
552        @Override
553        int doFinalInternal(byte[] output, int outputOffset, int maximumLen)
554                throws IllegalBlockSizeException, BadPaddingException, ShortBufferException {
555            /* Remember this so we can tell how many characters were written. */
556            final int initialOutputOffset = outputOffset;
557
558            /*
559             * If we're decrypting and haven't had any input, we should return
560             * null. Otherwise OpenSSL will complain if we call final.
561             */
562            if (!isEncrypting() && !calledUpdate) {
563                return 0;
564            }
565
566            /* Allow OpenSSL to pad if necessary and clean up state. */
567            final int bytesLeft = output.length - outputOffset;
568            final int writtenBytes;
569            if (bytesLeft >= maximumLen) {
570                writtenBytes = NativeCrypto.EVP_CipherFinal_ex(cipherCtx, output, outputOffset);
571            } else {
572                final byte[] lastBlock = new byte[maximumLen];
573                writtenBytes = NativeCrypto.EVP_CipherFinal_ex(cipherCtx, lastBlock, 0);
574                if (writtenBytes > bytesLeft) {
575                    throw new ShortBufferException("buffer is too short: " + writtenBytes + " > "
576                            + bytesLeft);
577                } else if (writtenBytes > 0) {
578                    System.arraycopy(lastBlock, 0, output, outputOffset, writtenBytes);
579                }
580            }
581            outputOffset += writtenBytes;
582
583            reset();
584
585            return outputOffset - initialOutputOffset;
586        }
587
588        @Override
589        int getOutputSizeForFinal(int inputLen) {
590            if (modeBlockSize == 1) {
591                return inputLen;
592            } else {
593                final int buffered = NativeCrypto.get_EVP_CIPHER_CTX_buf_len(cipherCtx);
594
595                if (getPadding() == Padding.NOPADDING) {
596                    return buffered + inputLen;
597                } else {
598                    final boolean finalUsed = NativeCrypto.get_EVP_CIPHER_CTX_final_used(cipherCtx);
599                    // There is an additional buffer containing the possible final block.
600                    int totalLen = inputLen + buffered + (finalUsed ? modeBlockSize : 0);
601                    // Extra block for remainder bytes plus padding.
602                    // In case it's encrypting and there are no remainder bytes, add an extra block
603                    // consisting only of padding.
604                    totalLen += ((totalLen % modeBlockSize != 0) || isEncrypting())
605                            ? modeBlockSize : 0;
606                    // The minimum multiple of {@code modeBlockSize} that can hold all the bytes.
607                    return totalLen - (totalLen % modeBlockSize);
608                }
609            }
610        }
611
612        @Override
613        int getOutputSizeForUpdate(int inputLen) {
614            return getOutputSizeForFinal(inputLen);
615        }
616
617        /**
618         * Returns the OpenSSL cipher name for the particular {@code keySize}
619         * and cipher {@code mode}.
620         */
621        abstract String getCipherName(int keySize, Mode mode);
622
623        /**
624         * Reset this Cipher instance state to process a new chunk of data.
625         */
626        private void reset() {
627            NativeCrypto.EVP_CipherInit_ex(cipherCtx, 0, encodedKey, iv, isEncrypting());
628            calledUpdate = false;
629        }
630
631        abstract static class AES_BASE extends EVP_CIPHER {
632            private static final int AES_BLOCK_SIZE = 16;
633
634            AES_BASE(Mode mode, Padding padding) {
635                super(mode, padding);
636            }
637
638            @Override
639            void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
640                switch (mode) {
641                    case CBC:
642                    case CTR:
643                    case ECB:
644                        return;
645                    default:
646                        throw new NoSuchAlgorithmException("Unsupported mode " + mode.toString());
647                }
648            }
649
650            @Override
651            void checkSupportedPadding(Padding padding) throws NoSuchPaddingException {
652                switch (padding) {
653                    case NOPADDING:
654                    case PKCS5PADDING:
655                        return;
656                    default:
657                        throw new NoSuchPaddingException(
658                                "Unsupported padding " + padding.toString());
659                }
660            }
661
662            @Override
663            String getBaseCipherName() {
664                return "AES";
665            }
666
667            @Override
668            String getCipherName(int keyLength, Mode mode) {
669                return "aes-" + (keyLength * 8) + "-" + mode.toString().toLowerCase(Locale.US);
670            }
671
672            @Override
673            int getCipherBlockSize() {
674                return AES_BLOCK_SIZE;
675            }
676        }
677
678        public static class AES extends AES_BASE {
679            AES(Mode mode, Padding padding) {
680                super(mode, padding);
681            }
682
683            public static class CBC extends AES {
684                public CBC(Padding padding) {
685                    super(Mode.CBC, padding);
686                }
687
688                public static class NoPadding extends CBC {
689                    public NoPadding() {
690                        super(Padding.NOPADDING);
691                    }
692                }
693
694                public static class PKCS5Padding extends CBC {
695                    public PKCS5Padding() {
696                        super(Padding.PKCS5PADDING);
697                    }
698                }
699            }
700
701            public static class CTR extends AES {
702                public CTR() {
703                    super(Mode.CTR, Padding.NOPADDING);
704                }
705            }
706
707            public static class ECB extends AES {
708                public ECB(Padding padding) {
709                    super(Mode.ECB, padding);
710                }
711
712                public static class NoPadding extends ECB {
713                    public NoPadding() {
714                        super(Padding.NOPADDING);
715                    }
716                }
717
718                public static class PKCS5Padding extends ECB {
719                    public PKCS5Padding() {
720                        super(Padding.PKCS5PADDING);
721                    }
722                }
723            }
724
725            @Override
726            void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
727                switch (keyLength) {
728                    case 16: // AES 128
729                    case 24: // AES 192
730                    case 32: // AES 256
731                        return;
732                    default:
733                        throw new InvalidKeyException("Unsupported key size: " + keyLength
734                                + " bytes");
735                }
736            }
737        }
738
739        public static class AES_128 extends AES_BASE {
740            AES_128(Mode mode, Padding padding) {
741                super(mode, padding);
742            }
743
744            public static class CBC extends AES_128 {
745                public CBC(Padding padding) {
746                    super(Mode.CBC, padding);
747                }
748
749                public static class NoPadding extends CBC {
750                    public NoPadding() {
751                        super(Padding.NOPADDING);
752                    }
753                }
754
755                public static class PKCS5Padding extends CBC {
756                    public PKCS5Padding() {
757                        super(Padding.PKCS5PADDING);
758                    }
759                }
760            }
761
762            public static class CTR extends AES_128 {
763                public CTR() {
764                    super(Mode.CTR, Padding.NOPADDING);
765                }
766            }
767
768            public static class ECB extends AES_128 {
769                public ECB(Padding padding) {
770                    super(Mode.ECB, padding);
771                }
772
773                public static class NoPadding extends ECB {
774                    public NoPadding() {
775                        super(Padding.NOPADDING);
776                    }
777                }
778
779                public static class PKCS5Padding extends ECB {
780                    public PKCS5Padding() {
781                        super(Padding.PKCS5PADDING);
782                    }
783                }
784            }
785
786            @Override
787            void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
788                if (keyLength != 16) { // 128 bits
789                    throw new InvalidKeyException("Unsupported key size: " + keyLength + " bytes");
790                }
791            }
792        }
793
794        public static class AES_256 extends AES_BASE {
795            AES_256(Mode mode, Padding padding) {
796                super(mode, padding);
797            }
798
799            public static class CBC extends AES_256 {
800                public CBC(Padding padding) {
801                    super(Mode.CBC, padding);
802                }
803
804                public static class NoPadding extends CBC {
805                    public NoPadding() {
806                        super(Padding.NOPADDING);
807                    }
808                }
809
810                public static class PKCS5Padding extends CBC {
811                    public PKCS5Padding() {
812                        super(Padding.PKCS5PADDING);
813                    }
814                }
815            }
816
817            public static class CTR extends AES_256 {
818                public CTR() {
819                    super(Mode.CTR, Padding.NOPADDING);
820                }
821            }
822
823            public static class ECB extends AES_256 {
824                public ECB(Padding padding) {
825                    super(Mode.ECB, padding);
826                }
827
828                public static class NoPadding extends ECB {
829                    public NoPadding() {
830                        super(Padding.NOPADDING);
831                    }
832                }
833
834                public static class PKCS5Padding extends ECB {
835                    public PKCS5Padding() {
836                        super(Padding.PKCS5PADDING);
837                    }
838                }
839            }
840
841            @Override
842            void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
843                if (keyLength != 32) { // 256 bits
844                    throw new InvalidKeyException("Unsupported key size: " + keyLength + " bytes");
845                }
846            }
847        }
848
849        public static class DESEDE extends EVP_CIPHER {
850            private static final int DES_BLOCK_SIZE = 8;
851
852            public DESEDE(Mode mode, Padding padding) {
853                super(mode, padding);
854            }
855
856            public static class CBC extends DESEDE {
857                public CBC(Padding padding) {
858                    super(Mode.CBC, padding);
859                }
860
861                public static class NoPadding extends CBC {
862                    public NoPadding() {
863                        super(Padding.NOPADDING);
864                    }
865                }
866
867                public static class PKCS5Padding extends CBC {
868                    public PKCS5Padding() {
869                        super(Padding.PKCS5PADDING);
870                    }
871                }
872            }
873
874            @Override
875            String getBaseCipherName() {
876                return "DESede";
877            }
878
879            @Override
880            String getCipherName(int keySize, Mode mode) {
881                final String baseCipherName;
882                if (keySize == 16) {
883                    baseCipherName = "des-ede";
884                } else {
885                    baseCipherName = "des-ede3";
886                }
887
888                return baseCipherName + "-" + mode.toString().toLowerCase(Locale.US);
889            }
890
891            @Override
892            void checkSupportedKeySize(int keySize) throws InvalidKeyException {
893                if (keySize != 16 && keySize != 24) {
894                    throw new InvalidKeyException("key size must be 128 or 192 bits");
895                }
896            }
897
898            @Override
899            void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
900                if (mode != Mode.CBC) {
901                    throw new NoSuchAlgorithmException("Unsupported mode " + mode.toString());
902                }
903            }
904
905            @Override
906            void checkSupportedPadding(Padding padding) throws NoSuchPaddingException {
907                switch (padding) {
908                    case NOPADDING:
909                    case PKCS5PADDING:
910                        return;
911                    default:
912                        throw new NoSuchPaddingException("Unsupported padding "
913                                + padding.toString());
914                }
915            }
916
917            @Override
918            int getCipherBlockSize() {
919                return DES_BLOCK_SIZE;
920            }
921        }
922
923        public static class ARC4 extends EVP_CIPHER {
924            public ARC4() {
925                // Modes and padding don't make sense for ARC4.
926                super(Mode.ECB, Padding.NOPADDING);
927            }
928
929            @Override
930            String getBaseCipherName() {
931                return "ARCFOUR";
932            }
933
934            @Override
935            String getCipherName(int keySize, Mode mode) {
936                return "rc4";
937            }
938
939            @Override
940            void checkSupportedKeySize(int keySize) throws InvalidKeyException {
941            }
942
943            @Override
944            void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
945                throw new NoSuchAlgorithmException("ARC4 does not support modes");
946            }
947
948            @Override
949            void checkSupportedPadding(Padding padding) throws NoSuchPaddingException {
950                throw new NoSuchPaddingException("ARC4 does not support padding");
951            }
952
953            @Override
954            int getCipherBlockSize() {
955                return 0;
956            }
957
958            @Override
959            boolean supportsVariableSizeKey() {
960                return true;
961            }
962        }
963    }
964
965    public static abstract class EVP_AEAD extends OpenSSLCipher {
966        /**
967         * The default tag size when one is not specified. Default to
968         * full-length tags (128-bits or 16 octets).
969         */
970        private static final int DEFAULT_TAG_SIZE_BITS = 16 * 8;
971
972        /**
973         * Keeps track of the last used block size.
974         */
975        private static int lastGlobalMessageSize = 32;
976
977        /**
978         * The byte array containing the bytes written.
979         */
980        byte[] buf;
981
982        /**
983         * The number of bytes written.
984         */
985        int bufCount;
986
987        /**
988         * AEAD cipher reference.
989         */
990        long evpAead;
991
992        /**
993         * Additional authenticated data.
994         */
995        private byte[] aad;
996
997        /**
998         * The length of the AEAD cipher tag in bytes.
999         */
1000        private int tagLengthInBytes;
1001
1002        public EVP_AEAD(Mode mode) {
1003            super(mode, Padding.NOPADDING);
1004        }
1005
1006        private void expand(int i) {
1007            /* Can the buffer handle i more bytes, if not expand it */
1008            if (bufCount + i <= buf.length) {
1009                return;
1010            }
1011
1012            byte[] newbuf = new byte[(bufCount + i) * 2];
1013            System.arraycopy(buf, 0, newbuf, 0, bufCount);
1014            buf = newbuf;
1015        }
1016
1017        private void reset() {
1018            aad = null;
1019            final int lastBufSize = lastGlobalMessageSize;
1020            if (buf == null) {
1021                buf = new byte[lastBufSize];
1022            } else if (bufCount > 0 && bufCount != lastBufSize) {
1023                lastGlobalMessageSize = bufCount;
1024                if (buf.length != bufCount) {
1025                    buf = new byte[bufCount];
1026                }
1027            }
1028            bufCount = 0;
1029        }
1030
1031        @Override
1032        void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params,
1033                SecureRandom random) throws InvalidKeyException,
1034                InvalidAlgorithmParameterException {
1035            byte[] iv;
1036            final int tagLenBits;
1037            if (params == null) {
1038                iv = null;
1039                tagLenBits = DEFAULT_TAG_SIZE_BITS;
1040            } else {
1041                GCMParameters gcmParams = Platform.fromGCMParameterSpec(params);
1042                if (gcmParams != null) {
1043                    iv = gcmParams.getIV();
1044                    tagLenBits = gcmParams.getTLen();
1045                } else if (params instanceof IvParameterSpec) {
1046                    IvParameterSpec ivParams = (IvParameterSpec) params;
1047                    iv = ivParams.getIV();
1048                    tagLenBits = DEFAULT_TAG_SIZE_BITS;
1049                } else {
1050                    iv = null;
1051                    tagLenBits = DEFAULT_TAG_SIZE_BITS;
1052                }
1053            }
1054
1055            if (tagLenBits % 8 != 0) {
1056                throw new InvalidAlgorithmParameterException(
1057                        "Tag length must be a multiple of 8; was " + tagLengthInBytes);
1058            }
1059
1060            tagLengthInBytes = tagLenBits / 8;
1061
1062            final boolean encrypting = isEncrypting();
1063
1064            evpAead = getEVP_AEAD(encodedKey.length);
1065
1066            final int expectedIvLength = NativeCrypto.EVP_AEAD_nonce_length(evpAead);
1067            if (iv == null && expectedIvLength != 0) {
1068                if (!encrypting) {
1069                    throw new InvalidAlgorithmParameterException("IV must be specified in " + mode
1070                            + " mode");
1071                }
1072
1073                iv = new byte[expectedIvLength];
1074                if (random != null) {
1075                    random.nextBytes(iv);
1076                } else {
1077                    NativeCrypto.RAND_bytes(iv);
1078                }
1079            } else if (expectedIvLength == 0 && iv != null) {
1080                throw new InvalidAlgorithmParameterException("IV not used in " + mode + " mode");
1081            } else if (iv != null && iv.length != expectedIvLength) {
1082                throw new InvalidAlgorithmParameterException("Expected IV length of "
1083                        + expectedIvLength + " but was " + iv.length);
1084            }
1085
1086            this.iv = iv;
1087            reset();
1088        }
1089
1090        @Override
1091        int updateInternal(byte[] input, int inputOffset, int inputLen, byte[] output,
1092                int outputOffset, int maximumLen) throws ShortBufferException {
1093            if (buf == null) {
1094                throw new IllegalStateException("Cipher not initialized");
1095            }
1096
1097            ArrayUtils.checkOffsetAndCount(input.length, inputOffset, inputLen);
1098            if (inputLen > 0) {
1099                expand(inputLen);
1100                System.arraycopy(input, inputOffset, buf, this.bufCount, inputLen);
1101                this.bufCount += inputLen;
1102            }
1103            return 0;
1104        }
1105
1106        @SuppressWarnings("LiteralClassName")
1107        private void throwAEADBadTagExceptionIfAvailable(String message, Throwable cause)
1108                throws BadPaddingException {
1109            Constructor<?> aeadBadTagConstructor;
1110            try {
1111                aeadBadTagConstructor = Class.forName("javax.crypto.AEADBadTagException")
1112                                                .getConstructor(String.class);
1113            } catch (Exception ignored) {
1114                return;
1115            }
1116
1117            BadPaddingException badTagException = null;
1118            try {
1119                badTagException = (BadPaddingException) aeadBadTagConstructor.newInstance(message);
1120                badTagException.initCause(cause);
1121            } catch (IllegalAccessException e2) {
1122                // Fall through
1123            } catch (InstantiationException e2) {
1124                // Fall through
1125            } catch (InvocationTargetException e2) {
1126                throw(BadPaddingException) new BadPaddingException().initCause(
1127                        e2.getTargetException());
1128            }
1129            if (badTagException != null) {
1130                throw badTagException;
1131            }
1132        }
1133
1134        @Override
1135        int doFinalInternal(byte[] output, int outputOffset, int maximumLen)
1136                throws IllegalBlockSizeException, BadPaddingException {
1137            final int bytesWritten;
1138            try {
1139                if (isEncrypting()) {
1140                    bytesWritten = NativeCrypto.EVP_AEAD_CTX_seal(evpAead, encodedKey,
1141                            tagLengthInBytes, output, outputOffset, iv, buf, 0, bufCount, aad);
1142                } else {
1143                    bytesWritten = NativeCrypto.EVP_AEAD_CTX_open(evpAead, encodedKey,
1144                            tagLengthInBytes, output, outputOffset, iv, buf, 0, bufCount, aad);
1145                }
1146            } catch (BadPaddingException e) {
1147                throwAEADBadTagExceptionIfAvailable(e.getMessage(), e.getCause());
1148                throw e;
1149            }
1150            reset();
1151            return bytesWritten;
1152        }
1153
1154        @Override
1155        void checkSupportedPadding(Padding padding) throws NoSuchPaddingException {
1156            if (padding != Padding.NOPADDING) {
1157                throw new NoSuchPaddingException("Must be NoPadding for AEAD ciphers");
1158            }
1159        }
1160
1161        @Override
1162        int getOutputSizeForFinal(int inputLen) {
1163            return bufCount + inputLen
1164                    + (isEncrypting() ? NativeCrypto.EVP_AEAD_max_overhead(evpAead) : 0);
1165        }
1166
1167        // Intentionally missing Override to compile on old versions of Android
1168        @SuppressWarnings("MissingOverride")
1169        protected void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) {
1170            if (aad == null) {
1171                aad = Arrays.copyOfRange(input, inputOffset, inputOffset + inputLen);
1172            } else {
1173                int newSize = aad.length + inputLen;
1174                byte[] newaad = new byte[newSize];
1175                System.arraycopy(aad, 0, newaad, 0, aad.length);
1176                System.arraycopy(input, inputOffset, newaad, aad.length, inputLen);
1177                aad = newaad;
1178            }
1179        }
1180
1181        @Override
1182        protected AlgorithmParameters engineGetParameters() {
1183            // iv will be non-null after initialization.
1184            if (iv == null) {
1185                return null;
1186            }
1187
1188            AlgorithmParameterSpec spec = Platform.toGCMParameterSpec(tagLengthInBytes * 8, iv);
1189            if (spec == null) {
1190                // The platform doesn't support GCMParameterSpec. Fall back to
1191                // the generic AES parameters so at least the caller can get the
1192                // IV.
1193                return super.engineGetParameters();
1194            }
1195
1196            try {
1197                AlgorithmParameters params = AlgorithmParameters.getInstance("GCM");
1198                params.init(spec);
1199                return params;
1200            } catch (NoSuchAlgorithmException | InvalidParameterSpecException e) {
1201                // This may happen since Conscrypt doesn't provide this itself.
1202                return null;
1203            }
1204        }
1205
1206        abstract long getEVP_AEAD(int keyLength) throws InvalidKeyException;
1207
1208        public abstract static class AES extends EVP_AEAD {
1209            private static final int AES_BLOCK_SIZE = 16;
1210
1211            AES(Mode mode) {
1212                super(mode);
1213            }
1214
1215            @Override
1216            void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
1217                switch (keyLength) {
1218                    case 16: // AES 128
1219                    case 32: // AES 256
1220                        return;
1221                    default:
1222                        throw new InvalidKeyException("Unsupported key size: " + keyLength
1223                                + " bytes (must be 16 or 32)");
1224                }
1225            }
1226
1227            @Override
1228            String getBaseCipherName() {
1229                return "AES";
1230            }
1231
1232            @Override
1233            int getCipherBlockSize() {
1234                return AES_BLOCK_SIZE;
1235            }
1236
1237            /**
1238             * AEAD buffers everything until a final output.
1239             */
1240            @Override
1241            int getOutputSizeForUpdate(int inputLen) {
1242                return 0;
1243            }
1244
1245            public static class GCM extends AES {
1246                /**
1247                 * The previously used key to prevent key + nonce (IV) reuse.
1248                 */
1249                private byte[] previousKey;
1250
1251                /**
1252                 * The previously used nonce (IV) to prevent key + nonce reuse.
1253                 */
1254                private byte[] previousIv;
1255
1256                /**
1257                 * When set this instance must be initialized before use again. This prevents key
1258                 * and IV reuse.
1259                 */
1260                private boolean mustInitialize;
1261
1262                public GCM() {
1263                    super(Mode.GCM);
1264                }
1265
1266                private void checkInitialization() {
1267                    if (mustInitialize) {
1268                        throw new IllegalStateException(
1269                                "Cannot re-use same key and IV for multiple encryptions");
1270                    }
1271                }
1272
1273                /** Constant time array comparison. */
1274                private boolean arraysAreEqual(byte[] a, byte[] b) {
1275                    if (a.length != b.length) {
1276                        return false;
1277                    }
1278
1279                    int diff = 0;
1280                    for (int i = 0; i < a.length; i++) {
1281                        diff |= a[i] ^ b[i];
1282                    }
1283                    return diff == 0;
1284                }
1285
1286                @Override
1287                void engineInitInternal(
1288                        byte[] encodedKey, AlgorithmParameterSpec params, SecureRandom random)
1289                        throws InvalidKeyException, InvalidAlgorithmParameterException {
1290                    super.engineInitInternal(encodedKey, params, random);
1291
1292                    if (isEncrypting() && iv != null) {
1293                        if (previousKey != null && previousIv != null
1294                                && arraysAreEqual(previousKey, encodedKey)
1295                                && arraysAreEqual(previousIv, iv)) {
1296                            mustInitialize = true;
1297                            throw new InvalidAlgorithmParameterException(
1298                                    "In GCM mode key and IV must not be re-used");
1299                        }
1300
1301                        this.previousKey = encodedKey;
1302                        this.previousIv = iv;
1303                    }
1304                    mustInitialize = false;
1305                }
1306
1307                @Override
1308                int updateInternal(byte[] input, int inputOffset, int inputLen,
1309                        byte[] output, int outputOffset, int maximumLen)
1310                        throws ShortBufferException {
1311                    checkInitialization();
1312                    return super.updateInternal(
1313                            input, inputOffset, inputLen, output, outputOffset, maximumLen);
1314                }
1315
1316                @Override
1317                int doFinalInternal(byte[] output, int outputOffset, int maximumLen)
1318                        throws IllegalBlockSizeException, BadPaddingException {
1319                    checkInitialization();
1320                    int retVal = super.doFinalInternal(output, outputOffset, maximumLen);
1321                    if (isEncrypting()) {
1322                        mustInitialize = true;
1323                    }
1324                    return retVal;
1325                }
1326
1327                @Override
1328                protected void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) {
1329                    checkInitialization();
1330                    super.engineUpdateAAD(input, inputOffset, inputLen);
1331                }
1332
1333                @Override
1334                void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
1335                    if (mode != Mode.GCM) {
1336                        throw new NoSuchAlgorithmException("Mode must be GCM");
1337                    }
1338                }
1339
1340                @Override
1341                long getEVP_AEAD(int keyLength) throws InvalidKeyException {
1342                    if (keyLength == 16) {
1343                        return NativeCrypto.EVP_aead_aes_128_gcm();
1344                    } else if (keyLength == 32) {
1345                        return NativeCrypto.EVP_aead_aes_256_gcm();
1346                    } else {
1347                        throw new RuntimeException("Unexpected key length: " + keyLength);
1348                    }
1349                }
1350
1351                public static class AES_128 extends GCM {
1352                    @Override
1353                    void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
1354                        if (keyLength != 16) { // 128 bits
1355                            throw new InvalidKeyException(
1356                                    "Unsupported key size: " + keyLength + " bytes (must be 16)");
1357                        }
1358                    }
1359                }
1360
1361                public static class AES_256 extends GCM {
1362                    @Override
1363                    void checkSupportedKeySize(int keyLength) throws InvalidKeyException {
1364                        if (keyLength != 32) { // 256 bits
1365                            throw new InvalidKeyException(
1366                                    "Unsupported key size: " + keyLength + " bytes (must be 32)");
1367                        }
1368                    }
1369                }
1370            }
1371        }
1372    }
1373}
1374