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