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