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.security.keystore2; 18 19 import android.annotation.CallSuper; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.hardware.security.keymint.KeyParameter; 23 import android.os.StrictMode; 24 import android.security.KeyStoreException; 25 import android.security.KeyStoreOperation; 26 import android.security.keymaster.KeymasterDefs; 27 import android.security.keystore.KeyProperties; 28 import android.security.keystore.KeyStoreCryptoOperation; 29 import android.system.keystore2.Authorization; 30 31 import libcore.util.EmptyArray; 32 33 import java.nio.BufferOverflowException; 34 import java.nio.ByteBuffer; 35 import java.security.AlgorithmParameters; 36 import java.security.GeneralSecurityException; 37 import java.security.InvalidAlgorithmParameterException; 38 import java.security.InvalidKeyException; 39 import java.security.InvalidParameterException; 40 import java.security.Key; 41 import java.security.KeyFactory; 42 import java.security.NoSuchAlgorithmException; 43 import java.security.PrivateKey; 44 import java.security.ProviderException; 45 import java.security.PublicKey; 46 import java.security.SecureRandom; 47 import java.security.spec.AlgorithmParameterSpec; 48 import java.security.spec.InvalidKeySpecException; 49 import java.security.spec.MGF1ParameterSpec; 50 import java.security.spec.PKCS8EncodedKeySpec; 51 import java.security.spec.X509EncodedKeySpec; 52 import java.util.ArrayList; 53 import java.util.List; 54 55 import javax.crypto.AEADBadTagException; 56 import javax.crypto.BadPaddingException; 57 import javax.crypto.Cipher; 58 import javax.crypto.CipherSpi; 59 import javax.crypto.IllegalBlockSizeException; 60 import javax.crypto.NoSuchPaddingException; 61 import javax.crypto.SecretKey; 62 import javax.crypto.SecretKeyFactory; 63 import javax.crypto.ShortBufferException; 64 import javax.crypto.spec.OAEPParameterSpec; 65 import javax.crypto.spec.PSource; 66 import javax.crypto.spec.SecretKeySpec; 67 68 /** 69 * Base class for {@link CipherSpi} implementations of Android KeyStore backed ciphers. 70 * 71 * @hide 72 */ 73 abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStoreCryptoOperation { 74 private static final String TAG = "AndroidKeyStoreCipherSpiBase"; 75 public static final String DEFAULT_MGF1_DIGEST = KeyProperties.DIGEST_SHA1; 76 77 // Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after 78 // doFinal finishes. 79 private boolean mEncrypting; 80 private int mKeymasterPurposeOverride = -1; 81 private AndroidKeyStoreKey mKey; 82 private SecureRandom mRng; 83 84 /** 85 * Object representing this operation inside keystore service. It is initialized 86 * by {@code engineInit} and is invalidated when {@code engineDoFinal} succeeds and on some 87 * error conditions in between. 88 */ 89 private KeyStoreOperation mOperation; 90 /** 91 * The operation challenge is required when an operation needs user authorization. 92 * The challenge is subjected to an authenticator, e.g., Gatekeeper or a biometric 93 * authenticator, and included in the authentication token minted by this authenticator. 94 * It may be null, if the operation does not require authorization. 95 */ 96 private long mOperationChallenge; 97 private KeyStoreCryptoOperationStreamer mMainDataStreamer; 98 private KeyStoreCryptoOperationStreamer mAdditionalAuthenticationDataStreamer; 99 private boolean mAdditionalAuthenticationDataStreamerClosed; 100 101 /** 102 * Encountered exception which could not be immediately thrown because it was encountered inside 103 * a method that does not throw checked exception. This exception will be thrown from 104 * {@code engineDoFinal}. Once such an exception is encountered, {@code engineUpdate} and 105 * {@code engineDoFinal} start ignoring input data. 106 */ 107 private Exception mCachedException; 108 109 private Cipher mCipher; 110 AndroidKeyStoreCipherSpiBase()111 AndroidKeyStoreCipherSpiBase() { 112 mOperation = null; 113 mEncrypting = false; 114 mKeymasterPurposeOverride = -1; 115 mKey = null; 116 mRng = null; 117 mOperationChallenge = 0; 118 mMainDataStreamer = null; 119 mAdditionalAuthenticationDataStreamer = null; 120 mAdditionalAuthenticationDataStreamerClosed = false; 121 mCachedException = null; 122 mCipher = null; 123 } 124 getKeyCharacteristics(Key key)125 private Authorization[] getKeyCharacteristics(Key key) { 126 if (!(key instanceof AndroidKeyStoreKey)) { 127 return new Authorization[] {}; 128 } 129 130 return ((AndroidKeyStoreKey) key).getAuthorizations(); 131 } 132 133 @Override engineInit(int opmode, Key key, SecureRandom random)134 protected final void engineInit(int opmode, Key key, SecureRandom random) 135 throws InvalidKeyException { 136 resetAll(); 137 138 // Public key operations get diverted to the default provider. 139 if (!(key instanceof AndroidKeyStorePrivateKey) 140 && (key instanceof PrivateKey || key instanceof PublicKey)) { 141 try { 142 StrictMode.noteSlowCall("engineInit"); 143 mCipher = Cipher.getInstance(getTransform()); 144 String transform = getTransform(); 145 146 if ("RSA/ECB/OAEPWithSHA-224AndMGF1Padding".equals(transform)) { 147 OAEPParameterSpec spec = 148 new OAEPParameterSpec("SHA-224", "MGF1", 149 new MGF1ParameterSpec(DEFAULT_MGF1_DIGEST), 150 PSource.PSpecified.DEFAULT); 151 mCipher.init(opmode, key, spec, random); 152 } else if ("RSA/ECB/OAEPWithSHA-256AndMGF1Padding".equals(transform)) { 153 OAEPParameterSpec spec = 154 new OAEPParameterSpec("SHA-256", "MGF1", 155 new MGF1ParameterSpec(DEFAULT_MGF1_DIGEST), 156 PSource.PSpecified.DEFAULT); 157 mCipher.init(opmode, key, spec, random); 158 159 } else if ("RSA/ECB/OAEPWithSHA-384AndMGF1Padding".equals(transform)) { 160 OAEPParameterSpec spec = 161 new OAEPParameterSpec("SHA-384", "MGF1", 162 new MGF1ParameterSpec(DEFAULT_MGF1_DIGEST), 163 PSource.PSpecified.DEFAULT); 164 mCipher.init(opmode, key, spec, random); 165 166 } else if ("RSA/ECB/OAEPWithSHA-512AndMGF1Padding".equals(transform)) { 167 OAEPParameterSpec spec = 168 new OAEPParameterSpec("SHA-512", "MGF1", 169 new MGF1ParameterSpec(DEFAULT_MGF1_DIGEST), 170 PSource.PSpecified.DEFAULT); 171 mCipher.init(opmode, key, spec, random); 172 } else { 173 mCipher.init(opmode, key, random); 174 } 175 return; 176 } catch (NoSuchAlgorithmException 177 | NoSuchPaddingException 178 | InvalidAlgorithmParameterException e) { 179 throw new InvalidKeyException(e); 180 } 181 } 182 183 boolean success = false; 184 try { 185 init(opmode, key, random); 186 initAlgorithmSpecificParameters(); 187 try { 188 ensureKeystoreOperationInitialized(getKeyCharacteristics(key)); 189 } catch (InvalidAlgorithmParameterException e) { 190 throw new InvalidKeyException(e); 191 } 192 success = true; 193 } finally { 194 if (!success) { 195 resetAll(); 196 } 197 } 198 } 199 200 @Override engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)201 protected final void engineInit(int opmode, Key key, AlgorithmParameters params, 202 SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { 203 resetAll(); 204 205 // Public key operations get diverted to the default provider. 206 if (!(key instanceof AndroidKeyStorePrivateKey) 207 && (key instanceof PrivateKey || key instanceof PublicKey)) { 208 try { 209 StrictMode.noteSlowCall("engineInit"); 210 mCipher = Cipher.getInstance(getTransform()); 211 mCipher.init(opmode, key, params, random); 212 return; 213 } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { 214 throw new InvalidKeyException(e); 215 } 216 } 217 218 boolean success = false; 219 try { 220 init(opmode, key, random); 221 initAlgorithmSpecificParameters(params); 222 ensureKeystoreOperationInitialized(getKeyCharacteristics(key)); 223 success = true; 224 } finally { 225 if (!success) { 226 resetAll(); 227 } 228 } 229 } 230 231 @Override engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)232 protected final void engineInit(int opmode, Key key, AlgorithmParameterSpec params, 233 SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { 234 resetAll(); 235 236 // Public key operations get diverted to the default provider. 237 if (!(key instanceof AndroidKeyStorePrivateKey) 238 && (key instanceof PrivateKey || key instanceof PublicKey)) { 239 try { 240 StrictMode.noteSlowCall("engineInit"); 241 mCipher = Cipher.getInstance(getTransform()); 242 mCipher.init(opmode, key, params, random); 243 return; 244 } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { 245 throw new InvalidKeyException(e); 246 } 247 } 248 249 boolean success = false; 250 try { 251 init(opmode, key, random); 252 initAlgorithmSpecificParameters(params); 253 ensureKeystoreOperationInitialized(getKeyCharacteristics(key)); 254 success = true; 255 } finally { 256 if (!success) { 257 resetAll(); 258 } 259 } 260 } 261 init(int opmode, Key key, SecureRandom random)262 private void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { 263 switch (opmode) { 264 case Cipher.ENCRYPT_MODE: 265 case Cipher.WRAP_MODE: 266 mEncrypting = true; 267 break; 268 case Cipher.DECRYPT_MODE: 269 case Cipher.UNWRAP_MODE: 270 mEncrypting = false; 271 break; 272 default: 273 throw new InvalidParameterException("Unsupported opmode: " + opmode); 274 } 275 initKey(opmode, key); 276 if (mKey == null) { 277 throw new ProviderException("initKey did not initialize the key"); 278 } 279 mRng = random; 280 } 281 abortOperation()282 private void abortOperation() { 283 KeyStoreCryptoOperationUtils.abortOperation(mOperation); 284 mOperation = null; 285 } 286 287 /** 288 * Resets this cipher to its pristine pre-init state. This must be equivalent to obtaining a new 289 * cipher instance. 290 * 291 * <p>Subclasses storing additional state should override this method, reset the additional 292 * state, and then chain to superclass. 293 */ 294 @CallSuper resetAll()295 protected void resetAll() { 296 abortOperation(); 297 mEncrypting = false; 298 mKeymasterPurposeOverride = -1; 299 mKey = null; 300 mRng = null; 301 mOperationChallenge = 0; 302 mMainDataStreamer = null; 303 mAdditionalAuthenticationDataStreamer = null; 304 mAdditionalAuthenticationDataStreamerClosed = false; 305 mCachedException = null; 306 mCipher = null; 307 } 308 309 /** 310 * Resets this cipher while preserving the initialized state. This must be equivalent to 311 * rolling back the cipher's state to just after the most recent {@code engineInit} completed 312 * successfully. 313 * 314 * <p>Subclasses storing additional post-init state should override this method, reset the 315 * additional state, and then chain to superclass. 316 */ 317 @CallSuper resetWhilePreservingInitState()318 protected void resetWhilePreservingInitState() { 319 abortOperation(); 320 mOperationChallenge = 0; 321 mMainDataStreamer = null; 322 mAdditionalAuthenticationDataStreamer = null; 323 mAdditionalAuthenticationDataStreamerClosed = false; 324 mCachedException = null; 325 } 326 ensureKeystoreOperationInitialized(Authorization[] keyCharacteristics)327 private void ensureKeystoreOperationInitialized(Authorization[] keyCharacteristics) 328 throws InvalidKeyException, 329 InvalidAlgorithmParameterException { 330 if (mMainDataStreamer != null) { 331 return; 332 } 333 if (mCachedException != null) { 334 return; 335 } 336 if (mKey == null) { 337 throw new IllegalStateException("Not initialized"); 338 } 339 340 List<KeyParameter> parameters = new ArrayList<>(); 341 addAlgorithmSpecificParametersToBegin(parameters, keyCharacteristics); 342 343 int purpose; 344 if (mKeymasterPurposeOverride != -1) { 345 purpose = mKeymasterPurposeOverride; 346 } else { 347 purpose = mEncrypting 348 ? KeymasterDefs.KM_PURPOSE_ENCRYPT : KeymasterDefs.KM_PURPOSE_DECRYPT; 349 } 350 351 parameters.add(KeyStore2ParameterUtils.makeEnum(KeymasterDefs.KM_TAG_PURPOSE, purpose)); 352 353 try { 354 StrictMode.noteDiskRead(); 355 mOperation = mKey.getSecurityLevel().createOperation( 356 mKey.getKeyIdDescriptor(), 357 parameters 358 ); 359 } catch (KeyStoreException keyStoreException) { 360 GeneralSecurityException e = KeyStoreCryptoOperationUtils.getExceptionForCipherInit( 361 mKey, keyStoreException); 362 if (e instanceof InvalidKeyException) { 363 throw (InvalidKeyException) e; 364 } else if (e instanceof InvalidAlgorithmParameterException) { 365 throw (InvalidAlgorithmParameterException) e; 366 } else { 367 throw new ProviderException("Unexpected exception type", e); 368 } 369 } 370 371 // Now we check if we got an operation challenge. This indicates that user authorization 372 // is required. And if we got a challenge we check if the authorization can possibly 373 // succeed. 374 mOperationChallenge = KeyStoreCryptoOperationUtils.getOrMakeOperationChallenge( 375 mOperation, mKey); 376 377 loadAlgorithmSpecificParametersFromBeginResult(mOperation.getParameters()); 378 mMainDataStreamer = createMainDataStreamer(mOperation); 379 mAdditionalAuthenticationDataStreamer = 380 createAdditionalAuthenticationDataStreamer(mOperation); 381 mAdditionalAuthenticationDataStreamerClosed = false; 382 } 383 384 /** 385 * Creates a streamer which sends plaintext/ciphertext into the provided KeyStore and receives 386 * the corresponding ciphertext/plaintext from the KeyStore. 387 * 388 * <p>This implementation returns a working streamer. 389 */ 390 @NonNull createMainDataStreamer( KeyStoreOperation operation)391 protected KeyStoreCryptoOperationStreamer createMainDataStreamer( 392 KeyStoreOperation operation) { 393 return new KeyStoreCryptoOperationChunkedStreamer( 394 new KeyStoreCryptoOperationChunkedStreamer.MainDataStream( 395 operation), 0); 396 } 397 398 /** 399 * Creates a streamer which sends Additional Authentication Data (AAD) into the KeyStore. 400 * 401 * <p>This implementation returns {@code null}. 402 * 403 * @return stream or {@code null} if AAD is not supported by this cipher. 404 */ 405 @Nullable createAdditionalAuthenticationDataStreamer( @uppressWarnings"unused") KeyStoreOperation operation)406 protected KeyStoreCryptoOperationStreamer createAdditionalAuthenticationDataStreamer( 407 @SuppressWarnings("unused") KeyStoreOperation operation) { 408 return null; 409 } 410 411 @Override engineUpdate(byte[] input, int inputOffset, int inputLen)412 protected final byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { 413 if (mCipher != null) { 414 return mCipher.update(input, inputOffset, inputLen); 415 } 416 417 if (mCachedException != null) { 418 return null; 419 } 420 try { 421 ensureKeystoreOperationInitialized(getKeyCharacteristics(mKey)); 422 } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { 423 mCachedException = e; 424 return null; 425 } 426 427 if (inputLen == 0) { 428 return null; 429 } 430 431 byte[] output; 432 try { 433 flushAAD(); 434 output = mMainDataStreamer.update(input, inputOffset, inputLen); 435 } catch (KeyStoreException e) { 436 mCachedException = e; 437 return null; 438 } 439 440 if (output.length == 0) { 441 return null; 442 } 443 444 return output; 445 } 446 flushAAD()447 private void flushAAD() throws KeyStoreException { 448 if ((mAdditionalAuthenticationDataStreamer != null) 449 && (!mAdditionalAuthenticationDataStreamerClosed)) { 450 byte[] output; 451 try { 452 output = mAdditionalAuthenticationDataStreamer.doFinal( 453 EmptyArray.BYTE, 0, 0, 454 null); // no signature 455 } finally { 456 mAdditionalAuthenticationDataStreamerClosed = true; 457 } 458 if ((output != null) && (output.length > 0)) { 459 throw new ProviderException( 460 "AAD update unexpectedly returned data: " + output.length + " bytes"); 461 } 462 } 463 } 464 465 @Override engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)466 protected final int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, 467 int outputOffset) throws ShortBufferException { 468 if (mCipher != null) { 469 return mCipher.update(input, inputOffset, inputLen, output); 470 } 471 byte[] outputCopy = engineUpdate(input, inputOffset, inputLen); 472 if (outputCopy == null) { 473 return 0; 474 } 475 int outputAvailable = output.length - outputOffset; 476 if (outputCopy.length > outputAvailable) { 477 throw new ShortBufferException("Output buffer too short. Produced: " 478 + outputCopy.length + ", available: " + outputAvailable); 479 } 480 System.arraycopy(outputCopy, 0, output, outputOffset, outputCopy.length); 481 return outputCopy.length; 482 } 483 484 @Override engineUpdate(ByteBuffer input, ByteBuffer output)485 protected final int engineUpdate(ByteBuffer input, ByteBuffer output) 486 throws ShortBufferException { 487 if (mCipher != null) { 488 return mCipher.update(input, output); 489 } 490 491 if (input == null) { 492 throw new NullPointerException("input == null"); 493 } 494 if (output == null) { 495 throw new NullPointerException("output == null"); 496 } 497 498 int inputSize = input.remaining(); 499 byte[] outputArray; 500 if (input.hasArray()) { 501 outputArray = 502 engineUpdate( 503 input.array(), input.arrayOffset() + input.position(), inputSize); 504 input.position(input.position() + inputSize); 505 } else { 506 byte[] inputArray = new byte[inputSize]; 507 input.get(inputArray); 508 outputArray = engineUpdate(inputArray, 0, inputSize); 509 } 510 511 int outputSize = (outputArray != null) ? outputArray.length : 0; 512 if (outputSize > 0) { 513 int outputBufferAvailable = output.remaining(); 514 try { 515 output.put(outputArray); 516 } catch (BufferOverflowException e) { 517 throw new ShortBufferException( 518 "Output buffer too small. Produced: " + outputSize + ", available: " 519 + outputBufferAvailable); 520 } 521 } 522 return outputSize; 523 } 524 525 @Override engineUpdateAAD(byte[] input, int inputOffset, int inputLen)526 protected final void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) { 527 if (mCipher != null) { 528 StrictMode.noteSlowCall("engineUpdateAAD"); 529 mCipher.updateAAD(input, inputOffset, inputLen); 530 return; 531 } 532 533 if (mCachedException != null) { 534 return; 535 } 536 537 try { 538 ensureKeystoreOperationInitialized(getKeyCharacteristics(mKey)); 539 } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { 540 mCachedException = e; 541 return; 542 } 543 544 if (mAdditionalAuthenticationDataStreamerClosed) { 545 throw new IllegalStateException( 546 "AAD can only be provided before Cipher.update is invoked"); 547 } 548 549 if (mAdditionalAuthenticationDataStreamer == null) { 550 throw new IllegalStateException("This cipher does not support AAD"); 551 } 552 553 byte[] output; 554 try { 555 output = mAdditionalAuthenticationDataStreamer.update(input, inputOffset, inputLen); 556 } catch (KeyStoreException e) { 557 mCachedException = e; 558 return; 559 } 560 561 if ((output != null) && (output.length > 0)) { 562 throw new ProviderException("AAD update unexpectedly produced output: " 563 + output.length + " bytes"); 564 } 565 } 566 567 @Override engineUpdateAAD(ByteBuffer src)568 protected final void engineUpdateAAD(ByteBuffer src) { 569 if (mCipher != null) { 570 StrictMode.noteSlowCall("engineUpdateAAD"); 571 mCipher.updateAAD(src); 572 return; 573 } 574 575 if (src == null) { 576 throw new IllegalArgumentException("src == null"); 577 } 578 if (!src.hasRemaining()) { 579 return; 580 } 581 582 byte[] input; 583 int inputOffset; 584 int inputLen; 585 if (src.hasArray()) { 586 input = src.array(); 587 inputOffset = src.arrayOffset() + src.position(); 588 inputLen = src.remaining(); 589 src.position(src.limit()); 590 } else { 591 input = new byte[src.remaining()]; 592 inputOffset = 0; 593 inputLen = input.length; 594 src.get(input); 595 } 596 engineUpdateAAD(input, inputOffset, inputLen); 597 } 598 599 @Override engineDoFinal(byte[] input, int inputOffset, int inputLen)600 protected final byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) 601 throws IllegalBlockSizeException, BadPaddingException { 602 if (mCipher != null) { 603 if (input == null && inputLen == 0) { 604 return mCipher.doFinal(); 605 } else { 606 return mCipher.doFinal(input, inputOffset, inputLen); 607 } 608 } 609 610 if (mCachedException != null) { 611 throw (IllegalBlockSizeException) 612 new IllegalBlockSizeException().initCause(mCachedException); 613 } 614 615 try { 616 ensureKeystoreOperationInitialized(getKeyCharacteristics(mKey)); 617 } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { 618 throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e); 619 } 620 621 byte[] output; 622 try { 623 flushAAD(); 624 output = mMainDataStreamer.doFinal( 625 input, inputOffset, inputLen, 626 null); // no signature involved 627 } catch (KeyStoreException e) { 628 switch (e.getErrorCode()) { 629 case KeymasterDefs.KM_ERROR_INVALID_ARGUMENT: 630 throw (BadPaddingException) new BadPaddingException().initCause(e); 631 case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED: 632 throw (AEADBadTagException) new AEADBadTagException().initCause(e); 633 default: 634 throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e); 635 } 636 } 637 638 resetWhilePreservingInitState(); 639 return output; 640 } 641 642 @Override engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)643 protected final int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, 644 int outputOffset) throws ShortBufferException, IllegalBlockSizeException, 645 BadPaddingException { 646 if (mCipher != null) { 647 return mCipher.doFinal(input, inputOffset, inputLen, output); 648 } 649 650 byte[] outputCopy = engineDoFinal(input, inputOffset, inputLen); 651 if (outputCopy == null) { 652 return 0; 653 } 654 int outputAvailable = output.length - outputOffset; 655 if (outputCopy.length > outputAvailable) { 656 throw new ShortBufferException("Output buffer too short. Produced: " 657 + outputCopy.length + ", available: " + outputAvailable); 658 } 659 System.arraycopy(outputCopy, 0, output, outputOffset, outputCopy.length); 660 return outputCopy.length; 661 } 662 663 @Override engineDoFinal(ByteBuffer input, ByteBuffer output)664 protected final int engineDoFinal(ByteBuffer input, ByteBuffer output) 665 throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { 666 if (mCipher != null) { 667 return mCipher.doFinal(input, output); 668 } 669 670 if (input == null) { 671 throw new NullPointerException("input == null"); 672 } 673 if (output == null) { 674 throw new NullPointerException("output == null"); 675 } 676 677 int inputSize = input.remaining(); 678 byte[] outputArray; 679 if (input.hasArray()) { 680 outputArray = 681 engineDoFinal( 682 input.array(), input.arrayOffset() + input.position(), inputSize); 683 input.position(input.position() + inputSize); 684 } else { 685 byte[] inputArray = new byte[inputSize]; 686 input.get(inputArray); 687 outputArray = engineDoFinal(inputArray, 0, inputSize); 688 } 689 690 int outputSize = (outputArray != null) ? outputArray.length : 0; 691 if (outputSize > 0) { 692 int outputBufferAvailable = output.remaining(); 693 try { 694 output.put(outputArray); 695 } catch (BufferOverflowException e) { 696 throw new ShortBufferException( 697 "Output buffer too small. Produced: " + outputSize + ", available: " 698 + outputBufferAvailable); 699 } 700 } 701 return outputSize; 702 } 703 704 @Override engineWrap(Key key)705 protected final byte[] engineWrap(Key key) 706 throws IllegalBlockSizeException, InvalidKeyException { 707 if (mCipher != null) { 708 return mCipher.wrap(key); 709 } 710 711 if (mKey == null) { 712 throw new IllegalStateException("Not initilized"); 713 } 714 715 if (!isEncrypting()) { 716 throw new IllegalStateException( 717 "Cipher must be initialized in Cipher.WRAP_MODE to wrap keys"); 718 } 719 720 if (key == null) { 721 throw new NullPointerException("key == null"); 722 } 723 byte[] encoded = null; 724 StrictMode.noteSlowCall("engineWrap"); 725 if (key instanceof SecretKey) { 726 if ("RAW".equalsIgnoreCase(key.getFormat())) { 727 encoded = key.getEncoded(); 728 } 729 if (encoded == null) { 730 try { 731 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(key.getAlgorithm()); 732 SecretKeySpec spec = 733 (SecretKeySpec) keyFactory.getKeySpec( 734 (SecretKey) key, SecretKeySpec.class); 735 encoded = spec.getEncoded(); 736 } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { 737 throw new InvalidKeyException( 738 "Failed to wrap key because it does not export its key material", 739 e); 740 } 741 } 742 } else if (key instanceof PrivateKey) { 743 if ("PKCS8".equalsIgnoreCase(key.getFormat())) { 744 encoded = key.getEncoded(); 745 } 746 if (encoded == null) { 747 try { 748 KeyFactory keyFactory = KeyFactory.getInstance(key.getAlgorithm()); 749 PKCS8EncodedKeySpec spec = 750 keyFactory.getKeySpec(key, PKCS8EncodedKeySpec.class); 751 encoded = spec.getEncoded(); 752 } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { 753 throw new InvalidKeyException( 754 "Failed to wrap key because it does not export its key material", 755 e); 756 } 757 } 758 } else if (key instanceof PublicKey) { 759 if ("X.509".equalsIgnoreCase(key.getFormat())) { 760 encoded = key.getEncoded(); 761 } 762 if (encoded == null) { 763 try { 764 KeyFactory keyFactory = KeyFactory.getInstance(key.getAlgorithm()); 765 X509EncodedKeySpec spec = 766 keyFactory.getKeySpec(key, X509EncodedKeySpec.class); 767 encoded = spec.getEncoded(); 768 } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { 769 throw new InvalidKeyException( 770 "Failed to wrap key because it does not export its key material", 771 e); 772 } 773 } 774 } else { 775 throw new InvalidKeyException("Unsupported key type: " + key.getClass().getName()); 776 } 777 778 if (encoded == null) { 779 throw new InvalidKeyException( 780 "Failed to wrap key because it does not export its key material"); 781 } 782 783 try { 784 return engineDoFinal(encoded, 0, encoded.length); 785 } catch (BadPaddingException e) { 786 throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e); 787 } 788 } 789 790 @Override engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)791 protected final Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, 792 int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException { 793 if (mCipher != null) { 794 return mCipher.unwrap(wrappedKey, wrappedKeyAlgorithm, wrappedKeyType); 795 } 796 797 if (mKey == null) { 798 throw new IllegalStateException("Not initilized"); 799 } 800 801 if (isEncrypting()) { 802 throw new IllegalStateException( 803 "Cipher must be initialized in Cipher.WRAP_MODE to wrap keys"); 804 } 805 806 if (wrappedKey == null) { 807 throw new NullPointerException("wrappedKey == null"); 808 } 809 810 byte[] encoded; 811 try { 812 encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length); 813 } catch (IllegalBlockSizeException | BadPaddingException e) { 814 throw new InvalidKeyException("Failed to unwrap key", e); 815 } 816 817 StrictMode.noteSlowCall("engineUnwrap"); 818 switch (wrappedKeyType) { 819 case Cipher.SECRET_KEY: 820 { 821 return new SecretKeySpec(encoded, wrappedKeyAlgorithm); 822 // break; 823 } 824 case Cipher.PRIVATE_KEY: 825 { 826 KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm); 827 try { 828 return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encoded)); 829 } catch (InvalidKeySpecException e) { 830 throw new InvalidKeyException( 831 "Failed to create private key from its PKCS#8 encoded form", e); 832 } 833 // break; 834 } 835 case Cipher.PUBLIC_KEY: 836 { 837 KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm); 838 try { 839 return keyFactory.generatePublic(new X509EncodedKeySpec(encoded)); 840 } catch (InvalidKeySpecException e) { 841 throw new InvalidKeyException( 842 "Failed to create public key from its X.509 encoded form", e); 843 } 844 // break; 845 } 846 default: 847 throw new InvalidParameterException( 848 "Unsupported wrappedKeyType: " + wrappedKeyType); 849 } 850 } 851 852 @Override engineSetMode(String mode)853 protected final void engineSetMode(String mode) throws NoSuchAlgorithmException { 854 // This should never be invoked because all algorithms registered with the AndroidKeyStore 855 // provide explicitly specify block mode. 856 throw new UnsupportedOperationException(); 857 } 858 859 @Override engineSetPadding(String arg0)860 protected final void engineSetPadding(String arg0) throws NoSuchPaddingException { 861 // This should never be invoked because all algorithms registered with the AndroidKeyStore 862 // provide explicitly specify padding mode. 863 throw new UnsupportedOperationException(); 864 } 865 866 @Override engineGetKeySize(Key key)867 protected final int engineGetKeySize(Key key) throws InvalidKeyException { 868 throw new UnsupportedOperationException(); 869 } 870 871 @CallSuper 872 @Override finalize()873 public void finalize() throws Throwable { 874 try { 875 abortOperation(); 876 } finally { 877 super.finalize(); 878 } 879 } 880 881 @Override getOperationHandle()882 public final long getOperationHandle() { 883 return mOperationChallenge; 884 } 885 setKey(@onNull AndroidKeyStoreKey key)886 protected final void setKey(@NonNull AndroidKeyStoreKey key) { 887 mKey = key; 888 } 889 890 /** 891 * Overrides the default purpose/type of the crypto operation. 892 */ setKeymasterPurposeOverride(int keymasterPurpose)893 protected final void setKeymasterPurposeOverride(int keymasterPurpose) { 894 mKeymasterPurposeOverride = keymasterPurpose; 895 } 896 getKeymasterPurposeOverride()897 protected final int getKeymasterPurposeOverride() { 898 return mKeymasterPurposeOverride; 899 } 900 901 /** 902 * Returns {@code true} if this cipher is initialized for encryption, {@code false} if this 903 * cipher is initialized for decryption. 904 */ isEncrypting()905 protected final boolean isEncrypting() { 906 return mEncrypting; 907 } 908 getConsumedInputSizeBytes()909 protected final long getConsumedInputSizeBytes() { 910 if (mMainDataStreamer == null) { 911 throw new IllegalStateException("Not initialized"); 912 } 913 return mMainDataStreamer.getConsumedInputSizeBytes(); 914 } 915 getProducedOutputSizeBytes()916 protected final long getProducedOutputSizeBytes() { 917 if (mMainDataStreamer == null) { 918 throw new IllegalStateException("Not initialized"); 919 } 920 return mMainDataStreamer.getProducedOutputSizeBytes(); 921 } 922 opmodeToString(int opmode)923 static String opmodeToString(int opmode) { 924 switch (opmode) { 925 case Cipher.ENCRYPT_MODE: 926 return "ENCRYPT_MODE"; 927 case Cipher.DECRYPT_MODE: 928 return "DECRYPT_MODE"; 929 case Cipher.WRAP_MODE: 930 return "WRAP_MODE"; 931 case Cipher.UNWRAP_MODE: 932 return "UNWRAP_MODE"; 933 default: 934 return String.valueOf(opmode); 935 } 936 } 937 938 // The methods below need to be implemented by subclasses. 939 940 /** 941 * Initializes this cipher with the provided key. 942 * 943 * @throws InvalidKeyException if the {@code key} is not suitable for this cipher in the 944 * specified {@code opmode}. 945 * 946 * @see #setKey(AndroidKeyStoreKey) 947 */ initKey(int opmode, @Nullable Key key)948 protected abstract void initKey(int opmode, @Nullable Key key) throws InvalidKeyException; 949 950 /** 951 * Returns algorithm-specific parameters used by this cipher or {@code null} if no 952 * algorithm-specific parameters are used. 953 */ 954 @Nullable 955 @Override engineGetParameters()956 protected abstract AlgorithmParameters engineGetParameters(); 957 958 /** 959 * Invoked by {@code engineInit} to initialize algorithm-specific parameters when no additional 960 * initialization parameters were provided. 961 * 962 * @throws InvalidKeyException if this cipher cannot be configured based purely on the provided 963 * key and needs additional parameters to be provided to {@code Cipher.init}. 964 */ initAlgorithmSpecificParameters()965 protected abstract void initAlgorithmSpecificParameters() throws InvalidKeyException; 966 967 /** 968 * Invoked by {@code engineInit} to initialize algorithm-specific parameters when additional 969 * parameters were provided. 970 * 971 * @param params additional algorithm parameters or {@code null} if not specified. 972 * 973 * @throws InvalidAlgorithmParameterException if there is insufficient information to configure 974 * this cipher or if the provided parameters are not suitable for this cipher. 975 */ initAlgorithmSpecificParameters( @ullable AlgorithmParameterSpec params)976 protected abstract void initAlgorithmSpecificParameters( 977 @Nullable AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException; 978 979 /** 980 * Invoked by {@code engineInit} to initialize algorithm-specific parameters when additional 981 * parameters were provided. 982 * 983 * @param params additional algorithm parameters or {@code null} if not specified. 984 * 985 * @throws InvalidAlgorithmParameterException if there is insufficient information to configure 986 * this cipher or if the provided parameters are not suitable for this cipher. 987 */ initAlgorithmSpecificParameters(@ullable AlgorithmParameters params)988 protected abstract void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params) 989 throws InvalidAlgorithmParameterException; 990 991 /** 992 * Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's 993 * {@code begin} operation. This amount of entropy is typically what's consumed to generate 994 * random parameters, such as IV. 995 * 996 * <p>For decryption, the return value should be {@code 0} because decryption should not be 997 * consuming any entropy. For encryption, the value combined with 998 * {@link #getAdditionalEntropyAmountForFinish()} should match (or exceed) the amount of Shannon 999 * entropy of the ciphertext produced by this cipher assuming the key, the plaintext, and all 1000 * explicitly provided parameters to {@code Cipher.init} are known. For example, for AES CBC 1001 * encryption with an explicitly provided IV the return value should be {@code 0}, whereas for 1002 * the case where IV is generated by the KeyStore's {@code begin} operation it should be 1003 * {@code 16}. 1004 */ getAdditionalEntropyAmountForBegin()1005 protected abstract int getAdditionalEntropyAmountForBegin(); 1006 1007 /** 1008 * Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's 1009 * {@code finish} operation. This amount of entropy is typically what's consumed by encryption 1010 * padding scheme. 1011 * 1012 * <p>For decryption, the return value should be {@code 0} because decryption should not be 1013 * consuming any entropy. For encryption, the value combined with 1014 * {@link #getAdditionalEntropyAmountForBegin()} should match (or exceed) the amount of Shannon 1015 * entropy of the ciphertext produced by this cipher assuming the key, the plaintext, and all 1016 * explicitly provided parameters to {@code Cipher.init} are known. For example, for RSA with 1017 * OAEP the return value should be the size of the OAEP hash output. For RSA with PKCS#1 padding 1018 * the return value should be the size of the padding string or could be raised (for simplicity) 1019 * to the size of the modulus. 1020 */ getAdditionalEntropyAmountForFinish()1021 protected abstract int getAdditionalEntropyAmountForFinish(); 1022 1023 /** 1024 * Invoked to add algorithm-specific parameters for the KeyStore's {@code begin} operation. 1025 * 1026 * @param parameters keystore/keymaster arguments to be populated with algorithm-specific 1027 * parameters. 1028 */ addAlgorithmSpecificParametersToBegin( @onNull List<KeyParameter> parameters)1029 protected abstract void addAlgorithmSpecificParametersToBegin( 1030 @NonNull List<KeyParameter> parameters); 1031 1032 /** 1033 * Invoked to add algorithm-specific parameters for the KeyStore's {@code begin} operation, 1034 * including the key characteristics. This is useful in case the parameters to {@code begin} 1035 * depend on how the key was generated. 1036 * The default implementation provided here simply ignores these key characteristics because 1037 * they are not be needed for most engines. 1038 * 1039 * @param parameters keystore/keymaster arguments to be populated with algorithm-specific 1040 * parameters. 1041 * @param keyCharacteristics The key's characteristics. 1042 */ addAlgorithmSpecificParametersToBegin( @onNull List<KeyParameter> parameters, Authorization[] keyCharacteristics)1043 protected void addAlgorithmSpecificParametersToBegin( 1044 @NonNull List<KeyParameter> parameters, Authorization[] keyCharacteristics) { 1045 addAlgorithmSpecificParametersToBegin(parameters); 1046 } 1047 1048 /** 1049 * Invoked to obtain algorithm-specific parameters from the result of the KeyStore's 1050 * {@code begin} operation. 1051 * 1052 * <p>Some parameters, such as IV, are not required to be provided to {@code Cipher.init}. Such 1053 * parameters, if not provided, must be generated by KeyStore and returned to the user of 1054 * {@code Cipher} and potentially reused after {@code doFinal}. 1055 * 1056 * @param parameters keystore/keymaster arguments returned by KeyStore {@code createOperation}. 1057 */ loadAlgorithmSpecificParametersFromBeginResult( KeyParameter[] parameters)1058 protected abstract void loadAlgorithmSpecificParametersFromBeginResult( 1059 KeyParameter[] parameters); 1060 getTransform()1061 protected abstract String getTransform(); 1062 } 1063