1/* 2 * Copyright (C) 2012 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 17package org.conscrypt; 18 19import java.io.IOException; 20import java.lang.reflect.Constructor; 21import java.lang.reflect.InvocationTargetException; 22import java.security.AlgorithmParameters; 23import java.security.InvalidAlgorithmParameterException; 24import java.security.InvalidKeyException; 25import java.security.InvalidParameterException; 26import java.security.Key; 27import java.security.KeyFactory; 28import java.security.NoSuchAlgorithmException; 29import java.security.SecureRandom; 30import java.security.spec.AlgorithmParameterSpec; 31import java.security.spec.InvalidKeySpecException; 32import java.security.spec.InvalidParameterSpecException; 33import java.security.spec.PKCS8EncodedKeySpec; 34import java.security.spec.X509EncodedKeySpec; 35import java.util.Arrays; 36import java.util.Locale; 37import javax.crypto.BadPaddingException; 38import javax.crypto.Cipher; 39import javax.crypto.CipherSpi; 40import javax.crypto.IllegalBlockSizeException; 41import javax.crypto.NoSuchPaddingException; 42import javax.crypto.SecretKey; 43import javax.crypto.ShortBufferException; 44import javax.crypto.spec.IvParameterSpec; 45import javax.crypto.spec.SecretKeySpec; 46import org.conscrypt.NativeRef.EVP_CIPHER_CTX; 47 48/** 49 * An implementation of {@link Cipher} using BoringSSL as the backing library. 50 * 51 * @hide 52 */ 53@Internal 54public abstract class OpenSSLCipher extends CipherSpi { 55 56 /** 57 * Modes that a block cipher may support. 58 */ 59 enum Mode { 60 CBC, 61 CTR, 62 ECB, 63 GCM, 64 } 65 66 /** 67 * Paddings that a block cipher may support. 68 */ 69 enum Padding { 70 NOPADDING, 71 PKCS5PADDING, 72 ISO10126PADDING, 73 } 74 75 /** 76 * The current cipher mode. 77 */ 78 Mode mode = Mode.ECB; 79 80 /** 81 * The current cipher padding. 82 */ 83 private Padding padding = Padding.PKCS5PADDING; 84 85 /** 86 * May be used when reseting the cipher instance after calling 87 * {@code doFinal}. 88 */ 89 byte[] encodedKey; 90 91 /** 92 * The Initial Vector (IV) used for the current cipher. 93 */ 94 byte[] iv; 95 96 /** 97 * Current cipher mode: encrypting or decrypting. 98 */ 99 private boolean encrypting; 100 101 /** 102 * The block size of the current cipher. 103 */ 104 private int blockSize; 105 106 OpenSSLCipher() { 107 } 108 109 OpenSSLCipher(Mode mode, Padding padding) { 110 this.mode = mode; 111 this.padding = padding; 112 blockSize = getCipherBlockSize(); 113 } 114 115 /** 116 * API-specific implementation of initializing the cipher. The 117 * {@link #isEncrypting()} function will tell whether it should be 118 * initialized for encryption or decryption. The {@code encodedKey} will be 119 * the bytes of a supported key size. 120 */ 121 abstract void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params, 122 SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException; 123 124 /** 125 * API-specific implementation of updating the cipher. The 126 * {@code maximumLen} will be the maximum length of the output as returned 127 * by {@link #getOutputSizeForUpdate(int)}. The return value must be the 128 * number of bytes processed and placed into {@code output}. On error, an 129 * exception must be thrown. 130 */ 131 abstract int updateInternal(byte[] input, int inputOffset, int inputLen, 132 byte[] output, int outputOffset, int maximumLen) throws ShortBufferException; 133 134 /** 135 * API-specific implementation of the final block. The {@code maximumLen} 136 * will be the maximum length of the possible output as returned by 137 * {@link #getOutputSizeForFinal(int)}. The return value must be the number 138 * of bytes processed and placed into {@code output}. On error, an exception 139 * must be thrown. 140 */ 141 abstract int doFinalInternal(byte[] output, int outputOffset, int maximumLen) 142 throws IllegalBlockSizeException, BadPaddingException, ShortBufferException; 143 144 /** 145 * Returns the standard name for the particular algorithm. 146 */ 147 abstract String getBaseCipherName(); 148 149 /** 150 * Checks whether the cipher supports this particular {@code keySize} (in 151 * bytes) and throws {@code InvalidKeyException} if it doesn't. 152 */ 153 abstract void checkSupportedKeySize(int keySize) throws InvalidKeyException; 154 155 /** 156 * Checks whether the cipher supports this particular cipher {@code mode} 157 * and throws {@code NoSuchAlgorithmException} if it doesn't. 158 */ 159 abstract void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException; 160 161 /** 162 * Checks whether the cipher supports this particular cipher {@code padding} 163 * and throws {@code NoSuchPaddingException} if it doesn't. 164 */ 165 abstract void checkSupportedPadding(Padding padding) throws NoSuchPaddingException; 166 167 abstract int getCipherBlockSize(); 168 169 boolean supportsVariableSizeKey() { 170 return false; 171 } 172 173 boolean supportsVariableSizeIv() { 174 return false; 175 } 176 177 @Override 178 protected void engineSetMode(String modeStr) throws NoSuchAlgorithmException { 179 final Mode mode; 180 try { 181 mode = Mode.valueOf(modeStr.toUpperCase(Locale.US)); 182 } catch (IllegalArgumentException e) { 183 NoSuchAlgorithmException newE = new NoSuchAlgorithmException("No such mode: " + modeStr); 184 newE.initCause(e); 185 throw newE; 186 } 187 checkSupportedMode(mode); 188 this.mode = mode; 189 } 190 191 @Override 192 protected void engineSetPadding(String paddingStr) throws NoSuchPaddingException { 193 final String paddingStrUpper = paddingStr.toUpperCase(Locale.US); 194 final Padding padding; 195 try { 196 padding = Padding.valueOf(paddingStrUpper); 197 } catch (IllegalArgumentException e) { 198 NoSuchPaddingException newE = new NoSuchPaddingException("No such padding: " 199 + paddingStr); 200 newE.initCause(e); 201 throw newE; 202 } 203 checkSupportedPadding(padding); 204 this.padding = padding; 205 } 206 207 /** 208 * Returns the padding type for which this cipher is initialized. 209 */ 210 Padding getPadding() { 211 return padding; 212 } 213 214 @Override 215 protected int engineGetBlockSize() { 216 return blockSize; 217 } 218 219 /** 220 * The size of output if {@code doFinal()} is called with this 221 * {@code inputLen}. If padding is enabled and the size of the input puts it 222 * right at the block size, it will add another block for the padding. 223 */ 224 abstract int getOutputSizeForFinal(int inputLen); 225 226 /** 227 * The size of output if {@code update()} is called with this 228 * {@code inputLen}. If padding is enabled and the size of the input puts it 229 * right at the block size, it will add another block for the padding. 230 */ 231 abstract int getOutputSizeForUpdate(int inputLen); 232 233 @Override 234 protected int engineGetOutputSize(int inputLen) { 235 return getOutputSizeForFinal(inputLen); 236 } 237 238 @Override 239 protected byte[] engineGetIV() { 240 return iv; 241 } 242 243 @Override 244 protected AlgorithmParameters engineGetParameters() { 245 if (iv != null && iv.length > 0) { 246 try { 247 AlgorithmParameters params = AlgorithmParameters.getInstance(getBaseCipherName()); 248 params.init(iv); 249 return params; 250 } catch (NoSuchAlgorithmException e) { 251 return null; 252 } catch (IOException e) { 253 return null; 254 } 255 } 256 return null; 257 } 258 259 @Override 260 protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { 261 checkAndSetEncodedKey(opmode, key); 262 try { 263 engineInitInternal(this.encodedKey, null, random); 264 } catch (InvalidAlgorithmParameterException e) { 265 // This can't actually happen since we pass in null. 266 throw new RuntimeException(e); 267 } 268 } 269 270 @Override 271 protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, 272 SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { 273 checkAndSetEncodedKey(opmode, key); 274 engineInitInternal(this.encodedKey, params, random); 275 } 276 277 @Override 278 protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random) 279 throws InvalidKeyException, InvalidAlgorithmParameterException { 280 AlgorithmParameterSpec spec; 281 if (params != null) { 282 try { 283 spec = params.getParameterSpec(IvParameterSpec.class); 284 } catch (InvalidParameterSpecException e) { 285 throw new InvalidAlgorithmParameterException( 286 "Params must be convertible to IvParameterSpec", e); 287 } 288 } else { 289 spec = null; 290 } 291 292 engineInit(opmode, key, spec, random); 293 } 294 295 @Override 296 protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { 297 final int maximumLen = getOutputSizeForUpdate(inputLen); 298 299 /* See how large our output buffer would need to be. */ 300 final byte[] output; 301 if (maximumLen > 0) { 302 output = new byte[maximumLen]; 303 } else { 304 output = EmptyArray.BYTE; 305 } 306 307 final int bytesWritten; 308 try { 309 bytesWritten = updateInternal(input, inputOffset, inputLen, output, 0, maximumLen); 310 } catch (ShortBufferException e) { 311 /* This shouldn't happen. */ 312 throw new RuntimeException("calculated buffer size was wrong: " + maximumLen); 313 } 314 315 if (output.length == bytesWritten) { 316 return output; 317 } else if (bytesWritten == 0) { 318 return EmptyArray.BYTE; 319 } else { 320 return Arrays.copyOfRange(output, 0, bytesWritten); 321 } 322 } 323 324 @Override 325 protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, 326 int outputOffset) throws ShortBufferException { 327 final int maximumLen = getOutputSizeForUpdate(inputLen); 328 return updateInternal(input, inputOffset, inputLen, output, outputOffset, maximumLen); 329 } 330 331 @Override 332 protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) 333 throws IllegalBlockSizeException, BadPaddingException { 334 final int maximumLen = getOutputSizeForFinal(inputLen); 335 /* Assume that we'll output exactly on a byte boundary. */ 336 final byte[] output = new byte[maximumLen]; 337 338 int bytesWritten; 339 if (inputLen > 0) { 340 try { 341 bytesWritten = updateInternal(input, inputOffset, inputLen, output, 0, maximumLen); 342 } catch (ShortBufferException e) { 343 /* This should not happen since we sized our own buffer. */ 344 throw new RuntimeException("our calculated buffer was too small", e); 345 } 346 } else { 347 bytesWritten = 0; 348 } 349 350 try { 351 bytesWritten += doFinalInternal(output, bytesWritten, maximumLen - bytesWritten); 352 } catch (ShortBufferException e) { 353 /* This should not happen since we sized our own buffer. */ 354 throw new RuntimeException("our calculated buffer was too small", e); 355 } 356 357 if (bytesWritten == output.length) { 358 return output; 359 } else if (bytesWritten == 0) { 360 return EmptyArray.BYTE; 361 } else { 362 return Arrays.copyOfRange(output, 0, bytesWritten); 363 } 364 } 365 366 @Override 367 protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, 368 int outputOffset) throws ShortBufferException, IllegalBlockSizeException, 369 BadPaddingException { 370 if (output == null) { 371 throw new NullPointerException("output == null"); 372 } 373 374 int maximumLen = getOutputSizeForFinal(inputLen); 375 376 final int bytesWritten; 377 if (inputLen > 0) { 378 bytesWritten = updateInternal(input, inputOffset, inputLen, output, outputOffset, 379 maximumLen); 380 outputOffset += bytesWritten; 381 maximumLen -= bytesWritten; 382 } else { 383 bytesWritten = 0; 384 } 385 386 return bytesWritten + doFinalInternal(output, outputOffset, maximumLen); 387 } 388 389 @Override 390 protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException { 391 try { 392 byte[] encoded = key.getEncoded(); 393 return engineDoFinal(encoded, 0, encoded.length); 394 } catch (BadPaddingException e) { 395 IllegalBlockSizeException newE = new IllegalBlockSizeException(); 396 newE.initCause(e); 397 throw newE; 398 } 399 } 400 401 @Override 402 protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType) 403 throws InvalidKeyException, NoSuchAlgorithmException { 404 try { 405 byte[] encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length); 406 if (wrappedKeyType == Cipher.PUBLIC_KEY) { 407 KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm); 408 return keyFactory.generatePublic(new X509EncodedKeySpec(encoded)); 409 } else if (wrappedKeyType == Cipher.PRIVATE_KEY) { 410 KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm); 411 return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encoded)); 412 } else if (wrappedKeyType == Cipher.SECRET_KEY) { 413 return new SecretKeySpec(encoded, wrappedKeyAlgorithm); 414 } else { 415 throw new UnsupportedOperationException("wrappedKeyType == " + wrappedKeyType); 416 } 417 } catch (IllegalBlockSizeException e) { 418 throw new InvalidKeyException(e); 419 } catch (BadPaddingException e) { 420 throw new InvalidKeyException(e); 421 } catch (InvalidKeySpecException e) { 422 throw new InvalidKeyException(e); 423 } 424 } 425 426 private byte[] checkAndSetEncodedKey(int opmode, Key key) throws InvalidKeyException { 427 if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) { 428 encrypting = true; 429 } else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE) { 430 encrypting = false; 431 } else { 432 throw new InvalidParameterException("Unsupported opmode " + opmode); 433 } 434 435 if (!(key instanceof SecretKey)) { 436 throw new InvalidKeyException("Only SecretKey is supported"); 437 } 438 439 final byte[] encodedKey = key.getEncoded(); 440 if (encodedKey == null) { 441 throw new InvalidKeyException("key.getEncoded() == null"); 442 } 443 checkSupportedKeySize(encodedKey.length); 444 this.encodedKey = encodedKey; 445 return encodedKey; 446 } 447 448 boolean isEncrypting() { 449 return encrypting; 450 } 451 452 public static abstract class EVP_CIPHER extends OpenSSLCipher { 453 /** 454 * Native pointer for the OpenSSL EVP_CIPHER context. 455 */ 456 private final EVP_CIPHER_CTX cipherCtx = new EVP_CIPHER_CTX( 457 NativeCrypto.EVP_CIPHER_CTX_new()); 458 459 /** 460 * Whether the cipher has processed any data yet. EVP_CIPHER doesn't 461 * like calling "doFinal()" in decryption mode without processing any 462 * updates. 463 */ 464 boolean calledUpdate; 465 466 /** 467 * The block size of the current mode. 468 */ 469 private int modeBlockSize; 470 471 public EVP_CIPHER(Mode mode, Padding padding) { 472 super(mode, padding); 473 } 474 475 @Override 476 void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params, 477 SecureRandom random) throws InvalidKeyException, 478 InvalidAlgorithmParameterException { 479 byte[] iv; 480 if (params instanceof IvParameterSpec) { 481 IvParameterSpec ivParams = (IvParameterSpec) params; 482 iv = ivParams.getIV(); 483 } else { 484 iv = null; 485 } 486 487 final long cipherType = NativeCrypto.EVP_get_cipherbyname(getCipherName( 488 encodedKey.length, mode)); 489 if (cipherType == 0) { 490 throw new InvalidAlgorithmParameterException("Cannot find name for key length = " 491 + (encodedKey.length * 8) + " and mode = " + mode); 492 } 493 494 final boolean encrypting = isEncrypting(); 495 496 final int expectedIvLength = NativeCrypto.EVP_CIPHER_iv_length(cipherType); 497 if (iv == null && expectedIvLength != 0) { 498 if (!encrypting) { 499 throw new InvalidAlgorithmParameterException("IV must be specified in " + mode 500 + " mode"); 501 } 502 503 iv = new byte[expectedIvLength]; 504 if (random != null) { 505 random.nextBytes(iv); 506 } else { 507 NativeCrypto.RAND_bytes(iv); 508 } 509 } else if (expectedIvLength == 0 && iv != null) { 510 throw new InvalidAlgorithmParameterException("IV not used in " + mode + " mode"); 511 } else if (iv != null && iv.length != expectedIvLength) { 512 throw new InvalidAlgorithmParameterException("expected IV length of " 513 + expectedIvLength + " but was " + iv.length); 514 } 515 516 this.iv = iv; 517 518 if (supportsVariableSizeKey()) { 519 NativeCrypto.EVP_CipherInit_ex(cipherCtx, cipherType, null, null, encrypting); 520 NativeCrypto.EVP_CIPHER_CTX_set_key_length(cipherCtx, encodedKey.length); 521 NativeCrypto.EVP_CipherInit_ex(cipherCtx, 0, encodedKey, iv, isEncrypting()); 522 } else { 523 NativeCrypto.EVP_CipherInit_ex(cipherCtx, cipherType, encodedKey, iv, encrypting); 524 } 525 526 // OpenSSL only supports PKCS5 Padding. 527 NativeCrypto 528 .EVP_CIPHER_CTX_set_padding(cipherCtx, getPadding() == Padding.PKCS5PADDING); 529 modeBlockSize = NativeCrypto.EVP_CIPHER_CTX_block_size(cipherCtx); 530 calledUpdate = false; 531 } 532 533 @Override 534 int updateInternal(byte[] input, int inputOffset, int inputLen, byte[] output, 535 int outputOffset, int maximumLen) throws ShortBufferException { 536 final int intialOutputOffset = outputOffset; 537 538 final int bytesLeft = output.length - outputOffset; 539 if (bytesLeft < maximumLen) { 540 throw new ShortBufferException("output buffer too small during update: " 541 + bytesLeft + " < " + maximumLen); 542 } 543 544 outputOffset += NativeCrypto.EVP_CipherUpdate(cipherCtx, output, outputOffset, input, 545 inputOffset, inputLen); 546 547 calledUpdate = true; 548 549 return outputOffset - intialOutputOffset; 550 } 551 552 @Override 553 int doFinalInternal(byte[] output, int outputOffset, int maximumLen) 554 throws IllegalBlockSizeException, BadPaddingException, ShortBufferException { 555 /* Remember this so we can tell how many characters were written. */ 556 final int initialOutputOffset = outputOffset; 557 558 /* 559 * If we're decrypting and haven't had any input, we should return 560 * null. Otherwise OpenSSL will complain if we call final. 561 */ 562 if (!isEncrypting() && !calledUpdate) { 563 return 0; 564 } 565 566 /* Allow OpenSSL to pad if necessary and clean up state. */ 567 final int bytesLeft = output.length - outputOffset; 568 final int writtenBytes; 569 if (bytesLeft >= maximumLen) { 570 writtenBytes = NativeCrypto.EVP_CipherFinal_ex(cipherCtx, output, outputOffset); 571 } else { 572 final byte[] lastBlock = new byte[maximumLen]; 573 writtenBytes = NativeCrypto.EVP_CipherFinal_ex(cipherCtx, lastBlock, 0); 574 if (writtenBytes > bytesLeft) { 575 throw new ShortBufferException("buffer is too short: " + writtenBytes + " > " 576 + bytesLeft); 577 } else if (writtenBytes > 0) { 578 System.arraycopy(lastBlock, 0, output, outputOffset, writtenBytes); 579 } 580 } 581 outputOffset += writtenBytes; 582 583 reset(); 584 585 return outputOffset - initialOutputOffset; 586 } 587 588 @Override 589 int getOutputSizeForFinal(int inputLen) { 590 if (modeBlockSize == 1) { 591 return inputLen; 592 } else { 593 final int buffered = NativeCrypto.get_EVP_CIPHER_CTX_buf_len(cipherCtx); 594 595 if (getPadding() == Padding.NOPADDING) { 596 return buffered + inputLen; 597 } else { 598 final boolean finalUsed = NativeCrypto.get_EVP_CIPHER_CTX_final_used(cipherCtx); 599 // There is an additional buffer containing the possible final block. 600 int totalLen = inputLen + buffered + (finalUsed ? modeBlockSize : 0); 601 // Extra block for remainder bytes plus padding. 602 // In case it's encrypting and there are no remainder bytes, add an extra block 603 // consisting only of padding. 604 totalLen += ((totalLen % modeBlockSize != 0) || isEncrypting()) 605 ? modeBlockSize : 0; 606 // The minimum multiple of {@code modeBlockSize} that can hold all the bytes. 607 return totalLen - (totalLen % modeBlockSize); 608 } 609 } 610 } 611 612 @Override 613 int getOutputSizeForUpdate(int inputLen) { 614 return getOutputSizeForFinal(inputLen); 615 } 616 617 /** 618 * Returns the OpenSSL cipher name for the particular {@code keySize} 619 * and cipher {@code mode}. 620 */ 621 abstract String getCipherName(int keySize, Mode mode); 622 623 /** 624 * Reset this Cipher instance state to process a new chunk of data. 625 */ 626 private void reset() { 627 NativeCrypto.EVP_CipherInit_ex(cipherCtx, 0, encodedKey, iv, isEncrypting()); 628 calledUpdate = false; 629 } 630 631 abstract static class AES_BASE extends EVP_CIPHER { 632 private static final int AES_BLOCK_SIZE = 16; 633 634 AES_BASE(Mode mode, Padding padding) { 635 super(mode, padding); 636 } 637 638 @Override 639 void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException { 640 switch (mode) { 641 case CBC: 642 case CTR: 643 case ECB: 644 return; 645 default: 646 throw new NoSuchAlgorithmException("Unsupported mode " + mode.toString()); 647 } 648 } 649 650 @Override 651 void checkSupportedPadding(Padding padding) throws NoSuchPaddingException { 652 switch (padding) { 653 case NOPADDING: 654 case PKCS5PADDING: 655 return; 656 default: 657 throw new NoSuchPaddingException( 658 "Unsupported padding " + padding.toString()); 659 } 660 } 661 662 @Override 663 String getBaseCipherName() { 664 return "AES"; 665 } 666 667 @Override 668 String getCipherName(int keyLength, Mode mode) { 669 return "aes-" + (keyLength * 8) + "-" + mode.toString().toLowerCase(Locale.US); 670 } 671 672 @Override 673 int getCipherBlockSize() { 674 return AES_BLOCK_SIZE; 675 } 676 } 677 678 public static class AES extends AES_BASE { 679 AES(Mode mode, Padding padding) { 680 super(mode, padding); 681 } 682 683 public static class CBC extends AES { 684 public CBC(Padding padding) { 685 super(Mode.CBC, padding); 686 } 687 688 public static class NoPadding extends CBC { 689 public NoPadding() { 690 super(Padding.NOPADDING); 691 } 692 } 693 694 public static class PKCS5Padding extends CBC { 695 public PKCS5Padding() { 696 super(Padding.PKCS5PADDING); 697 } 698 } 699 } 700 701 public static class CTR extends AES { 702 public CTR() { 703 super(Mode.CTR, Padding.NOPADDING); 704 } 705 } 706 707 public static class ECB extends AES { 708 public ECB(Padding padding) { 709 super(Mode.ECB, padding); 710 } 711 712 public static class NoPadding extends ECB { 713 public NoPadding() { 714 super(Padding.NOPADDING); 715 } 716 } 717 718 public static class PKCS5Padding extends ECB { 719 public PKCS5Padding() { 720 super(Padding.PKCS5PADDING); 721 } 722 } 723 } 724 725 @Override 726 void checkSupportedKeySize(int keyLength) throws InvalidKeyException { 727 switch (keyLength) { 728 case 16: // AES 128 729 case 24: // AES 192 730 case 32: // AES 256 731 return; 732 default: 733 throw new InvalidKeyException("Unsupported key size: " + keyLength 734 + " bytes"); 735 } 736 } 737 } 738 739 public static class AES_128 extends AES_BASE { 740 AES_128(Mode mode, Padding padding) { 741 super(mode, padding); 742 } 743 744 public static class CBC extends AES_128 { 745 public CBC(Padding padding) { 746 super(Mode.CBC, padding); 747 } 748 749 public static class NoPadding extends CBC { 750 public NoPadding() { 751 super(Padding.NOPADDING); 752 } 753 } 754 755 public static class PKCS5Padding extends CBC { 756 public PKCS5Padding() { 757 super(Padding.PKCS5PADDING); 758 } 759 } 760 } 761 762 public static class CTR extends AES_128 { 763 public CTR() { 764 super(Mode.CTR, Padding.NOPADDING); 765 } 766 } 767 768 public static class ECB extends AES_128 { 769 public ECB(Padding padding) { 770 super(Mode.ECB, padding); 771 } 772 773 public static class NoPadding extends ECB { 774 public NoPadding() { 775 super(Padding.NOPADDING); 776 } 777 } 778 779 public static class PKCS5Padding extends ECB { 780 public PKCS5Padding() { 781 super(Padding.PKCS5PADDING); 782 } 783 } 784 } 785 786 @Override 787 void checkSupportedKeySize(int keyLength) throws InvalidKeyException { 788 if (keyLength != 16) { // 128 bits 789 throw new InvalidKeyException("Unsupported key size: " + keyLength + " bytes"); 790 } 791 } 792 } 793 794 public static class AES_256 extends AES_BASE { 795 AES_256(Mode mode, Padding padding) { 796 super(mode, padding); 797 } 798 799 public static class CBC extends AES_256 { 800 public CBC(Padding padding) { 801 super(Mode.CBC, padding); 802 } 803 804 public static class NoPadding extends CBC { 805 public NoPadding() { 806 super(Padding.NOPADDING); 807 } 808 } 809 810 public static class PKCS5Padding extends CBC { 811 public PKCS5Padding() { 812 super(Padding.PKCS5PADDING); 813 } 814 } 815 } 816 817 public static class CTR extends AES_256 { 818 public CTR() { 819 super(Mode.CTR, Padding.NOPADDING); 820 } 821 } 822 823 public static class ECB extends AES_256 { 824 public ECB(Padding padding) { 825 super(Mode.ECB, padding); 826 } 827 828 public static class NoPadding extends ECB { 829 public NoPadding() { 830 super(Padding.NOPADDING); 831 } 832 } 833 834 public static class PKCS5Padding extends ECB { 835 public PKCS5Padding() { 836 super(Padding.PKCS5PADDING); 837 } 838 } 839 } 840 841 @Override 842 void checkSupportedKeySize(int keyLength) throws InvalidKeyException { 843 if (keyLength != 32) { // 256 bits 844 throw new InvalidKeyException("Unsupported key size: " + keyLength + " bytes"); 845 } 846 } 847 } 848 849 public static class DESEDE extends EVP_CIPHER { 850 private static final int DES_BLOCK_SIZE = 8; 851 852 public DESEDE(Mode mode, Padding padding) { 853 super(mode, padding); 854 } 855 856 public static class CBC extends DESEDE { 857 public CBC(Padding padding) { 858 super(Mode.CBC, padding); 859 } 860 861 public static class NoPadding extends CBC { 862 public NoPadding() { 863 super(Padding.NOPADDING); 864 } 865 } 866 867 public static class PKCS5Padding extends CBC { 868 public PKCS5Padding() { 869 super(Padding.PKCS5PADDING); 870 } 871 } 872 } 873 874 @Override 875 String getBaseCipherName() { 876 return "DESede"; 877 } 878 879 @Override 880 String getCipherName(int keySize, Mode mode) { 881 final String baseCipherName; 882 if (keySize == 16) { 883 baseCipherName = "des-ede"; 884 } else { 885 baseCipherName = "des-ede3"; 886 } 887 888 return baseCipherName + "-" + mode.toString().toLowerCase(Locale.US); 889 } 890 891 @Override 892 void checkSupportedKeySize(int keySize) throws InvalidKeyException { 893 if (keySize != 16 && keySize != 24) { 894 throw new InvalidKeyException("key size must be 128 or 192 bits"); 895 } 896 } 897 898 @Override 899 void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException { 900 if (mode != Mode.CBC) { 901 throw new NoSuchAlgorithmException("Unsupported mode " + mode.toString()); 902 } 903 } 904 905 @Override 906 void checkSupportedPadding(Padding padding) throws NoSuchPaddingException { 907 switch (padding) { 908 case NOPADDING: 909 case PKCS5PADDING: 910 return; 911 default: 912 throw new NoSuchPaddingException("Unsupported padding " 913 + padding.toString()); 914 } 915 } 916 917 @Override 918 int getCipherBlockSize() { 919 return DES_BLOCK_SIZE; 920 } 921 } 922 923 public static class ARC4 extends EVP_CIPHER { 924 public ARC4() { 925 // Modes and padding don't make sense for ARC4. 926 super(Mode.ECB, Padding.NOPADDING); 927 } 928 929 @Override 930 String getBaseCipherName() { 931 return "ARCFOUR"; 932 } 933 934 @Override 935 String getCipherName(int keySize, Mode mode) { 936 return "rc4"; 937 } 938 939 @Override 940 void checkSupportedKeySize(int keySize) throws InvalidKeyException { 941 } 942 943 @Override 944 void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException { 945 throw new NoSuchAlgorithmException("ARC4 does not support modes"); 946 } 947 948 @Override 949 void checkSupportedPadding(Padding padding) throws NoSuchPaddingException { 950 throw new NoSuchPaddingException("ARC4 does not support padding"); 951 } 952 953 @Override 954 int getCipherBlockSize() { 955 return 0; 956 } 957 958 @Override 959 boolean supportsVariableSizeKey() { 960 return true; 961 } 962 } 963 } 964 965 public static abstract class EVP_AEAD extends OpenSSLCipher { 966 /** 967 * The default tag size when one is not specified. Default to 968 * full-length tags (128-bits or 16 octets). 969 */ 970 private static final int DEFAULT_TAG_SIZE_BITS = 16 * 8; 971 972 /** 973 * Keeps track of the last used block size. 974 */ 975 private static int lastGlobalMessageSize = 32; 976 977 /** 978 * The byte array containing the bytes written. 979 */ 980 byte[] buf; 981 982 /** 983 * The number of bytes written. 984 */ 985 int bufCount; 986 987 /** 988 * AEAD cipher reference. 989 */ 990 long evpAead; 991 992 /** 993 * Additional authenticated data. 994 */ 995 private byte[] aad; 996 997 /** 998 * The length of the AEAD cipher tag in bytes. 999 */ 1000 private int tagLengthInBytes; 1001 1002 public EVP_AEAD(Mode mode) { 1003 super(mode, Padding.NOPADDING); 1004 } 1005 1006 private void expand(int i) { 1007 /* Can the buffer handle i more bytes, if not expand it */ 1008 if (bufCount + i <= buf.length) { 1009 return; 1010 } 1011 1012 byte[] newbuf = new byte[(bufCount + i) * 2]; 1013 System.arraycopy(buf, 0, newbuf, 0, bufCount); 1014 buf = newbuf; 1015 } 1016 1017 private void reset() { 1018 aad = null; 1019 final int lastBufSize = lastGlobalMessageSize; 1020 if (buf == null) { 1021 buf = new byte[lastBufSize]; 1022 } else if (bufCount > 0 && bufCount != lastBufSize) { 1023 lastGlobalMessageSize = bufCount; 1024 if (buf.length != bufCount) { 1025 buf = new byte[bufCount]; 1026 } 1027 } 1028 bufCount = 0; 1029 } 1030 1031 @Override 1032 void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params, 1033 SecureRandom random) throws InvalidKeyException, 1034 InvalidAlgorithmParameterException { 1035 byte[] iv; 1036 final int tagLenBits; 1037 if (params == null) { 1038 iv = null; 1039 tagLenBits = DEFAULT_TAG_SIZE_BITS; 1040 } else { 1041 GCMParameters gcmParams = Platform.fromGCMParameterSpec(params); 1042 if (gcmParams != null) { 1043 iv = gcmParams.getIV(); 1044 tagLenBits = gcmParams.getTLen(); 1045 } else if (params instanceof IvParameterSpec) { 1046 IvParameterSpec ivParams = (IvParameterSpec) params; 1047 iv = ivParams.getIV(); 1048 tagLenBits = DEFAULT_TAG_SIZE_BITS; 1049 } else { 1050 iv = null; 1051 tagLenBits = DEFAULT_TAG_SIZE_BITS; 1052 } 1053 } 1054 1055 if (tagLenBits % 8 != 0) { 1056 throw new InvalidAlgorithmParameterException( 1057 "Tag length must be a multiple of 8; was " + tagLengthInBytes); 1058 } 1059 1060 tagLengthInBytes = tagLenBits / 8; 1061 1062 final boolean encrypting = isEncrypting(); 1063 1064 evpAead = getEVP_AEAD(encodedKey.length); 1065 1066 final int expectedIvLength = NativeCrypto.EVP_AEAD_nonce_length(evpAead); 1067 if (iv == null && expectedIvLength != 0) { 1068 if (!encrypting) { 1069 throw new InvalidAlgorithmParameterException("IV must be specified in " + mode 1070 + " mode"); 1071 } 1072 1073 iv = new byte[expectedIvLength]; 1074 if (random != null) { 1075 random.nextBytes(iv); 1076 } else { 1077 NativeCrypto.RAND_bytes(iv); 1078 } 1079 } else if (expectedIvLength == 0 && iv != null) { 1080 throw new InvalidAlgorithmParameterException("IV not used in " + mode + " mode"); 1081 } else if (iv != null && iv.length != expectedIvLength) { 1082 throw new InvalidAlgorithmParameterException("Expected IV length of " 1083 + expectedIvLength + " but was " + iv.length); 1084 } 1085 1086 this.iv = iv; 1087 reset(); 1088 } 1089 1090 @Override 1091 int updateInternal(byte[] input, int inputOffset, int inputLen, byte[] output, 1092 int outputOffset, int maximumLen) throws ShortBufferException { 1093 if (buf == null) { 1094 throw new IllegalStateException("Cipher not initialized"); 1095 } 1096 1097 ArrayUtils.checkOffsetAndCount(input.length, inputOffset, inputLen); 1098 if (inputLen > 0) { 1099 expand(inputLen); 1100 System.arraycopy(input, inputOffset, buf, this.bufCount, inputLen); 1101 this.bufCount += inputLen; 1102 } 1103 return 0; 1104 } 1105 1106 @SuppressWarnings("LiteralClassName") 1107 private void throwAEADBadTagExceptionIfAvailable(String message, Throwable cause) 1108 throws BadPaddingException { 1109 Constructor<?> aeadBadTagConstructor; 1110 try { 1111 aeadBadTagConstructor = Class.forName("javax.crypto.AEADBadTagException") 1112 .getConstructor(String.class); 1113 } catch (Exception ignored) { 1114 return; 1115 } 1116 1117 BadPaddingException badTagException = null; 1118 try { 1119 badTagException = (BadPaddingException) aeadBadTagConstructor.newInstance(message); 1120 badTagException.initCause(cause); 1121 } catch (IllegalAccessException e2) { 1122 // Fall through 1123 } catch (InstantiationException e2) { 1124 // Fall through 1125 } catch (InvocationTargetException e2) { 1126 throw(BadPaddingException) new BadPaddingException().initCause( 1127 e2.getTargetException()); 1128 } 1129 if (badTagException != null) { 1130 throw badTagException; 1131 } 1132 } 1133 1134 @Override 1135 int doFinalInternal(byte[] output, int outputOffset, int maximumLen) 1136 throws IllegalBlockSizeException, BadPaddingException { 1137 final int bytesWritten; 1138 try { 1139 if (isEncrypting()) { 1140 bytesWritten = NativeCrypto.EVP_AEAD_CTX_seal(evpAead, encodedKey, 1141 tagLengthInBytes, output, outputOffset, iv, buf, 0, bufCount, aad); 1142 } else { 1143 bytesWritten = NativeCrypto.EVP_AEAD_CTX_open(evpAead, encodedKey, 1144 tagLengthInBytes, output, outputOffset, iv, buf, 0, bufCount, aad); 1145 } 1146 } catch (BadPaddingException e) { 1147 throwAEADBadTagExceptionIfAvailable(e.getMessage(), e.getCause()); 1148 throw e; 1149 } 1150 reset(); 1151 return bytesWritten; 1152 } 1153 1154 @Override 1155 void checkSupportedPadding(Padding padding) throws NoSuchPaddingException { 1156 if (padding != Padding.NOPADDING) { 1157 throw new NoSuchPaddingException("Must be NoPadding for AEAD ciphers"); 1158 } 1159 } 1160 1161 @Override 1162 int getOutputSizeForFinal(int inputLen) { 1163 return bufCount + inputLen 1164 + (isEncrypting() ? NativeCrypto.EVP_AEAD_max_overhead(evpAead) : 0); 1165 } 1166 1167 // Intentionally missing Override to compile on old versions of Android 1168 @SuppressWarnings("MissingOverride") 1169 protected void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) { 1170 if (aad == null) { 1171 aad = Arrays.copyOfRange(input, inputOffset, inputOffset + inputLen); 1172 } else { 1173 int newSize = aad.length + inputLen; 1174 byte[] newaad = new byte[newSize]; 1175 System.arraycopy(aad, 0, newaad, 0, aad.length); 1176 System.arraycopy(input, inputOffset, newaad, aad.length, inputLen); 1177 aad = newaad; 1178 } 1179 } 1180 1181 @Override 1182 protected AlgorithmParameters engineGetParameters() { 1183 // iv will be non-null after initialization. 1184 if (iv == null) { 1185 return null; 1186 } 1187 1188 AlgorithmParameterSpec spec = Platform.toGCMParameterSpec(tagLengthInBytes * 8, iv); 1189 if (spec == null) { 1190 // The platform doesn't support GCMParameterSpec. Fall back to 1191 // the generic AES parameters so at least the caller can get the 1192 // IV. 1193 return super.engineGetParameters(); 1194 } 1195 1196 try { 1197 AlgorithmParameters params = AlgorithmParameters.getInstance("GCM"); 1198 params.init(spec); 1199 return params; 1200 } catch (NoSuchAlgorithmException | InvalidParameterSpecException e) { 1201 // This may happen since Conscrypt doesn't provide this itself. 1202 return null; 1203 } 1204 } 1205 1206 abstract long getEVP_AEAD(int keyLength) throws InvalidKeyException; 1207 1208 public abstract static class AES extends EVP_AEAD { 1209 private static final int AES_BLOCK_SIZE = 16; 1210 1211 AES(Mode mode) { 1212 super(mode); 1213 } 1214 1215 @Override 1216 void checkSupportedKeySize(int keyLength) throws InvalidKeyException { 1217 switch (keyLength) { 1218 case 16: // AES 128 1219 case 32: // AES 256 1220 return; 1221 default: 1222 throw new InvalidKeyException("Unsupported key size: " + keyLength 1223 + " bytes (must be 16 or 32)"); 1224 } 1225 } 1226 1227 @Override 1228 String getBaseCipherName() { 1229 return "AES"; 1230 } 1231 1232 @Override 1233 int getCipherBlockSize() { 1234 return AES_BLOCK_SIZE; 1235 } 1236 1237 /** 1238 * AEAD buffers everything until a final output. 1239 */ 1240 @Override 1241 int getOutputSizeForUpdate(int inputLen) { 1242 return 0; 1243 } 1244 1245 public static class GCM extends AES { 1246 /** 1247 * The previously used key to prevent key + nonce (IV) reuse. 1248 */ 1249 private byte[] previousKey; 1250 1251 /** 1252 * The previously used nonce (IV) to prevent key + nonce reuse. 1253 */ 1254 private byte[] previousIv; 1255 1256 /** 1257 * When set this instance must be initialized before use again. This prevents key 1258 * and IV reuse. 1259 */ 1260 private boolean mustInitialize; 1261 1262 public GCM() { 1263 super(Mode.GCM); 1264 } 1265 1266 private void checkInitialization() { 1267 if (mustInitialize) { 1268 throw new IllegalStateException( 1269 "Cannot re-use same key and IV for multiple encryptions"); 1270 } 1271 } 1272 1273 /** Constant time array comparison. */ 1274 private boolean arraysAreEqual(byte[] a, byte[] b) { 1275 if (a.length != b.length) { 1276 return false; 1277 } 1278 1279 int diff = 0; 1280 for (int i = 0; i < a.length; i++) { 1281 diff |= a[i] ^ b[i]; 1282 } 1283 return diff == 0; 1284 } 1285 1286 @Override 1287 void engineInitInternal( 1288 byte[] encodedKey, AlgorithmParameterSpec params, SecureRandom random) 1289 throws InvalidKeyException, InvalidAlgorithmParameterException { 1290 super.engineInitInternal(encodedKey, params, random); 1291 1292 if (isEncrypting() && iv != null) { 1293 if (previousKey != null && previousIv != null 1294 && arraysAreEqual(previousKey, encodedKey) 1295 && arraysAreEqual(previousIv, iv)) { 1296 mustInitialize = true; 1297 throw new InvalidAlgorithmParameterException( 1298 "In GCM mode key and IV must not be re-used"); 1299 } 1300 1301 this.previousKey = encodedKey; 1302 this.previousIv = iv; 1303 } 1304 mustInitialize = false; 1305 } 1306 1307 @Override 1308 int updateInternal(byte[] input, int inputOffset, int inputLen, 1309 byte[] output, int outputOffset, int maximumLen) 1310 throws ShortBufferException { 1311 checkInitialization(); 1312 return super.updateInternal( 1313 input, inputOffset, inputLen, output, outputOffset, maximumLen); 1314 } 1315 1316 @Override 1317 int doFinalInternal(byte[] output, int outputOffset, int maximumLen) 1318 throws IllegalBlockSizeException, BadPaddingException { 1319 checkInitialization(); 1320 int retVal = super.doFinalInternal(output, outputOffset, maximumLen); 1321 if (isEncrypting()) { 1322 mustInitialize = true; 1323 } 1324 return retVal; 1325 } 1326 1327 @Override 1328 protected void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) { 1329 checkInitialization(); 1330 super.engineUpdateAAD(input, inputOffset, inputLen); 1331 } 1332 1333 @Override 1334 void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException { 1335 if (mode != Mode.GCM) { 1336 throw new NoSuchAlgorithmException("Mode must be GCM"); 1337 } 1338 } 1339 1340 @Override 1341 long getEVP_AEAD(int keyLength) throws InvalidKeyException { 1342 if (keyLength == 16) { 1343 return NativeCrypto.EVP_aead_aes_128_gcm(); 1344 } else if (keyLength == 32) { 1345 return NativeCrypto.EVP_aead_aes_256_gcm(); 1346 } else { 1347 throw new RuntimeException("Unexpected key length: " + keyLength); 1348 } 1349 } 1350 1351 public static class AES_128 extends GCM { 1352 @Override 1353 void checkSupportedKeySize(int keyLength) throws InvalidKeyException { 1354 if (keyLength != 16) { // 128 bits 1355 throw new InvalidKeyException( 1356 "Unsupported key size: " + keyLength + " bytes (must be 16)"); 1357 } 1358 } 1359 } 1360 1361 public static class AES_256 extends GCM { 1362 @Override 1363 void checkSupportedKeySize(int keyLength) throws InvalidKeyException { 1364 if (keyLength != 32) { // 256 bits 1365 throw new InvalidKeyException( 1366 "Unsupported key size: " + keyLength + " bytes (must be 32)"); 1367 } 1368 } 1369 } 1370 } 1371 } 1372 } 1373} 1374