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