Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2015 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 android.keystore.cts;
     18 
     19 import android.security.keystore.KeyProperties;
     20 import android.security.keystore.KeyProtection;
     21 import android.test.AndroidTestCase;
     22 
     23 import junit.framework.AssertionFailedError;
     24 
     25 import java.nio.Buffer;
     26 import java.nio.ByteBuffer;
     27 import java.security.AlgorithmParameters;
     28 import java.security.InvalidAlgorithmParameterException;
     29 import java.security.InvalidKeyException;
     30 import java.security.Key;
     31 import java.security.KeyStore;
     32 import java.security.NoSuchAlgorithmException;
     33 import java.security.NoSuchProviderException;
     34 import java.security.Provider;
     35 import java.security.SecureRandom;
     36 import java.security.Security;
     37 import java.security.spec.AlgorithmParameterSpec;
     38 import java.security.spec.InvalidParameterSpecException;
     39 import java.util.Arrays;
     40 import java.util.Enumeration;
     41 import java.util.Locale;
     42 
     43 import javax.crypto.BadPaddingException;
     44 import javax.crypto.Cipher;
     45 import javax.crypto.IllegalBlockSizeException;
     46 import javax.crypto.NoSuchPaddingException;
     47 import javax.crypto.SecretKey;
     48 import javax.crypto.ShortBufferException;
     49 import javax.crypto.spec.IvParameterSpec;
     50 import javax.crypto.spec.SecretKeySpec;
     51 
     52 abstract class BlockCipherTestBase extends AndroidTestCase {
     53 
     54     private static final String EXPECTED_PROVIDER_NAME = TestUtils.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
     55 
     56     private KeyStore mAndroidKeyStore;
     57     private int mNextKeyId;
     58 
     59     @Override
     60     protected void setUp() throws Exception {
     61         super.setUp();
     62         mAndroidKeyStore = KeyStore.getInstance("AndroidKeyStore");
     63         mAndroidKeyStore.load(null);
     64         for (Enumeration<String> e = mAndroidKeyStore.aliases(); e.hasMoreElements();) {
     65             mAndroidKeyStore.deleteEntry(e.nextElement());
     66         }
     67     }
     68 
     69     @Override
     70     protected void tearDown() throws Exception {
     71         try {
     72             for (Enumeration<String> e = mAndroidKeyStore.aliases(); e.hasMoreElements();) {
     73                 mAndroidKeyStore.deleteEntry(e.nextElement());
     74             }
     75         } finally {
     76             super.tearDown();
     77         }
     78     }
     79 
     80     protected abstract String getTransformation();
     81     protected abstract int getBlockSize();
     82 
     83     protected abstract byte[] getKatKey();
     84     protected abstract byte[] getKatIv();
     85     protected abstract AlgorithmParameterSpec getKatAlgorithmParameterSpec();
     86     protected abstract byte[] getKatPlaintext();
     87     protected abstract byte[] getKatCiphertext();
     88     protected abstract int getKatAuthenticationTagLengthBytes();
     89     protected abstract boolean isStreamCipher();
     90     protected abstract boolean isAuthenticatedCipher();
     91 
     92     protected abstract byte[] getIv(AlgorithmParameters params)
     93             throws InvalidParameterSpecException;
     94 
     95     private byte[] getKatInput(int opmode) {
     96         switch (opmode) {
     97             case Cipher.ENCRYPT_MODE:
     98                 return getKatPlaintext();
     99             case Cipher.DECRYPT_MODE:
    100                 return getKatCiphertext();
    101             default:
    102                 throw new IllegalArgumentException("Invalid opmode: " + opmode);
    103         }
    104     }
    105 
    106     private byte[] getKatOutput(int opmode) {
    107         switch (opmode) {
    108             case Cipher.ENCRYPT_MODE:
    109                 return getKatCiphertext();
    110             case Cipher.DECRYPT_MODE:
    111                 return getKatPlaintext();
    112             default:
    113                 throw new IllegalArgumentException("Invalid opmode: " + opmode);
    114         }
    115     }
    116 
    117     private Cipher mCipher;
    118     private int mOpmode;
    119 
    120     public void testGetAlgorithm() throws Exception {
    121         createCipher();
    122         assertEquals(getTransformation(), mCipher.getAlgorithm());
    123     }
    124 
    125     public void testGetProvider() throws Exception {
    126         createCipher();
    127         Provider expectedProvider = Security.getProvider(EXPECTED_PROVIDER_NAME);
    128         assertSame(expectedProvider, mCipher.getProvider());
    129     }
    130 
    131     public void testGetBlockSize() throws Exception {
    132         createCipher();
    133         assertEquals(getBlockSize(), mCipher.getBlockSize());
    134     }
    135 
    136     public void testGetExemptionMechanism() throws Exception {
    137         createCipher();
    138         assertNull(mCipher.getExemptionMechanism());
    139     }
    140 
    141     public void testGetParameters() throws Exception {
    142         createCipher();
    143         assertAlgoritmParametersIv(null);
    144 
    145         initKat(Cipher.ENCRYPT_MODE);
    146         assertAlgoritmParametersIv(getKatIv());
    147         doFinal(getKatPlaintext());
    148         assertAlgoritmParametersIv(getKatIv());
    149 
    150         initKat(Cipher.DECRYPT_MODE);
    151         assertAlgoritmParametersIv(getKatIv());
    152         doFinal(getKatCiphertext());
    153         assertAlgoritmParametersIv(getKatIv());
    154     }
    155 
    156     private void assertAlgoritmParametersIv(byte[] expectedIv)
    157             throws InvalidParameterSpecException {
    158         AlgorithmParameters actualParameters = mCipher.getParameters();
    159         if (expectedIv == null) {
    160             assertNull(actualParameters);
    161         } else {
    162             byte[] actualIv = getIv(actualParameters);
    163             assertEquals(expectedIv, actualIv);
    164         }
    165     }
    166 
    167     public void testGetOutputSizeInEncryptionMode() throws Exception {
    168         int blockSize = getBlockSize();
    169         createCipher();
    170         try {
    171             mCipher.getOutputSize(blockSize);
    172             fail();
    173         } catch (IllegalStateException expected) {}
    174 
    175         initKat(Cipher.ENCRYPT_MODE);
    176         if (isAuthenticatedCipher()) {
    177             // Authenticated ciphers do not return any output when decrypting until doFinal where
    178             // ciphertext is authenticated.
    179             for (int input = 0; input <= blockSize * 2; input++) {
    180                 int actualOutputSize = mCipher.getOutputSize(input);
    181                 int expectedOutputSize = input + getKatAuthenticationTagLengthBytes();
    182                 if (actualOutputSize < expectedOutputSize) {
    183                     fail("getOutputSize(" + expectedOutputSize + ") underestimated output size"
    184                             + ". min expected: <" + expectedOutputSize
    185                             + ">, actual: <" + actualOutputSize + ">");
    186                 }
    187             }
    188             return;
    189         } else if (isStreamCipher()) {
    190             // Unauthenticated stream ciphers do not buffer input or output.
    191             for (int input = 0; input <= blockSize * 2; input++) {
    192                 int actualOutputSize = mCipher.getOutputSize(input);
    193                 if (actualOutputSize < input) {
    194                     fail("getOutputSize(" + input + ") underestimated output size. min expected: <"
    195                             + input + ">, actual: <" + actualOutputSize + ">");
    196                 }
    197             }
    198             return;
    199         }
    200         // Not a stream cipher -- input may be buffered.
    201 
    202         for (int buffered = 0; buffered < blockSize; buffered++) {
    203             // Assert that the output of getOutputSize is not lower than the minimum expected.
    204             for (int input = 0; input <= blockSize * 2; input++) {
    205                 int inputInclBuffered = buffered + input;
    206                 // doFinal dominates the output size.
    207                 // One full plaintext block results in one ciphertext block.
    208                 int minExpectedOutputSize = inputInclBuffered - (inputInclBuffered % blockSize);
    209                 if (isPaddingEnabled()) {
    210                     // Regardless of whether there is a partial input block, an additional block of
    211                     // ciphertext should be output.
    212                     minExpectedOutputSize += blockSize;
    213                 } else {
    214                     // When no padding is enabled, any remaining partial block of plaintext will
    215                     // cause an error. Thus, there's no need to account for its ciphertext.
    216                 }
    217                 int actualOutputSize = mCipher.getOutputSize(input);
    218                 if (actualOutputSize < minExpectedOutputSize) {
    219                     fail("getOutputSize(" + input + ") underestimated output size when buffered == "
    220                             + buffered + ". min expected: <"
    221                             + minExpectedOutputSize + ">, actual: <" + actualOutputSize + ">");
    222                 }
    223             }
    224 
    225             if (buffered == blockSize - 1) {
    226                 break;
    227             }
    228             // Buffer one more byte of input.
    229             assertNull("buffered: " + buffered, update(new byte[1]));
    230         }
    231     }
    232 
    233     public void testGetOutputSizeInDecryptionMode() throws Exception {
    234         int blockSize = getBlockSize();
    235         createCipher();
    236         try {
    237             mCipher.getOutputSize(blockSize);
    238             fail();
    239         } catch (IllegalStateException expected) {}
    240 
    241         initKat(Cipher.DECRYPT_MODE);
    242         if ((!isAuthenticatedCipher()) && (isStreamCipher())) {
    243             // Unauthenticated stream ciphers do not buffer input or output.
    244             for (int input = 0; input <= blockSize * 2; input++) {
    245                 int actualOutputSize = mCipher.getOutputSize(input);
    246                 int expectedOutputSize = input;
    247                 if (actualOutputSize < expectedOutputSize) {
    248                     fail("getOutputSize(" + expectedOutputSize + ") underestimated output size"
    249                             + ". min expected: <" + expectedOutputSize
    250                             + ">, actual: <" + actualOutputSize + ">");
    251                 }
    252             }
    253             return;
    254         }
    255         // Input may be buffered.
    256 
    257         for (int buffered = 0; buffered < blockSize; buffered++) {
    258             // Assert that the output of getOutputSize is not lower than the minimum expected.
    259             for (int input = 0; input <= blockSize * 2; input++) {
    260                 int inputInclBuffered = buffered + input;
    261                 // doFinal dominates the output size.
    262                 int minExpectedOutputSize;
    263                 if (isAuthenticatedCipher()) {
    264                     // Non-stream authenticated ciphers not supported
    265                     assertTrue(isStreamCipher());
    266 
    267                     // Authenticated stream cipher
    268                     minExpectedOutputSize =
    269                             inputInclBuffered - getKatAuthenticationTagLengthBytes();
    270                 } else {
    271                     // Unauthenticated block cipher.
    272 
    273                     // One full ciphertext block results in one ciphertext block.
    274                     minExpectedOutputSize = inputInclBuffered - (inputInclBuffered % blockSize);
    275                     if (isPaddingEnabled()) {
    276                         if ((inputInclBuffered % blockSize) == 0) {
    277                             // No more ciphertext remaining. Thus, the last plaintext block is at
    278                             // most blockSize - 1 bytes long.
    279                             minExpectedOutputSize--;
    280                         } else {
    281                             // Partial ciphertext block cannot be decrypted. Thus, the last
    282                             // plaintext block would not have been output.
    283                             minExpectedOutputSize -= blockSize;
    284                         }
    285                     } else {
    286                         // When no padding is enabled, any remaining ciphertext will cause a error
    287                         // because only full blocks can be decrypted. Thus, there's no need to
    288                         // account for its plaintext.
    289                     }
    290                 }
    291                 if (minExpectedOutputSize < 0) {
    292                     minExpectedOutputSize = 0;
    293                 }
    294                 int actualOutputSize = mCipher.getOutputSize(input);
    295                 if (actualOutputSize < minExpectedOutputSize) {
    296                     fail("getOutputSize(" + input + ") underestimated output size when buffered == "
    297                             + buffered + ". min expected: <"
    298                             + minExpectedOutputSize + ">, actual: <" + actualOutputSize + ">");
    299                 }
    300             }
    301 
    302             if (buffered == blockSize - 1) {
    303                 break;
    304             }
    305             // Buffer one more byte of input.
    306             assertNull("buffered: " + buffered, update(new byte[1]));
    307         }
    308     }
    309 
    310     public void testInitRequiresIvInDecryptMode() throws Exception {
    311         if (getKatIv() == null) {
    312             // IV not used in this transformation.
    313             return;
    314         }
    315 
    316         createCipher();
    317         try {
    318             init(Cipher.DECRYPT_MODE, getKey());
    319             fail();
    320         } catch (InvalidKeyException expected) {}
    321 
    322         createCipher();
    323         try {
    324             init(Cipher.DECRYPT_MODE, getKey(), (SecureRandom) null);
    325             fail();
    326         } catch (InvalidKeyException expected) {}
    327 
    328         createCipher();
    329         try {
    330             init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameterSpec) null, null);
    331             fail();
    332         } catch (InvalidAlgorithmParameterException expected) {}
    333 
    334         createCipher();
    335         try {
    336             init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameterSpec) null, null);
    337             fail();
    338         } catch (InvalidAlgorithmParameterException expected) {}
    339 
    340         createCipher();
    341         try {
    342             init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameters) null, null);
    343             fail();
    344         } catch (InvalidAlgorithmParameterException expected) {}
    345 
    346         createCipher();
    347         try {
    348             init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameters) null, null);
    349             fail();
    350         } catch (InvalidAlgorithmParameterException expected) {}
    351     }
    352 
    353     public void testGetIV() throws Exception {
    354         createCipher();
    355         assertNull(mCipher.getIV());
    356 
    357         initKat(Cipher.ENCRYPT_MODE);
    358         assertEquals(getKatIv(), mCipher.getIV());
    359 
    360         byte[] ciphertext = doFinal(new byte[getBlockSize()]);
    361         assertEquals(getKatIv(), mCipher.getIV());
    362 
    363         createCipher();
    364         initKat(Cipher.DECRYPT_MODE);
    365         assertEquals(getKatIv(), mCipher.getIV());
    366 
    367         doFinal(ciphertext);
    368         assertEquals(getKatIv(), mCipher.getIV());
    369     }
    370 
    371     public void testIvGeneratedAndUsedWhenEncryptingWithoutExplicitIv() throws Exception {
    372         createCipher();
    373         SecretKey key = getKey();
    374         init(Cipher.ENCRYPT_MODE, key);
    375         byte[] generatedIv = mCipher.getIV();
    376         AlgorithmParameters generatedParams = mCipher.getParameters();
    377         if (getKatIv() == null) {
    378             // IV not needed by this transformation -- shouldn't have been generated by Cipher.init
    379             assertNull(generatedIv);
    380             assertNull(generatedParams);
    381         } else {
    382             // IV is needed by this transformation -- should've been generated by Cipher.init
    383             assertNotNull(generatedIv);
    384             assertEquals(getKatIv().length, generatedIv.length);
    385             assertNotNull(generatedParams);
    386             assertEquals(generatedIv, getIv(generatedParams));
    387         }
    388 
    389         // Assert that encrypting then decrypting using the above IV (or null) results in the
    390         // original plaintext.
    391         byte[] plaintext = new byte[getBlockSize()];
    392         byte[] ciphertext = doFinal(plaintext);
    393         createCipher();
    394         init(Cipher.DECRYPT_MODE, key, generatedParams);
    395         byte[] decryptedPlaintext = mCipher.doFinal(ciphertext);
    396         assertEquals(plaintext, decryptedPlaintext);
    397     }
    398 
    399     public void testGeneratedIvSurvivesReset() throws Exception {
    400         if (getKatIv() == null) {
    401             // This transformation does not use an IV
    402             return;
    403         }
    404 
    405         createCipher();
    406         init(Cipher.ENCRYPT_MODE, getKey());
    407         byte[] iv = mCipher.getIV();
    408         AlgorithmParameters generatedParams = mCipher.getParameters();
    409         byte[] ciphertext = mCipher.doFinal(getKatPlaintext());
    410         // Assert that the IV is still there
    411         assertEquals(iv, mCipher.getIV());
    412         assertAlgoritmParametersIv(iv);
    413 
    414         if (getKatIv() != null) {
    415             // We try to prevent IV reuse by not letting the Cipher be reused.
    416             return;
    417         }
    418 
    419         // Assert that encrypting the same input after the above reset produces the same ciphertext.
    420         assertEquals(ciphertext, mCipher.doFinal(getKatPlaintext()));
    421 
    422         assertEquals(iv, mCipher.getIV());
    423         assertAlgoritmParametersIv(iv);
    424 
    425         // Just in case, test with a new instance of Cipher with the same parameters
    426         createCipher();
    427         init(Cipher.ENCRYPT_MODE, getKey(), generatedParams);
    428         assertEquals(ciphertext, mCipher.doFinal(getKatPlaintext()));
    429     }
    430 
    431     public void testGeneratedIvDoesNotSurviveReinitialization() throws Exception {
    432         if (getKatIv() == null) {
    433             // This transformation does not use an IV
    434             return;
    435         }
    436 
    437         createCipher();
    438         init(Cipher.ENCRYPT_MODE, getKey());
    439         byte[] ivBeforeReinitialization = mCipher.getIV();
    440 
    441         init(Cipher.ENCRYPT_MODE, getKey());
    442         // A new IV should've been generated
    443         if (Arrays.equals(ivBeforeReinitialization, mCipher.getIV())) {
    444             fail("Same auto-generated IV after Cipher reinitialized."
    445                     + " Broken implementation or you're very unlucky (p: 2^{-"
    446                     + (ivBeforeReinitialization.length * 8) + "})");
    447         }
    448     }
    449 
    450     public void testExplicitlySetIvDoesNotSurviveReinitialization() throws Exception {
    451         if (getKatIv() == null) {
    452             // This transformation does not use an IV
    453             return;
    454         }
    455 
    456         createCipher();
    457         initKat(Cipher.ENCRYPT_MODE);
    458         init(Cipher.ENCRYPT_MODE, getKey());
    459         // A new IV should've been generated
    460         if (Arrays.equals(getKatIv(), mCipher.getIV())) {
    461             fail("Auto-generated IV after Cipher reinitialized is the same as previous IV."
    462                     + " Broken implementation or you're very unlucky (p: 2^{-"
    463                     + (getKatIv().length * 8) + "})");
    464         }
    465     }
    466 
    467     public void testReinitializingInDecryptModeDoesNotUsePreviouslyUsedIv() throws Exception {
    468         if (getKatIv() == null) {
    469             // This transformation does not use an IV
    470             return;
    471         }
    472 
    473         createCipher();
    474         // Initialize with explicitly provided IV
    475         init(Cipher.ENCRYPT_MODE, getKey(), getKatAlgorithmParameterSpec());
    476         // Make sure the IV has been used, just in case it's set/cached lazily.
    477         mCipher.update(new byte[getBlockSize() * 2]);
    478 
    479         // IV required but not provided
    480         try {
    481             init(Cipher.DECRYPT_MODE, getKey());
    482             fail();
    483         } catch (InvalidKeyException expected) {}
    484 
    485         createCipher();
    486         // Initialize with a generated IV
    487         init(Cipher.ENCRYPT_MODE, getKey());
    488         mCipher.doFinal(getKatPlaintext());
    489 
    490         // IV required but not provided
    491         try {
    492             init(Cipher.DECRYPT_MODE, getKey());
    493             fail();
    494         } catch (InvalidKeyException expected) {}
    495 
    496         // IV required but not provided
    497         try {
    498             init(Cipher.DECRYPT_MODE, getKey(), (SecureRandom) null);
    499             fail();
    500         } catch (InvalidKeyException expected) {}
    501 
    502         // IV required but not provided
    503         try {
    504             init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameterSpec) null);
    505             fail();
    506         } catch (InvalidAlgorithmParameterException expected) {}
    507 
    508         // IV required but not provided
    509         try {
    510             init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameterSpec) null, null);
    511             fail();
    512         } catch (InvalidAlgorithmParameterException expected) {}
    513 
    514         // IV required but not provided
    515         try {
    516             init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameters) null);
    517             fail();
    518         } catch (InvalidAlgorithmParameterException expected) {}
    519 
    520         // IV required but not provided
    521         try {
    522             init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameters) null, null);
    523             fail();
    524         } catch (InvalidAlgorithmParameterException expected) {}
    525     }
    526 
    527     public void testKeyDoesNotSurviveReinitialization() throws Exception {
    528         assertKeyDoesNotSurviveReinitialization(Cipher.ENCRYPT_MODE);
    529         assertKeyDoesNotSurviveReinitialization(Cipher.DECRYPT_MODE);
    530     }
    531 
    532     private void assertKeyDoesNotSurviveReinitialization(int opmode) throws Exception {
    533         byte[] input = getKatInput(opmode);
    534         createCipher();
    535         byte[] katKeyBytes = getKatKey();
    536         SecretKey key1 = importKey(katKeyBytes);
    537         init(opmode, key1, getKatAlgorithmParameterSpec());
    538         byte[] output1 = doFinal(input);
    539 
    540         // Create a different key by flipping a bit in the KAT key.
    541         katKeyBytes[0] ^= 0b1000; // Flip a bit that _does_ affect 3DES
    542         SecretKey key2 = importKey(katKeyBytes);
    543 
    544         init(opmode, key2, getKatAlgorithmParameterSpec());
    545         byte[] output2;
    546         try {
    547             output2 = doFinal(input);
    548         } catch (BadPaddingException expected) {
    549             // Padding doesn't decode probably because the new key is being used. This can only
    550             // occur if padding is used.
    551             return;
    552         }
    553 
    554         // Either padding wasn't used or the old key was used.
    555         if (Arrays.equals(output1, output2)) {
    556             fail("Same output when reinitialized with a different key. opmode: " + opmode);
    557         }
    558     }
    559 
    560     public void testDoFinalResets() throws Exception {
    561         assertDoFinalResetsCipher(Cipher.DECRYPT_MODE);
    562         assertDoFinalResetsCipher(Cipher.ENCRYPT_MODE);
    563     }
    564 
    565     private void assertDoFinalResetsCipher(int opmode) throws Exception {
    566         byte[] input = getKatInput(opmode);
    567         byte[] expectedOutput = getKatOutput(opmode);
    568 
    569         createCipher();
    570         initKat(opmode);
    571         assertEquals(expectedOutput, doFinal(input));
    572 
    573         if ((opmode == Cipher.ENCRYPT_MODE) && (getKatIv() != null)) {
    574             // Assert that this cipher cannot be reused (thus making IV reuse harder)
    575             try {
    576                 doFinal(input);
    577                 fail();
    578             } catch (IllegalStateException expected) {}
    579             return;
    580         }
    581 
    582         // Assert that the same output is produced after the above reset
    583         assertEquals(expectedOutput, doFinal(input));
    584 
    585         // Assert that the same output is produced after the above reset. This time, make update()
    586         // buffer half a block of input.
    587         if (input.length < getBlockSize() * 2) {
    588             fail("This test requires an input which is at least two blocks long");
    589         }
    590         assertEquals(expectedOutput, concat(
    591                 update(subarray(input, 0, getBlockSize() * 3 / 2)),
    592                 doFinal(subarray(input, getBlockSize() * 3 / 2, input.length))));
    593 
    594         // Assert that the same output is produced after the above reset, despite half of the block
    595         // having been buffered prior to the reset. This is in case the implementation does not
    596         // empty that buffer when resetting.
    597         assertEquals(expectedOutput, doFinal(input));
    598 
    599         // Assert that the IV with which the cipher was initialized is still there after the resets.
    600         assertEquals(getKatIv(), mCipher.getIV());
    601         assertAlgoritmParametersIv(getKatIv());
    602     }
    603 
    604     public void testUpdateWithEmptyInputReturnsCorrectValue() throws Exception {
    605         // Test encryption
    606         createCipher();
    607         initKat(Cipher.ENCRYPT_MODE);
    608         assertUpdateWithEmptyInputReturnsNull();
    609 
    610         // Test decryption
    611         createCipher();
    612         initKat(Cipher.DECRYPT_MODE);
    613         assertUpdateWithEmptyInputReturnsNull();
    614     }
    615 
    616     private void assertUpdateWithEmptyInputReturnsNull() {
    617         assertEquals(null, update(new byte[0]));
    618         assertEquals(null, update(new byte[getBlockSize() * 2], getBlockSize(), 0));
    619         assertEquals(null, update(new byte[getBlockSize()], 0, 0));
    620 
    621         // Feed two blocks through the Cipher, so that it's in a state where a block of input
    622         // produces a block of output.
    623         // Two blocks are used instead of one because when decrypting with padding enabled, output
    624         // lags behind input by a block because the Cipher doesn't know whether the most recent
    625         // input block was supposed to contain padding.
    626         update(new byte[getBlockSize() * 2]);
    627 
    628         assertEquals(null, update(new byte[0]));
    629         assertEquals(null, update(new byte[getBlockSize() * 2], getBlockSize(), 0));
    630         assertEquals(null, update(new byte[getBlockSize()], 0, 0));
    631     }
    632 
    633     public void testUpdateDoesNotProduceOutputWhenInsufficientInput() throws Exception {
    634         if (isStreamCipher()) {
    635             // Stream ciphers always produce output for non-empty input.
    636             return;
    637         }
    638 
    639         // Test encryption
    640         createCipher();
    641         initKat(Cipher.ENCRYPT_MODE);
    642         assertUpdateDoesNotProduceOutputWhenInsufficientInput();
    643 
    644         // Test decryption
    645         createCipher();
    646         initKat(Cipher.DECRYPT_MODE);
    647         assertUpdateDoesNotProduceOutputWhenInsufficientInput();
    648     }
    649 
    650     private void assertUpdateDoesNotProduceOutputWhenInsufficientInput() throws Exception {
    651         if (getBlockSize() < 8) {
    652             fail("This test isn't designed for small block size: " + getBlockSize());
    653         }
    654 
    655         assertEquals(null, update(new byte[1]));
    656         assertEquals(null, update(new byte[1], 0, 1));
    657         assertEquals(0, update(new byte[1], 0, 1, new byte[getBlockSize()]));
    658         assertEquals(0, update(new byte[1], 0, 1, new byte[getBlockSize()], 0));
    659         assertEquals(0, update(ByteBuffer.allocate(1), ByteBuffer.allocate(getBlockSize())));
    660 
    661         // Complete the current block. There are blockSize - 4 bytes left to fill.
    662         byte[] output = update(new byte[getBlockSize() - 4]);
    663         assertEquals(getBlockSize(), output.length);
    664 
    665         assertEquals(null, update(new byte[1]));
    666         assertEquals(null, update(new byte[1], 0, 1));
    667         assertEquals(0, update(new byte[1], 0, 1, new byte[getBlockSize()]));
    668         assertEquals(0, update(new byte[1], 0, 1, new byte[getBlockSize()], 0));
    669         assertEquals(0, update(ByteBuffer.allocate(1), ByteBuffer.allocate(getBlockSize())));
    670     }
    671 
    672     public void testKatOneShotEncryptUsingDoFinal() throws Exception {
    673         createCipher();
    674         assertKatOneShotTransformUsingDoFinal(
    675                 Cipher.ENCRYPT_MODE, getKatPlaintext(), getKatCiphertext());
    676     }
    677 
    678     public void testKatOneShotDecryptUsingDoFinal() throws Exception {
    679         createCipher();
    680         assertKatOneShotTransformUsingDoFinal(
    681                 Cipher.DECRYPT_MODE, getKatCiphertext(), getKatPlaintext());
    682     }
    683 
    684     private void assertKatOneShotTransformUsingDoFinal(
    685             int opmode, byte[] input, byte[] expectedOutput) throws Exception {
    686         int bufferWithInputInTheMiddleCleartextOffset = 5;
    687         byte[] bufferWithInputInTheMiddle = concat(
    688                 new byte[bufferWithInputInTheMiddleCleartextOffset],
    689                 input,
    690                 new byte[4]);
    691 
    692         initKat(opmode);
    693         assertEquals(expectedOutput, doFinal(input));
    694         initKat(opmode);
    695         assertEquals(expectedOutput, doFinal(input, 0, input.length));
    696         initKat(opmode);
    697         assertEquals(expectedOutput,
    698                 doFinal(bufferWithInputInTheMiddle,
    699                         bufferWithInputInTheMiddleCleartextOffset,
    700                         input.length));
    701 
    702         ByteBuffer inputBuffer = ByteBuffer.wrap(
    703                 bufferWithInputInTheMiddle,
    704                 bufferWithInputInTheMiddleCleartextOffset,
    705                 input.length);
    706         ByteBuffer actualOutputBuffer = ByteBuffer.allocate(expectedOutput.length);
    707         initKat(opmode);
    708         assertEquals(expectedOutput.length, doFinal(inputBuffer, actualOutputBuffer));
    709         assertEquals(0, inputBuffer.remaining());
    710         assertByteBufferEquals(
    711                 (ByteBuffer) ByteBuffer.wrap(expectedOutput).position(expectedOutput.length),
    712                 actualOutputBuffer);
    713     }
    714 
    715     public void testKatEncryptOneByteAtATime() throws Exception {
    716         createCipher();
    717         initKat(Cipher.ENCRYPT_MODE);
    718         byte[] plaintext = getKatPlaintext();
    719         byte[] expectedCiphertext = getKatCiphertext();
    720         int blockSize = getBlockSize();
    721         if (isStreamCipher()) {
    722             // Stream cipher -- one byte in, one byte out
    723             for (int plaintextIndex = 0; plaintextIndex < plaintext.length; plaintextIndex++) {
    724                 byte[] output = update(new byte[] {plaintext[plaintextIndex]});
    725                 assertEquals("plaintext index: " + plaintextIndex, 1, output.length);
    726                 assertEquals("plaintext index: " + plaintextIndex,
    727                         expectedCiphertext[plaintextIndex], output[0]);
    728             }
    729             byte[] finalOutput = doFinal();
    730             byte[] expectedFinalOutput;
    731             if (isAuthenticatedCipher()) {
    732                 expectedFinalOutput =
    733                         subarray(expectedCiphertext, plaintext.length, expectedCiphertext.length);
    734             } else {
    735                 expectedFinalOutput = EmptyArray.BYTE;
    736             }
    737             assertEquals(expectedFinalOutput, finalOutput);
    738         } else {
    739             // Not a stream cipher -- operates on full blocks only.
    740 
    741             // Assert that a block of output is produced once a full block of input is provided.
    742             // Every input block produces an output block.
    743             int ciphertextIndex = 0;
    744             for (int plaintextIndex = 0; plaintextIndex < plaintext.length; plaintextIndex++) {
    745                 byte[] output = update(new byte[] {plaintext[plaintextIndex]});
    746                 if ((plaintextIndex % blockSize) == blockSize - 1) {
    747                     // Cipher.update is expected to have output a new block
    748                     assertEquals(
    749                             "plaintext index: " + plaintextIndex,
    750                             subarray(
    751                                     expectedCiphertext,
    752                                     ciphertextIndex,
    753                                     ciphertextIndex + blockSize),
    754                             output);
    755                 } else {
    756                     // Cipher.update is expected to have produced no output
    757                     assertEquals("plaintext index: " + plaintextIndex, null, output);
    758                 }
    759                 if (output != null) {
    760                     ciphertextIndex += output.length;
    761                 }
    762             }
    763 
    764             byte[] actualFinalOutput = doFinal();
    765             byte[] expectedFinalOutput =
    766                     subarray(expectedCiphertext, ciphertextIndex, expectedCiphertext.length);
    767             assertEquals(expectedFinalOutput, actualFinalOutput);
    768         }
    769     }
    770 
    771     public void testKatDecryptOneByteAtATime() throws Exception {
    772         createCipher();
    773         initKat(Cipher.DECRYPT_MODE);
    774         byte[] ciphertext = getKatCiphertext();
    775         int plaintextIndex = 0;
    776         int blockSize = getBlockSize();
    777         byte[] expectedPlaintext = getKatPlaintext();
    778         boolean paddingEnabled = isPaddingEnabled();
    779         if (isAuthenticatedCipher()) {
    780             // Authenticated cipher -- no output until doFinal where ciphertext is authenticated.
    781             for (int ciphertextIndex = 0; ciphertextIndex < ciphertext.length; ciphertextIndex++) {
    782                 byte[] output = update(new byte[] {ciphertext[ciphertextIndex]});
    783                 assertEquals("ciphertext index: " + ciphertextIndex,
    784                         0, (output != null) ? output.length : 0);
    785             }
    786             byte[] finalOutput = doFinal();
    787             assertEquals(expectedPlaintext, finalOutput);
    788         } else if (isStreamCipher()) {
    789             // Unauthenticated stream cipher -- one byte in, one byte out
    790             for (int ciphertextIndex = 0; ciphertextIndex < ciphertext.length; ciphertextIndex++) {
    791                 byte[] output = update(new byte[] {ciphertext[ciphertextIndex]});
    792                 assertEquals("ciphertext index: " + ciphertextIndex, 1, output.length);
    793                 assertEquals("ciphertext index: " + ciphertextIndex,
    794                         expectedPlaintext[ciphertextIndex], output[0]);
    795             }
    796             byte[] finalOutput = doFinal();
    797             assertEquals(0, finalOutput.length);
    798         } else {
    799             // Unauthenticated block cipher -- operates in full blocks only
    800 
    801             // Assert that a block of output is produced once a full block of input is provided.
    802             // When padding is used, output is produced one input byte later: once the first byte of the
    803             // next input block is provided.
    804             for (int ciphertextIndex = 0; ciphertextIndex < ciphertext.length; ciphertextIndex++) {
    805                 byte[] output = update(new byte[] {ciphertext[ciphertextIndex]});
    806                 boolean outputExpected =
    807                         ((paddingEnabled)
    808                                 && (ciphertextIndex > 0) && ((ciphertextIndex % blockSize) == 0))
    809                         || ((!paddingEnabled) && ((ciphertextIndex % blockSize) == blockSize - 1));
    810 
    811                 if (outputExpected) {
    812                     assertEquals(
    813                             "ciphertext index: " + ciphertextIndex,
    814                             subarray(expectedPlaintext, plaintextIndex, plaintextIndex + blockSize),
    815                             output);
    816                 } else {
    817                     assertEquals("ciphertext index: " + ciphertextIndex, null, output);
    818                 }
    819 
    820                 if (output != null) {
    821                     plaintextIndex += output.length;
    822                 }
    823             }
    824 
    825             byte[] actualFinalOutput = doFinal();
    826             byte[] expectedFinalOutput =
    827                     subarray(expectedPlaintext, plaintextIndex, expectedPlaintext.length);
    828             assertEquals(expectedFinalOutput, actualFinalOutput);
    829         }
    830     }
    831 
    832     public void testUpdateAADNotSupported() throws Exception {
    833         if (isAuthenticatedCipher()) {
    834             // Not applicable to authenticated ciphers where updateAAD is supported.
    835             return;
    836         }
    837 
    838         createCipher();
    839         initKat(Cipher.ENCRYPT_MODE);
    840         assertUpdateAADNotSupported();
    841 
    842         createCipher();
    843         initKat(Cipher.DECRYPT_MODE);
    844         assertUpdateAADNotSupported();
    845     }
    846 
    847     public void testUpdateAADSupported() throws Exception {
    848         if (!isAuthenticatedCipher()) {
    849             // Not applicable to unauthenticated ciphers where updateAAD is not supported.
    850             return;
    851         }
    852 
    853         createCipher();
    854         initKat(Cipher.ENCRYPT_MODE);
    855         assertUpdateAADSupported();
    856 
    857         createCipher();
    858         initKat(Cipher.DECRYPT_MODE);
    859         assertUpdateAADSupported();
    860     }
    861 
    862     private void assertUpdateAADNotSupported() throws Exception {
    863         try {
    864             mCipher.updateAAD(new byte[getBlockSize()]);
    865             fail();
    866         } catch (UnsupportedOperationException expected) {
    867         } catch (IllegalStateException expected) {}
    868 
    869         try {
    870             mCipher.updateAAD(new byte[getBlockSize()], 0, getBlockSize());
    871             fail();
    872         } catch (UnsupportedOperationException expected) {
    873         } catch (IllegalStateException expected) {}
    874 
    875         try {
    876             mCipher.updateAAD(ByteBuffer.allocate(getBlockSize()));
    877             fail();
    878         } catch (UnsupportedOperationException expected) {
    879         } catch (IllegalStateException expected) {}
    880     }
    881 
    882     private void assertUpdateAADSupported() throws Exception {
    883         mCipher.updateAAD(new byte[getBlockSize()]);
    884         mCipher.updateAAD(new byte[getBlockSize()], 0, getBlockSize());
    885         mCipher.updateAAD(ByteBuffer.allocate(getBlockSize()));
    886     }
    887 
    888     // TODO: Add tests for WRAP and UNWRAP
    889 
    890     public void testUpdateAndDoFinalNotSupportedInWrapAndUnwrapModes() throws Exception {
    891         createCipher();
    892         assertUpdateAndDoFinalThrowIllegalStateExceprtion(
    893                 Cipher.WRAP_MODE, getKey(), getKatAlgorithmParameterSpec());
    894 
    895         createCipher();
    896         assertUpdateAndDoFinalThrowIllegalStateExceprtion(
    897                 Cipher.UNWRAP_MODE, getKey(), getKatAlgorithmParameterSpec());
    898     }
    899 
    900     private void assertUpdateAndDoFinalThrowIllegalStateExceprtion(
    901             int opmode, SecretKey key, AlgorithmParameterSpec paramSpec)
    902             throws Exception {
    903         try {
    904             init(opmode, key, paramSpec);
    905         } catch (UnsupportedOperationException e) {
    906             // Skip this test because wrap/unwrap is not supported by this Cipher
    907             return;
    908         }
    909 
    910         try {
    911             update(new byte[getBlockSize()]);
    912             fail();
    913         } catch (IllegalStateException expected) {}
    914 
    915         init(opmode, key, paramSpec);
    916         try {
    917             update(new byte[getBlockSize()], 0, getBlockSize());
    918             fail();
    919         } catch (IllegalStateException expected) {}
    920 
    921         init(opmode, key, paramSpec);
    922         try {
    923             update(new byte[getBlockSize()], 0, getBlockSize(), new byte[getBlockSize() * 2]);
    924             fail();
    925         } catch (IllegalStateException expected) {}
    926 
    927         init(opmode, key, paramSpec);
    928         try {
    929             update(new byte[getBlockSize()], 0, getBlockSize(), new byte[getBlockSize() * 2], 0);
    930             fail();
    931         } catch (IllegalStateException expected) {}
    932 
    933         init(opmode, key, paramSpec);
    934         try {
    935             update(ByteBuffer.allocate(getBlockSize()), ByteBuffer.allocate(getBlockSize() * 2));
    936             fail();
    937         } catch (IllegalStateException expected) {}
    938 
    939         init(opmode, key, paramSpec);
    940         try {
    941             doFinal();
    942             fail();
    943         } catch (IllegalStateException expected) {}
    944 
    945         init(opmode, key, paramSpec);
    946         try {
    947             doFinal(new byte[getBlockSize()]);
    948             fail();
    949         } catch (IllegalStateException expected) {}
    950 
    951         init(opmode, key, paramSpec);
    952         try {
    953             doFinal(new byte[getBlockSize()], 0, getBlockSize());
    954             fail();
    955         } catch (IllegalStateException expected) {}
    956 
    957         init(opmode, key, paramSpec);
    958         try {
    959             doFinal(new byte[getBlockSize() * 2], 0);
    960             fail();
    961         } catch (IllegalStateException expected) {}
    962 
    963         init(opmode, key, paramSpec);
    964         try {
    965             doFinal(new byte[getBlockSize()], 0, getBlockSize(), new byte[getBlockSize() * 2]);
    966             fail();
    967         } catch (IllegalStateException expected) {}
    968 
    969         init(opmode, key, paramSpec);
    970         try {
    971             doFinal(new byte[getBlockSize()], 0, getBlockSize(), new byte[getBlockSize() * 2], 0);
    972             fail();
    973         } catch (IllegalStateException expected) {}
    974 
    975         init(opmode, key, paramSpec);
    976         try {
    977             doFinal(ByteBuffer.allocate(getBlockSize()), ByteBuffer.allocate(getBlockSize() * 2));
    978             fail();
    979         } catch (IllegalStateException expected) {}
    980     }
    981 
    982     public void testGeneratedPadding() throws Exception {
    983         // Assert that the Cipher under test correctly handles plaintexts of various lengths.
    984         if (isStreamCipher()) {
    985             // Not applicable to stream ciphers
    986             return;
    987         }
    988 
    989         // Encryption of basePlaintext and additional data should result in baseCiphertext and some
    990         // data (some of which may be padding).
    991         int blockSize = getBlockSize();
    992         byte[] basePlaintext = subarray(getKatPlaintext(), 0, blockSize);
    993         byte[] baseCiphertext = subarray(getKatCiphertext(), 0, blockSize);
    994         boolean paddingEnabled = isPaddingEnabled();
    995 
    996         for (int lastInputBlockUnusedByteCount = 0;
    997                 lastInputBlockUnusedByteCount < blockSize;
    998                 lastInputBlockUnusedByteCount++) {
    999             byte[] plaintext = concat(basePlaintext, new byte[lastInputBlockUnusedByteCount]);
   1000             createCipher();
   1001             initKat(Cipher.ENCRYPT_MODE);
   1002 
   1003             if ((!paddingEnabled) && ((lastInputBlockUnusedByteCount % blockSize) != 0)) {
   1004                 // Without padding, plaintext which does not end with a full block should be
   1005                 // rejected.
   1006                 try {
   1007                     doFinal(plaintext);
   1008                     fail();
   1009                 } catch (IllegalBlockSizeException expected) {}
   1010                 continue;
   1011             }
   1012             byte[] ciphertext = doFinal(plaintext);
   1013 
   1014             assertEquals(
   1015                     "lastInputBlockUnusedByteCount: " + lastInputBlockUnusedByteCount,
   1016                     baseCiphertext,
   1017                     subarray(ciphertext, 0, baseCiphertext.length));
   1018 
   1019             int expectedCiphertextLength = getExpectedCiphertextLength(plaintext.length);
   1020             int expectedDecryptedPlaintextLength =
   1021                     (paddingEnabled) ? plaintext.length : expectedCiphertextLength;
   1022             assertEquals(
   1023                     "lastInputBlockUnusedByteCount: " + lastInputBlockUnusedByteCount,
   1024                     expectedCiphertextLength,
   1025                     ciphertext.length);
   1026             initKat(Cipher.DECRYPT_MODE);
   1027             byte[] decryptedPlaintext = doFinal(ciphertext);
   1028             assertEquals(
   1029                     "lastInputBlockUnusedByteCount: " + lastInputBlockUnusedByteCount,
   1030                     expectedDecryptedPlaintextLength,
   1031                     decryptedPlaintext.length);
   1032             assertEquals(
   1033                     "lastInputBlockUnusedByteCount: " + lastInputBlockUnusedByteCount,
   1034                     basePlaintext,
   1035                     subarray(decryptedPlaintext, 0, basePlaintext.length));
   1036         }
   1037     }
   1038 
   1039     public void testDecryptWithMangledPadding() throws Exception {
   1040         if (!isPaddingEnabled()) {
   1041             // Test not applicable when padding not in use
   1042             return;
   1043         }
   1044 
   1045         createCipher();
   1046         initKat(Cipher.DECRYPT_MODE);
   1047         byte[] ciphertext = getKatCiphertext();
   1048         // Flip a bit in the last byte of ciphertext -- this should result in the last plaintext
   1049         // block getting mangled. In turn, this should result in bad padding.
   1050         ciphertext[ciphertext.length - 1] ^= 1;
   1051         try {
   1052             doFinal(ciphertext);
   1053             fail();
   1054         } catch (BadPaddingException expected) {}
   1055     }
   1056 
   1057     public void testDecryptWithMissingPadding() throws Exception {
   1058         if (!isPaddingEnabled()) {
   1059             // Test not applicable when padding not in use
   1060             return;
   1061         }
   1062 
   1063         createCipher();
   1064         initKat(Cipher.DECRYPT_MODE);
   1065         byte[] ciphertext = subarray(getKatCiphertext(), 0, getBlockSize());
   1066         try {
   1067             doFinal(ciphertext);
   1068             fail();
   1069         } catch (BadPaddingException expected) {}
   1070     }
   1071 
   1072     public void testUpdateCopySafe() throws Exception {
   1073         // Assert that when input and output buffers passed to Cipher.update reference the same
   1074         // byte array, then no input data is overwritten before it's consumed.
   1075         assertUpdateCopySafe(Cipher.ENCRYPT_MODE, 0, 0);
   1076         assertUpdateCopySafe(Cipher.ENCRYPT_MODE, 0, 1);
   1077         assertUpdateCopySafe(Cipher.ENCRYPT_MODE, 1, 0);
   1078         assertUpdateCopySafe(Cipher.ENCRYPT_MODE, 0, getBlockSize() - 1);
   1079         assertUpdateCopySafe(Cipher.ENCRYPT_MODE, 0, getBlockSize());
   1080         assertUpdateCopySafe(Cipher.ENCRYPT_MODE, 0, getBlockSize() + 1);
   1081         assertUpdateCopySafe(Cipher.ENCRYPT_MODE, getBlockSize() * 2 - 1, 0);
   1082         assertUpdateCopySafe(Cipher.ENCRYPT_MODE, getBlockSize() * 2, 0);
   1083         assertUpdateCopySafe(Cipher.ENCRYPT_MODE, getBlockSize() * 2 + 1, 0);
   1084 
   1085         assertUpdateCopySafe(Cipher.DECRYPT_MODE, 0, 0);
   1086         assertUpdateCopySafe(Cipher.DECRYPT_MODE, 0, 1);
   1087         assertUpdateCopySafe(Cipher.DECRYPT_MODE, 1, 0);
   1088         assertUpdateCopySafe(Cipher.DECRYPT_MODE, 0, getBlockSize() - 1);
   1089         assertUpdateCopySafe(Cipher.DECRYPT_MODE, 0, getBlockSize());
   1090         assertUpdateCopySafe(Cipher.DECRYPT_MODE, 0, getBlockSize() + 1);
   1091         assertUpdateCopySafe(Cipher.DECRYPT_MODE, getBlockSize() * 2 - 1, 0);
   1092         assertUpdateCopySafe(Cipher.DECRYPT_MODE, getBlockSize() * 2, 0);
   1093         assertUpdateCopySafe(Cipher.DECRYPT_MODE, getBlockSize() * 2 + 1, 0);
   1094     }
   1095 
   1096     private void assertUpdateCopySafe(
   1097             int opmode, int inputOffsetInBuffer, int outputOffsetInBuffer)
   1098             throws Exception {
   1099         int blockSize = getBlockSize();
   1100         byte[] input;
   1101         byte[] expectedOutput;
   1102         switch (opmode) {
   1103             case Cipher.ENCRYPT_MODE:
   1104                 input = getKatPlaintext();
   1105                 if (isStreamCipher()) {
   1106                     if (isAuthenticatedCipher()) {
   1107                         expectedOutput = subarray(getKatCiphertext(), 0, input.length);
   1108                     } else {
   1109                         expectedOutput = getKatCiphertext();
   1110                     }
   1111                 } else {
   1112                     // Update outputs exactly one block of ciphertext for one block of plaintext,
   1113                     // excluding padding.
   1114                     expectedOutput = subarray(
   1115                             getKatCiphertext(), 0, (input.length / blockSize) * blockSize);
   1116                 }
   1117                 break;
   1118             case Cipher.DECRYPT_MODE:
   1119                 input = getKatCiphertext();
   1120                 if (isAuthenticatedCipher()) {
   1121                     expectedOutput = EmptyArray.BYTE;
   1122                 } else if (isStreamCipher()) {
   1123                     expectedOutput = getKatPlaintext();
   1124                 } else {
   1125                     expectedOutput = getKatPlaintext();
   1126                     if (isPaddingEnabled()) {
   1127                         // When padding is enabled, update will not output the last block of
   1128                         // plaintext because it doesn't know whether more ciphertext will be
   1129                         // provided.
   1130                         expectedOutput = subarray(
   1131                                 expectedOutput, 0, ((input.length / blockSize) - 1) * blockSize);
   1132                     } else {
   1133                         // When no padding is used, one block of ciphertext results in one block of
   1134                         // plaintext.
   1135                         expectedOutput = subarray(
   1136                                 expectedOutput, 0, (input.length - (input.length % blockSize)));
   1137                     }
   1138                 }
   1139                 break;
   1140             default:
   1141                 throw new AssertionFailedError("Unsupported opmode: " + opmode);
   1142         }
   1143 
   1144         int inputEndIndexInBuffer = inputOffsetInBuffer + input.length;
   1145         int outputEndIndexInBuffer = outputOffsetInBuffer + expectedOutput.length;
   1146 
   1147         // Test the update(byte[], int, int, byte[], int) variant
   1148         byte[] buffer = new byte[Math.max(inputEndIndexInBuffer, outputEndIndexInBuffer)];
   1149         System.arraycopy(input, 0, buffer, inputOffsetInBuffer, input.length);
   1150         createCipher();
   1151         initKat(opmode);
   1152         assertEquals(expectedOutput.length,
   1153                 update(buffer, inputOffsetInBuffer, input.length,
   1154                         buffer, outputOffsetInBuffer));
   1155         assertEquals(expectedOutput,
   1156                 subarray(buffer, outputOffsetInBuffer, outputEndIndexInBuffer));
   1157 
   1158         if (outputOffsetInBuffer == 0) {
   1159             // We can use the update variant which assumes that output offset is 0.
   1160             buffer = new byte[Math.max(inputEndIndexInBuffer, outputEndIndexInBuffer)];
   1161             System.arraycopy(input, 0, buffer, inputOffsetInBuffer, input.length);
   1162             createCipher();
   1163             initKat(opmode);
   1164             assertEquals(expectedOutput.length,
   1165                     update(buffer, inputOffsetInBuffer, input.length, buffer));
   1166             assertEquals(expectedOutput,
   1167                     subarray(buffer, outputOffsetInBuffer, outputEndIndexInBuffer));
   1168         }
   1169 
   1170         // Test the update(ByteBuffer, ByteBuffer) variant
   1171         buffer = new byte[Math.max(inputEndIndexInBuffer, outputEndIndexInBuffer)];
   1172         System.arraycopy(input, 0, buffer, inputOffsetInBuffer, input.length);
   1173         ByteBuffer inputBuffer = ByteBuffer.wrap(buffer, inputOffsetInBuffer, input.length);
   1174         ByteBuffer outputBuffer =
   1175                 ByteBuffer.wrap(buffer, outputOffsetInBuffer, expectedOutput.length);
   1176         createCipher();
   1177         initKat(opmode);
   1178         assertEquals(expectedOutput.length, update(inputBuffer, outputBuffer));
   1179         assertEquals(expectedOutput,
   1180                 subarray(buffer, outputOffsetInBuffer, outputEndIndexInBuffer));
   1181     }
   1182 
   1183     public void testDoFinalCopySafe() throws Exception {
   1184         // Assert that when input and output buffers passed to Cipher.doFinal reference the same
   1185         // byte array, then no input data is overwritten before it's consumed.
   1186         assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, 0, 0);
   1187         assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, 0, 1);
   1188         assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, 1, 0);
   1189         assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, 0, getBlockSize() - 1);
   1190         assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, 0, getBlockSize());
   1191         assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, 0, getBlockSize() + 1);
   1192         assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, getBlockSize() * 2 - 1, 0);
   1193         assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, getBlockSize() * 2, 0);
   1194         assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, getBlockSize() * 2 + 1, 0);
   1195 
   1196         assertDoFinalCopySafe(Cipher.DECRYPT_MODE, 0, 0);
   1197         assertDoFinalCopySafe(Cipher.DECRYPT_MODE, 0, 1);
   1198         assertDoFinalCopySafe(Cipher.DECRYPT_MODE, 1, 0);
   1199         assertDoFinalCopySafe(Cipher.DECRYPT_MODE, 0, getBlockSize() - 1);
   1200         assertDoFinalCopySafe(Cipher.DECRYPT_MODE, 0, getBlockSize());
   1201         assertDoFinalCopySafe(Cipher.DECRYPT_MODE, 0, getBlockSize() + 1);
   1202         assertDoFinalCopySafe(Cipher.DECRYPT_MODE, getBlockSize() * 2 - 1, 0);
   1203         assertDoFinalCopySafe(Cipher.DECRYPT_MODE, getBlockSize() * 2, 0);
   1204         assertDoFinalCopySafe(Cipher.DECRYPT_MODE, getBlockSize() * 2 + 1, 0);
   1205     }
   1206 
   1207     private void assertDoFinalCopySafe(
   1208             int opmode, int inputOffsetInBuffer, int outputOffsetInBuffer)
   1209             throws Exception {
   1210         byte[] input = getKatInput(opmode);
   1211         byte[] expectedOutput = getKatOutput(opmode);
   1212 
   1213         int inputEndIndexInBuffer = inputOffsetInBuffer + input.length;
   1214         int outputEndIndexInBuffer = outputOffsetInBuffer + expectedOutput.length;
   1215 
   1216         // Test the doFinal(byte[], int, int, byte[], int) variant
   1217         byte[] buffer = new byte[Math.max(inputEndIndexInBuffer, outputEndIndexInBuffer)];
   1218         System.arraycopy(input, 0, buffer, inputOffsetInBuffer, input.length);
   1219         createCipher();
   1220         initKat(opmode);
   1221         assertEquals(expectedOutput.length,
   1222                 doFinal(buffer, inputOffsetInBuffer, input.length,
   1223                         buffer, outputOffsetInBuffer));
   1224         assertEquals(expectedOutput,
   1225                 subarray(buffer, outputOffsetInBuffer, outputEndIndexInBuffer));
   1226 
   1227         if (outputOffsetInBuffer == 0) {
   1228             // We can use the doFinal variant which assumes that output offset is 0.
   1229             buffer = new byte[Math.max(inputEndIndexInBuffer, outputEndIndexInBuffer)];
   1230             System.arraycopy(input, 0, buffer, inputOffsetInBuffer, input.length);
   1231             createCipher();
   1232             initKat(opmode);
   1233             assertEquals(expectedOutput.length,
   1234                     doFinal(buffer, inputOffsetInBuffer, input.length, buffer));
   1235             assertEquals(expectedOutput,
   1236                     subarray(buffer, outputOffsetInBuffer, outputEndIndexInBuffer));
   1237         }
   1238 
   1239         // Test the doFinal(ByteBuffer, ByteBuffer) variant
   1240         buffer = new byte[Math.max(inputEndIndexInBuffer, outputEndIndexInBuffer)];
   1241         System.arraycopy(input, 0, buffer, inputOffsetInBuffer, input.length);
   1242         ByteBuffer inputBuffer = ByteBuffer.wrap(buffer, inputOffsetInBuffer, input.length);
   1243         ByteBuffer outputBuffer =
   1244                 ByteBuffer.wrap(buffer, outputOffsetInBuffer, expectedOutput.length);
   1245         createCipher();
   1246         initKat(opmode);
   1247         assertEquals(expectedOutput.length, doFinal(inputBuffer, outputBuffer));
   1248         assertEquals(expectedOutput,
   1249                 subarray(buffer, outputOffsetInBuffer, outputEndIndexInBuffer));
   1250     }
   1251 
   1252     protected void createCipher() throws NoSuchAlgorithmException,
   1253             NoSuchPaddingException, NoSuchProviderException  {
   1254         mCipher = Cipher.getInstance(getTransformation(), EXPECTED_PROVIDER_NAME);
   1255     }
   1256 
   1257     private String getKeyAlgorithm() {
   1258         String transformation = getTransformation();
   1259         int delimiterIndex = transformation.indexOf('/');
   1260         if (delimiterIndex == -1) {
   1261             fail("Unexpected transformation: " + transformation);
   1262         }
   1263         return transformation.substring(0, delimiterIndex);
   1264     }
   1265 
   1266     private String getBlockMode() {
   1267         String transformation = getTransformation();
   1268         int delimiterIndex = transformation.indexOf('/');
   1269         if (delimiterIndex == -1) {
   1270             fail("Unexpected transformation: " + transformation);
   1271         }
   1272         int nextDelimiterIndex = transformation.indexOf('/', delimiterIndex + 1);
   1273         if (nextDelimiterIndex == -1) {
   1274             fail("Unexpected transformation: " + transformation);
   1275         }
   1276         return transformation.substring(delimiterIndex + 1, nextDelimiterIndex);
   1277     }
   1278 
   1279     private String getPadding() {
   1280         String transformation = getTransformation();
   1281         int delimiterIndex = transformation.indexOf('/');
   1282         if (delimiterIndex == -1) {
   1283             fail("Unexpected transformation: " + transformation);
   1284         }
   1285         int nextDelimiterIndex = transformation.indexOf('/', delimiterIndex + 1);
   1286         if (nextDelimiterIndex == -1) {
   1287             fail("Unexpected transformation: " + transformation);
   1288         }
   1289         return transformation.substring(nextDelimiterIndex + 1);
   1290     }
   1291 
   1292     private SecretKey getKey() {
   1293         return importKey(getKatKey());
   1294     }
   1295 
   1296     protected SecretKey importKey(byte[] keyMaterial) {
   1297         try {
   1298             int keyId = mNextKeyId++;
   1299             String keyAlias = "key" + keyId;
   1300             mAndroidKeyStore.setEntry(
   1301                     keyAlias,
   1302                     new KeyStore.SecretKeyEntry(new SecretKeySpec(keyMaterial, getKeyAlgorithm())),
   1303                     new KeyProtection.Builder(
   1304                             KeyProperties.PURPOSE_ENCRYPT
   1305                                     | KeyProperties.PURPOSE_DECRYPT)
   1306                             .setBlockModes(getBlockMode())
   1307                             .setEncryptionPaddings(getPadding())
   1308                             .setRandomizedEncryptionRequired(false)
   1309                             .build());
   1310             return (SecretKey) mAndroidKeyStore.getKey(keyAlias, null);
   1311         } catch (Exception e) {
   1312             throw new RuntimeException("Failed to import key into AndroidKeyStore", e);
   1313         }
   1314     }
   1315 
   1316     private boolean isPaddingEnabled() {
   1317         return !getTransformation().toLowerCase(Locale.US).endsWith("/nopadding");
   1318     }
   1319 
   1320     private int getExpectedCiphertextLength(int plaintextLength) {
   1321         int blockSize = getBlockSize();
   1322         if (isStreamCipher()) {
   1323             // Padding not supported for stream ciphers
   1324             assertFalse(isPaddingEnabled());
   1325             return plaintextLength;
   1326         } else {
   1327             if (isPaddingEnabled()) {
   1328                 return ((plaintextLength / blockSize) + 1) * blockSize;
   1329             } else {
   1330                 return ((plaintextLength + blockSize - 1) / blockSize) * blockSize;
   1331             }
   1332         }
   1333     }
   1334 
   1335     protected void initKat(int opmode)
   1336             throws InvalidKeyException, InvalidAlgorithmParameterException {
   1337         init(opmode, getKey(), getKatAlgorithmParameterSpec());
   1338     }
   1339 
   1340     protected void init(int opmode, Key key, AlgorithmParameters spec)
   1341             throws InvalidKeyException, InvalidAlgorithmParameterException {
   1342         mCipher.init(opmode, key, spec);
   1343         mOpmode = opmode;
   1344     }
   1345 
   1346     protected void init(int opmode, Key key, AlgorithmParameters spec, SecureRandom random)
   1347             throws InvalidKeyException, InvalidAlgorithmParameterException {
   1348         mCipher.init(opmode, key, spec, random);
   1349         mOpmode = opmode;
   1350     }
   1351 
   1352     protected void init(int opmode, Key key, AlgorithmParameterSpec spec)
   1353             throws InvalidKeyException, InvalidAlgorithmParameterException {
   1354         mCipher.init(opmode, key, spec);
   1355         mOpmode = opmode;
   1356     }
   1357 
   1358     protected void init(int opmode, Key key, AlgorithmParameterSpec spec, SecureRandom random)
   1359             throws InvalidKeyException, InvalidAlgorithmParameterException {
   1360         mCipher.init(opmode, key, spec, random);
   1361         mOpmode = opmode;
   1362     }
   1363 
   1364     protected void init(int opmode, Key key) throws InvalidKeyException {
   1365         mCipher.init(opmode, key);
   1366         mOpmode = opmode;
   1367     }
   1368 
   1369     protected void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
   1370         mCipher.init(opmode, key, random);
   1371         mOpmode = opmode;
   1372     }
   1373 
   1374     protected byte[] doFinal() throws IllegalBlockSizeException, BadPaddingException {
   1375         return mCipher.doFinal();
   1376     }
   1377 
   1378     protected byte[] doFinal(byte[] input) throws IllegalBlockSizeException, BadPaddingException {
   1379         return mCipher.doFinal(input);
   1380     }
   1381 
   1382     protected byte[] doFinal(byte[] input, int inputOffset, int inputLen)
   1383             throws IllegalBlockSizeException, BadPaddingException {
   1384         return mCipher.doFinal(input, inputOffset, inputLen);
   1385     }
   1386 
   1387     protected int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output)
   1388             throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
   1389         return mCipher.doFinal(input, inputOffset, inputLen, output);
   1390     }
   1391 
   1392     protected int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
   1393             int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
   1394             BadPaddingException {
   1395         return mCipher.doFinal(input, inputOffset, inputLen, output, outputOffset);
   1396     }
   1397 
   1398     protected int doFinal(byte[] output, int outputOffset) throws IllegalBlockSizeException,
   1399             ShortBufferException, BadPaddingException {
   1400         return mCipher.doFinal(output, outputOffset);
   1401     }
   1402 
   1403     protected int doFinal(ByteBuffer input, ByteBuffer output) throws ShortBufferException,
   1404             IllegalBlockSizeException, BadPaddingException {
   1405         return mCipher.doFinal(input, output);
   1406     }
   1407 
   1408     private boolean isEncrypting() {
   1409         return (mOpmode == Cipher.ENCRYPT_MODE) || (mOpmode == Cipher.WRAP_MODE);
   1410     }
   1411 
   1412     private void assertUpdateOutputSize(int inputLength, int outputLength) {
   1413         if ((isAuthenticatedCipher()) && (!isEncrypting())) {
   1414             assertEquals("Output of update must be empty for authenticated cipher when decrypting",
   1415                     0, outputLength);
   1416             return;
   1417         }
   1418 
   1419         if (isStreamCipher()) {
   1420             if (outputLength != inputLength) {
   1421                 fail("Output of update (" + outputLength + ") not same size as input ("
   1422                         + inputLength + ")");
   1423             }
   1424         } else {
   1425             if ((outputLength % getBlockSize()) != 0) {
   1426                 fail("Output of update (" + outputLength + ") not a multiple of block size ("
   1427                         + getBlockSize() + ")");
   1428             }
   1429         }
   1430     }
   1431 
   1432     protected byte[] update(byte[] input) {
   1433         byte[] output = mCipher.update(input);
   1434         assertUpdateOutputSize(
   1435                 (input != null) ? input.length : 0, (output != null) ? output.length : 0);
   1436         return output;
   1437     }
   1438 
   1439     protected byte[] update(byte[] input, int offset, int len) {
   1440         byte[] output = mCipher.update(input, offset, len);
   1441         assertUpdateOutputSize(len, (output != null) ? output.length : 0);
   1442 
   1443         return output;
   1444     }
   1445 
   1446     protected int update(byte[] input, int offset, int len, byte[] output)
   1447             throws ShortBufferException {
   1448         int outputLen = mCipher.update(input, offset, len, output);
   1449         assertUpdateOutputSize(len, outputLen);
   1450 
   1451         return outputLen;
   1452     }
   1453 
   1454     protected int update(byte[] input, int offset, int len, byte[] output, int outputOffset)
   1455             throws ShortBufferException {
   1456         int outputLen = mCipher.update(input, offset, len, output, outputOffset);
   1457         assertUpdateOutputSize(len, outputLen);
   1458 
   1459         return outputLen;
   1460     }
   1461 
   1462     protected int update(ByteBuffer input, ByteBuffer output) throws ShortBufferException {
   1463         int inputLimitBefore = input.limit();
   1464         int outputLimitBefore = output.limit();
   1465         int inputLen = input.remaining();
   1466         int outputPosBefore = output.position();
   1467 
   1468         int outputLen = mCipher.update(input, output);
   1469 
   1470         assertUpdateOutputSize(inputLen, outputLen);
   1471         assertEquals(inputLimitBefore, input.limit());
   1472         assertEquals(input.limit(), input.position());
   1473 
   1474         assertEquals(outputLimitBefore, output.limit());
   1475         assertEquals(outputPosBefore + outputLen, output.position());
   1476 
   1477         return outputLen;
   1478     }
   1479 
   1480     protected void updateAAD(byte[] input) {
   1481         mCipher.updateAAD(input);
   1482     }
   1483 
   1484     protected void updateAAD(byte[] input, int offset, int len) {
   1485         mCipher.updateAAD(input, offset, len);
   1486     }
   1487 
   1488     protected void updateAAD(ByteBuffer input) {
   1489         mCipher.updateAAD(input);
   1490     }
   1491 
   1492     @SuppressWarnings("unused")
   1493     protected static void assertEquals(Buffer expected, Buffer actual) {
   1494         throw new RuntimeException(
   1495                 "Comparing ByteBuffers using their .equals is probably not what you want"
   1496                 + " -- use assertByteBufferEquals instead.");
   1497     }
   1498 
   1499     /**
   1500      * Asserts that the position, limit, and capacity of the provided buffers are the same, and that
   1501      * their contents (from position {@code 0} to capacity) are the same.
   1502      */
   1503     protected static void assertByteBufferEquals(ByteBuffer expected, ByteBuffer actual) {
   1504         if (expected == null) {
   1505             if (actual == null) {
   1506                 return;
   1507             } else {
   1508                 fail("Expected: null, actual: " + bufferToString(actual));
   1509             }
   1510         } else {
   1511             if (actual == null) {
   1512                 fail("Expected: " + bufferToString(expected) + ", actual: null");
   1513             } else {
   1514                 if ((expected.capacity() != actual.capacity())
   1515                         || (expected.position() != actual.position())
   1516                         || (expected.limit() != actual.limit())
   1517                         || (!equals(expected.array(), expected.arrayOffset(), expected.capacity(),
   1518                                     actual.array(), actual.arrayOffset(), actual.capacity()))) {
   1519                     fail("Expected: " + bufferToString(expected)
   1520                             + ", actual: " + bufferToString(actual));
   1521                 }
   1522             }
   1523         }
   1524     }
   1525 
   1526     private static String bufferToString(ByteBuffer buffer) {
   1527         return "ByteBuffer[pos: " + buffer.position() + ", limit: " + buffer.limit()
   1528                 + ", capacity: " + buffer.capacity()
   1529                 + ", backing array: " + HexEncoding.encode(
   1530                         buffer.array(), buffer.arrayOffset(), buffer.capacity()) + "]";
   1531     }
   1532 
   1533     protected static boolean equals(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2,
   1534             int len2) {
   1535         if (arr1 == null) {
   1536             return (arr2 == null);
   1537         } else if (arr2 == null) {
   1538             return (arr1 == null);
   1539         } else {
   1540             if (len1 != len2) {
   1541                 return false;
   1542             }
   1543             for (int i = 0; i < len1; i++) {
   1544                 if (arr1[i + offset1] != arr2[i + offset2]) {
   1545                     return false;
   1546                 }
   1547             }
   1548             return true;
   1549         }
   1550     }
   1551 
   1552     protected static byte[] subarray(byte[] array, int beginIndex, int endIndex) {
   1553         byte[] result = new byte[endIndex - beginIndex];
   1554         System.arraycopy(array, beginIndex, result, 0, result.length);
   1555         return result;
   1556     }
   1557 
   1558     protected static byte[] concat(byte[]... arrays) {
   1559         int resultLength = 0;
   1560         for (byte[] array : arrays) {
   1561             resultLength += (array != null) ? array.length : 0;
   1562         }
   1563 
   1564         byte[] result = new byte[resultLength];
   1565         int resultOffset = 0;
   1566         for (byte[] array : arrays) {
   1567             if (array != null) {
   1568                 System.arraycopy(array, 0, result, resultOffset, array.length);
   1569                 resultOffset += array.length;
   1570             }
   1571         }
   1572         return result;
   1573     }
   1574 
   1575     protected static void assertEquals(byte[] expected, byte[] actual) {
   1576         assertEquals(null, expected, actual);
   1577     }
   1578 
   1579     protected static void assertEquals(String message, byte[] expected, byte[] actual) {
   1580         if (!Arrays.equals(expected, actual)) {
   1581             StringBuilder detail = new StringBuilder();
   1582             if (expected != null) {
   1583                 detail.append("Expected (" + expected.length + " bytes): <"
   1584                         + HexEncoding.encode(expected) + ">");
   1585             } else {
   1586                 detail.append("Expected: null");
   1587             }
   1588             if (actual != null) {
   1589                 detail.append(", actual (" + actual.length + " bytes): <"
   1590                         + HexEncoding.encode(actual) + ">");
   1591             } else {
   1592                 detail.append(", actual: null");
   1593             }
   1594             if (message != null) {
   1595                 fail(message + ": " + detail);
   1596             } else {
   1597                 fail(detail.toString());
   1598             }
   1599         }
   1600     }
   1601 
   1602     protected final void assertInitRejectsIvParameterSpec(byte[] iv) throws Exception {
   1603         Key key = importKey(getKatKey());
   1604         createCipher();
   1605         IvParameterSpec spec = new IvParameterSpec(iv);
   1606         try {
   1607             init(Cipher.ENCRYPT_MODE, key, spec);
   1608             fail();
   1609         } catch (InvalidAlgorithmParameterException expected) {}
   1610 
   1611         try {
   1612             init(Cipher.WRAP_MODE, key, spec);
   1613             fail();
   1614         } catch (InvalidAlgorithmParameterException expected) {}
   1615 
   1616         try {
   1617             init(Cipher.DECRYPT_MODE, key, spec);
   1618             fail();
   1619         } catch (InvalidAlgorithmParameterException expected) {}
   1620 
   1621         try {
   1622             init(Cipher.UNWRAP_MODE, key, spec);
   1623             fail();
   1624         } catch (InvalidAlgorithmParameterException expected) {}
   1625 
   1626         AlgorithmParameters param = AlgorithmParameters.getInstance("AES");
   1627         param.init(new IvParameterSpec(iv));
   1628         try {
   1629             init(Cipher.ENCRYPT_MODE, key, param);
   1630             fail();
   1631         } catch (InvalidAlgorithmParameterException expected) {}
   1632 
   1633         try {
   1634             init(Cipher.WRAP_MODE, key, param);
   1635             fail();
   1636         } catch (InvalidAlgorithmParameterException expected) {}
   1637 
   1638         try {
   1639             init(Cipher.DECRYPT_MODE, key, param);
   1640             fail();
   1641         } catch (InvalidAlgorithmParameterException expected) {}
   1642 
   1643         try {
   1644             init(Cipher.UNWRAP_MODE, key, param);
   1645             fail();
   1646         } catch (InvalidAlgorithmParameterException expected) {}
   1647     }
   1648 }
   1649