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