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