1 package org.bouncycastle.jcajce.provider.symmetric.util; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Method; 5 import java.nio.ByteBuffer; 6 import java.security.AlgorithmParameters; 7 import java.security.InvalidAlgorithmParameterException; 8 import java.security.InvalidKeyException; 9 import java.security.InvalidParameterException; 10 import java.security.Key; 11 import java.security.NoSuchAlgorithmException; 12 import java.security.SecureRandom; 13 import java.security.spec.AlgorithmParameterSpec; 14 15 import javax.crypto.BadPaddingException; 16 import javax.crypto.Cipher; 17 import javax.crypto.IllegalBlockSizeException; 18 import javax.crypto.NoSuchPaddingException; 19 import javax.crypto.SecretKey; 20 import javax.crypto.ShortBufferException; 21 import javax.crypto.spec.IvParameterSpec; 22 import javax.crypto.spec.PBEParameterSpec; 23 // BEGIN android-removed 24 // import javax.crypto.spec.RC2ParameterSpec; 25 // import javax.crypto.spec.RC5ParameterSpec; 26 // END android-removed 27 28 import org.bouncycastle.asn1.cms.GCMParameters; 29 import org.bouncycastle.crypto.BlockCipher; 30 import org.bouncycastle.crypto.BufferedBlockCipher; 31 import org.bouncycastle.crypto.CipherParameters; 32 import org.bouncycastle.crypto.DataLengthException; 33 import org.bouncycastle.crypto.InvalidCipherTextException; 34 import org.bouncycastle.crypto.OutputLengthException; 35 import org.bouncycastle.crypto.modes.AEADBlockCipher; 36 import org.bouncycastle.crypto.modes.CBCBlockCipher; 37 import org.bouncycastle.crypto.modes.CCMBlockCipher; 38 import org.bouncycastle.crypto.modes.CFBBlockCipher; 39 import org.bouncycastle.crypto.modes.CTSBlockCipher; 40 // BEGIN android-removed 41 // import org.bouncycastle.crypto.modes.EAXBlockCipher; 42 // import org.bouncycastle.crypto.modes.GCFBBlockCipher; 43 // END android-removed 44 import org.bouncycastle.crypto.modes.GCMBlockCipher; 45 // BEGIN android-removed 46 // import org.bouncycastle.crypto.modes.GOFBBlockCipher; 47 // import org.bouncycastle.crypto.modes.OCBBlockCipher; 48 // END android-removed 49 import org.bouncycastle.crypto.modes.OFBBlockCipher; 50 // BEGIN android-removed 51 // import org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher; 52 // import org.bouncycastle.crypto.modes.PGPCFBBlockCipher; 53 // END android-removed 54 import org.bouncycastle.crypto.modes.SICBlockCipher; 55 import org.bouncycastle.crypto.paddings.BlockCipherPadding; 56 import org.bouncycastle.crypto.paddings.ISO10126d2Padding; 57 import org.bouncycastle.crypto.paddings.ISO7816d4Padding; 58 import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; 59 import org.bouncycastle.crypto.paddings.TBCPadding; 60 import org.bouncycastle.crypto.paddings.X923Padding; 61 import org.bouncycastle.crypto.paddings.ZeroBytePadding; 62 import org.bouncycastle.crypto.params.AEADParameters; 63 import org.bouncycastle.crypto.params.KeyParameter; 64 import org.bouncycastle.crypto.params.ParametersWithIV; 65 import org.bouncycastle.crypto.params.ParametersWithRandom; 66 // BEGIN android-removed 67 // import org.bouncycastle.crypto.params.ParametersWithSBox; 68 // END android-removed 69 import org.bouncycastle.crypto.params.RC2Parameters; 70 // BEGIN android-removed 71 // import org.bouncycastle.crypto.params.RC5Parameters; 72 // import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec; 73 // import org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec; 74 // END android-removed 75 import org.bouncycastle.jce.provider.BouncyCastleProvider; 76 import org.bouncycastle.util.Strings; 77 78 public class BaseBlockCipher 79 extends BaseWrapCipher 80 implements PBE 81 { 82 private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec"); 83 84 // 85 // specs we can handle. 86 // 87 private Class[] availableSpecs = 88 { 89 // BEGIN android-removed 90 // RC2ParameterSpec.class, 91 // RC5ParameterSpec.class, 92 // END android-removed 93 IvParameterSpec.class, 94 PBEParameterSpec.class, 95 // BEGIN android-removed 96 // GOST28147ParameterSpec.class, 97 // END android-removed 98 gcmSpecClass 99 }; 100 101 private BlockCipher baseEngine; 102 private BlockCipherProvider engineProvider; 103 private GenericBlockCipher cipher; 104 private ParametersWithIV ivParam; 105 private AEADParameters aeadParams; 106 107 private int ivLength = 0; 108 109 private boolean padded; 110 111 private PBEParameterSpec pbeSpec = null; 112 private String pbeAlgorithm = null; 113 114 private String modeName = null; 115 lookup(String className)116 private static Class lookup(String className) 117 { 118 try 119 { 120 Class def = BaseBlockCipher.class.getClassLoader().loadClass(className); 121 122 return def; 123 } 124 catch (Exception e) 125 { 126 return null; 127 } 128 } 129 BaseBlockCipher( BlockCipher engine)130 protected BaseBlockCipher( 131 BlockCipher engine) 132 { 133 baseEngine = engine; 134 135 cipher = new BufferedGenericBlockCipher(engine); 136 } 137 BaseBlockCipher( BlockCipherProvider provider)138 protected BaseBlockCipher( 139 BlockCipherProvider provider) 140 { 141 baseEngine = provider.get(); 142 engineProvider = provider; 143 144 cipher = new BufferedGenericBlockCipher(provider.get()); 145 } 146 BaseBlockCipher( AEADBlockCipher engine)147 protected BaseBlockCipher( 148 AEADBlockCipher engine) 149 { 150 baseEngine = engine.getUnderlyingCipher(); 151 ivLength = baseEngine.getBlockSize(); 152 cipher = new AEADGenericBlockCipher(engine); 153 } 154 BaseBlockCipher( org.bouncycastle.crypto.BlockCipher engine, int ivLength)155 protected BaseBlockCipher( 156 org.bouncycastle.crypto.BlockCipher engine, 157 int ivLength) 158 { 159 baseEngine = engine; 160 161 this.cipher = new BufferedGenericBlockCipher(engine); 162 this.ivLength = ivLength / 8; 163 } 164 BaseBlockCipher( BufferedBlockCipher engine, int ivLength)165 protected BaseBlockCipher( 166 BufferedBlockCipher engine, 167 int ivLength) 168 { 169 baseEngine = engine.getUnderlyingCipher(); 170 171 this.cipher = new BufferedGenericBlockCipher(engine); 172 this.ivLength = ivLength / 8; 173 } 174 engineGetBlockSize()175 protected int engineGetBlockSize() 176 { 177 return baseEngine.getBlockSize(); 178 } 179 engineGetIV()180 protected byte[] engineGetIV() 181 { 182 if (aeadParams != null) 183 { 184 return aeadParams.getNonce(); 185 } 186 187 return (ivParam != null) ? ivParam.getIV() : null; 188 } 189 engineGetKeySize( Key key)190 protected int engineGetKeySize( 191 Key key) 192 { 193 return key.getEncoded().length * 8; 194 } 195 engineGetOutputSize( int inputLen)196 protected int engineGetOutputSize( 197 int inputLen) 198 { 199 return cipher.getOutputSize(inputLen); 200 } 201 engineGetParameters()202 protected AlgorithmParameters engineGetParameters() 203 { 204 if (engineParams == null) 205 { 206 if (pbeSpec != null) 207 { 208 try 209 { 210 engineParams = createParametersInstance(pbeAlgorithm); 211 engineParams.init(pbeSpec); 212 } 213 catch (Exception e) 214 { 215 return null; 216 } 217 } 218 else if (ivParam != null) 219 { 220 String name = cipher.getUnderlyingCipher().getAlgorithmName(); 221 222 if (name.indexOf('/') >= 0) 223 { 224 name = name.substring(0, name.indexOf('/')); 225 } 226 227 try 228 { 229 engineParams = createParametersInstance(name); 230 engineParams.init(ivParam.getIV()); 231 } 232 catch (Exception e) 233 { 234 throw new RuntimeException(e.toString()); 235 } 236 } 237 else if (aeadParams != null) 238 { 239 try 240 { 241 engineParams = createParametersInstance("GCM"); 242 engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize()).getEncoded()); 243 } 244 catch (Exception e) 245 { 246 throw new RuntimeException(e.toString()); 247 } 248 } 249 } 250 251 return engineParams; 252 } 253 engineSetMode( String mode)254 protected void engineSetMode( 255 String mode) 256 throws NoSuchAlgorithmException 257 { 258 modeName = Strings.toUpperCase(mode); 259 260 if (modeName.equals("ECB")) 261 { 262 ivLength = 0; 263 cipher = new BufferedGenericBlockCipher(baseEngine); 264 } 265 else if (modeName.equals("CBC")) 266 { 267 ivLength = baseEngine.getBlockSize(); 268 cipher = new BufferedGenericBlockCipher( 269 new CBCBlockCipher(baseEngine)); 270 } 271 else if (modeName.startsWith("OFB")) 272 { 273 ivLength = baseEngine.getBlockSize(); 274 if (modeName.length() != 3) 275 { 276 int wordSize = Integer.parseInt(modeName.substring(3)); 277 278 cipher = new BufferedGenericBlockCipher( 279 new OFBBlockCipher(baseEngine, wordSize)); 280 } 281 else 282 { 283 cipher = new BufferedGenericBlockCipher( 284 new OFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize())); 285 } 286 } 287 else if (modeName.startsWith("CFB")) 288 { 289 ivLength = baseEngine.getBlockSize(); 290 if (modeName.length() != 3) 291 { 292 int wordSize = Integer.parseInt(modeName.substring(3)); 293 294 cipher = new BufferedGenericBlockCipher( 295 new CFBBlockCipher(baseEngine, wordSize)); 296 } 297 else 298 { 299 cipher = new BufferedGenericBlockCipher( 300 new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize())); 301 } 302 } 303 // BEGIN android-removed 304 // else if (modeName.startsWith("PGP")) 305 // { 306 // boolean inlineIV = modeName.equalsIgnoreCase("PGPCFBwithIV"); 307 // 308 // ivLength = baseEngine.getBlockSize(); 309 // cipher = new BufferedGenericBlockCipher( 310 // new PGPCFBBlockCipher(baseEngine, inlineIV)); 311 // } 312 // else if (modeName.equalsIgnoreCase("OpenPGPCFB")) 313 // { 314 // ivLength = 0; 315 // cipher = new BufferedGenericBlockCipher( 316 // new OpenPGPCFBBlockCipher(baseEngine)); 317 // } 318 // else if (modeName.startsWith("SIC")) 319 // { 320 // ivLength = baseEngine.getBlockSize(); 321 // if (ivLength < 16) 322 // { 323 // throw new IllegalArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)"); 324 // } 325 // cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( 326 // new SICBlockCipher(baseEngine))); 327 // } 328 // END android-removed 329 else if (modeName.startsWith("CTR")) 330 { 331 ivLength = baseEngine.getBlockSize(); 332 cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( 333 new SICBlockCipher(baseEngine))); 334 } 335 // BEGIN android-removed 336 // else if (modeName.startsWith("GOFB")) 337 // { 338 // ivLength = baseEngine.getBlockSize(); 339 // cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( 340 // new GOFBBlockCipher(baseEngine))); 341 // } 342 // else if (modeName.startsWith("GCFB")) 343 // { 344 // ivLength = baseEngine.getBlockSize(); 345 // cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( 346 // new GCFBBlockCipher(baseEngine))); 347 // } 348 // END android-removed 349 else if (modeName.startsWith("CTS")) 350 { 351 ivLength = baseEngine.getBlockSize(); 352 cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(new CBCBlockCipher(baseEngine))); 353 } 354 else if (modeName.startsWith("CCM")) 355 { 356 ivLength = 13; // CCM nonce 7..13 bytes 357 cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine)); 358 } 359 // BEGIN android-removed 360 // else if (modeName.startsWith("OCB")) 361 // { 362 // if (engineProvider != null) 363 // { 364 // /* 365 // * RFC 7253 4.2. Nonce is a string of no more than 120 bits 366 // */ 367 // ivLength = 15; 368 // cipher = new AEADGenericBlockCipher(new OCBBlockCipher(baseEngine, engineProvider.get())); 369 // } 370 // else 371 // { 372 // throw new NoSuchAlgorithmException("can't support mode " + mode); 373 // } 374 // } 375 // else if (modeName.startsWith("EAX")) 376 // { 377 // ivLength = baseEngine.getBlockSize(); 378 // cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine)); 379 // } 380 // END android-removed 381 else if (modeName.startsWith("GCM")) 382 { 383 ivLength = baseEngine.getBlockSize(); 384 cipher = new AEADGenericBlockCipher(new GCMBlockCipher(baseEngine)); 385 } 386 else 387 { 388 throw new NoSuchAlgorithmException("can't support mode " + mode); 389 } 390 } 391 engineSetPadding( String padding)392 protected void engineSetPadding( 393 String padding) 394 throws NoSuchPaddingException 395 { 396 String paddingName = Strings.toUpperCase(padding); 397 398 if (paddingName.equals("NOPADDING")) 399 { 400 if (cipher.wrapOnNoPadding()) 401 { 402 cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(cipher.getUnderlyingCipher())); 403 } 404 } 405 else if (paddingName.equals("WITHCTS")) 406 { 407 cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(cipher.getUnderlyingCipher())); 408 } 409 else 410 { 411 padded = true; 412 413 if (isAEADModeName(modeName)) 414 { 415 throw new NoSuchPaddingException("Only NoPadding can be used with AEAD modes."); 416 } 417 else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING")) 418 { 419 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher()); 420 } 421 else if (paddingName.equals("ZEROBYTEPADDING")) 422 { 423 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ZeroBytePadding()); 424 } 425 else if (paddingName.equals("ISO10126PADDING") || paddingName.equals("ISO10126-2PADDING")) 426 { 427 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO10126d2Padding()); 428 } 429 else if (paddingName.equals("X9.23PADDING") || paddingName.equals("X923PADDING")) 430 { 431 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new X923Padding()); 432 } 433 else if (paddingName.equals("ISO7816-4PADDING") || paddingName.equals("ISO9797-1PADDING")) 434 { 435 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO7816d4Padding()); 436 } 437 else if (paddingName.equals("TBCPADDING")) 438 { 439 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new TBCPadding()); 440 } 441 else 442 { 443 throw new NoSuchPaddingException("Padding " + padding + " unknown."); 444 } 445 } 446 } 447 engineInit( int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)448 protected void engineInit( 449 int opmode, 450 Key key, 451 AlgorithmParameterSpec params, 452 SecureRandom random) 453 throws InvalidKeyException, InvalidAlgorithmParameterException 454 { 455 CipherParameters param; 456 457 this.pbeSpec = null; 458 this.pbeAlgorithm = null; 459 this.engineParams = null; 460 this.aeadParams = null; 461 462 // 463 // basic key check 464 // 465 if (!(key instanceof SecretKey)) 466 { 467 throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption."); 468 } 469 470 // 471 // for RC5-64 we must have some default parameters 472 // 473 if (params == null && baseEngine.getAlgorithmName().startsWith("RC5-64")) 474 { 475 throw new InvalidAlgorithmParameterException("RC5 requires an RC5ParametersSpec to be passed in."); 476 } 477 478 // 479 // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it). 480 // 481 if (key instanceof BCPBEKey) 482 { 483 BCPBEKey k = (BCPBEKey)key; 484 485 if (k.getOID() != null) 486 { 487 pbeAlgorithm = k.getOID().getId(); 488 } 489 else 490 { 491 pbeAlgorithm = k.getAlgorithm(); 492 } 493 494 if (k.getParam() != null) 495 { 496 param = k.getParam(); 497 if (params instanceof IvParameterSpec) 498 { 499 IvParameterSpec iv = (IvParameterSpec)params; 500 501 param = new ParametersWithIV(param, iv.getIV()); 502 } 503 // BEGIN android-removed 504 // else if (params instanceof GOST28147ParameterSpec) 505 // { 506 // // need to pick up IV and SBox. 507 // GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params; 508 // 509 // param = new ParametersWithSBox(param, gost28147Param.getSbox()); 510 // 511 // if (gost28147Param.getIV() != null && ivLength != 0) 512 // { 513 // param = new ParametersWithIV(param, gost28147Param.getIV()); 514 // } 515 // } 516 // END android-removed 517 } 518 else if (params instanceof PBEParameterSpec) 519 { 520 pbeSpec = (PBEParameterSpec)params; 521 param = PBE.Util.makePBEParameters(k, params, cipher.getUnderlyingCipher().getAlgorithmName()); 522 } 523 else 524 { 525 throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set."); 526 } 527 528 if (param instanceof ParametersWithIV) 529 { 530 ivParam = (ParametersWithIV)param; 531 } 532 } 533 else if (params == null) 534 { 535 param = new KeyParameter(key.getEncoded()); 536 } 537 else if (params instanceof IvParameterSpec) 538 { 539 if (ivLength != 0) 540 { 541 IvParameterSpec p = (IvParameterSpec)params; 542 543 if (p.getIV().length != ivLength && !isAEADModeName(modeName)) 544 { 545 throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long."); 546 } 547 548 // BEGIN android-removed 549 // if (key instanceof RepeatedSecretKeySpec) 550 // { 551 // param = new ParametersWithIV(null, p.getIV()); 552 // ivParam = (ParametersWithIV)param; 553 // } 554 // else 555 // END android-removed 556 { 557 param = new ParametersWithIV(new KeyParameter(key.getEncoded()), p.getIV()); 558 ivParam = (ParametersWithIV)param; 559 } 560 } 561 else 562 { 563 if (modeName != null && modeName.equals("ECB")) 564 { 565 throw new InvalidAlgorithmParameterException("ECB mode does not use an IV"); 566 } 567 568 param = new KeyParameter(key.getEncoded()); 569 } 570 } 571 // BEGIN android-removed 572 // else if (params instanceof GOST28147ParameterSpec) 573 // { 574 // GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params; 575 // 576 // param = new ParametersWithSBox( 577 // new KeyParameter(key.getEncoded()), ((GOST28147ParameterSpec)params).getSbox()); 578 // 579 // if (gost28147Param.getIV() != null && ivLength != 0) 580 // { 581 // param = new ParametersWithIV(param, gost28147Param.getIV()); 582 // ivParam = (ParametersWithIV)param; 583 // } 584 // } 585 // else if (params instanceof RC2ParameterSpec) 586 // { 587 // RC2ParameterSpec rc2Param = (RC2ParameterSpec)params; 588 // 589 // param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits()); 590 // 591 // if (rc2Param.getIV() != null && ivLength != 0) 592 // { 593 // param = new ParametersWithIV(param, rc2Param.getIV()); 594 // ivParam = (ParametersWithIV)param; 595 // } 596 // } 597 // else if (params instanceof RC5ParameterSpec) 598 // { 599 // RC5ParameterSpec rc5Param = (RC5ParameterSpec)params; 600 // 601 // param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds()); 602 // if (baseEngine.getAlgorithmName().startsWith("RC5")) 603 // { 604 // if (baseEngine.getAlgorithmName().equals("RC5-32")) 605 // { 606 // if (rc5Param.getWordSize() != 32) 607 // { 608 // throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 32 not " + rc5Param.getWordSize() + "."); 609 // } 610 // } 611 // else if (baseEngine.getAlgorithmName().equals("RC5-64")) 612 // { 613 // if (rc5Param.getWordSize() != 64) 614 // { 615 // throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 64 not " + rc5Param.getWordSize() + "."); 616 // } 617 // } 618 // } 619 // else 620 // { 621 // throw new InvalidAlgorithmParameterException("RC5 parameters passed to a cipher that is not RC5."); 622 // } 623 // if ((rc5Param.getIV() != null) && (ivLength != 0)) 624 // { 625 // param = new ParametersWithIV(param, rc5Param.getIV()); 626 // ivParam = (ParametersWithIV)param; 627 // } 628 // } 629 // END android-removed 630 else if (gcmSpecClass != null && gcmSpecClass.isInstance(params)) 631 { 632 if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher)) 633 { 634 throw new InvalidAlgorithmParameterException("GCMParameterSpec can only be used with AEAD modes."); 635 } 636 637 try 638 { 639 Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]); 640 Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]); 641 642 // BEGIN android-removed 643 // if (key instanceof RepeatedSecretKeySpec) 644 // { 645 // param = aeadParams = new AEADParameters(null, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0])); 646 // } 647 // else 648 // END android-removed 649 { 650 param = aeadParams = new AEADParameters(new KeyParameter(key.getEncoded()), ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0])); 651 } 652 } 653 catch (Exception e) 654 { 655 throw new InvalidAlgorithmParameterException("Cannot process GCMParameterSpec."); 656 } 657 } 658 else 659 { 660 throw new InvalidAlgorithmParameterException("unknown parameter type."); 661 } 662 663 if ((ivLength != 0) && !(param instanceof ParametersWithIV) && !(param instanceof AEADParameters)) 664 { 665 SecureRandom ivRandom = random; 666 667 if (ivRandom == null) 668 { 669 ivRandom = new SecureRandom(); 670 } 671 672 if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE)) 673 { 674 byte[] iv = new byte[ivLength]; 675 676 ivRandom.nextBytes(iv); 677 param = new ParametersWithIV(param, iv); 678 ivParam = (ParametersWithIV)param; 679 } 680 else if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0) 681 { 682 throw new InvalidAlgorithmParameterException("no IV set when one expected"); 683 } 684 } 685 686 if (random != null && padded) 687 { 688 param = new ParametersWithRandom(param, random); 689 } 690 691 try 692 { 693 switch (opmode) 694 { 695 case Cipher.ENCRYPT_MODE: 696 case Cipher.WRAP_MODE: 697 cipher.init(true, param); 698 break; 699 case Cipher.DECRYPT_MODE: 700 case Cipher.UNWRAP_MODE: 701 cipher.init(false, param); 702 break; 703 default: 704 throw new InvalidParameterException("unknown opmode " + opmode + " passed"); 705 } 706 } 707 catch (Exception e) 708 { 709 throw new InvalidKeyException(e.getMessage()); 710 } 711 } 712 engineInit( int opmode, Key key, AlgorithmParameters params, SecureRandom random)713 protected void engineInit( 714 int opmode, 715 Key key, 716 AlgorithmParameters params, 717 SecureRandom random) 718 throws InvalidKeyException, InvalidAlgorithmParameterException 719 { 720 AlgorithmParameterSpec paramSpec = null; 721 722 if (params != null) 723 { 724 for (int i = 0; i != availableSpecs.length; i++) 725 { 726 if (availableSpecs[i] == null) 727 { 728 continue; 729 } 730 731 try 732 { 733 paramSpec = params.getParameterSpec(availableSpecs[i]); 734 break; 735 } 736 catch (Exception e) 737 { 738 // try again if possible 739 } 740 } 741 742 if (paramSpec == null) 743 { 744 throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString()); 745 } 746 } 747 748 engineInit(opmode, key, paramSpec, random); 749 750 engineParams = params; 751 } 752 engineInit( int opmode, Key key, SecureRandom random)753 protected void engineInit( 754 int opmode, 755 Key key, 756 SecureRandom random) 757 throws InvalidKeyException 758 { 759 try 760 { 761 engineInit(opmode, key, (AlgorithmParameterSpec)null, random); 762 } 763 catch (InvalidAlgorithmParameterException e) 764 { 765 throw new InvalidKeyException(e.getMessage()); 766 } 767 } 768 engineUpdateAAD(byte[] input, int offset, int length)769 protected void engineUpdateAAD(byte[] input, int offset, int length) 770 { 771 cipher.updateAAD(input, offset, length); 772 } 773 engineUpdateAAD(ByteBuffer bytebuffer)774 protected void engineUpdateAAD(ByteBuffer bytebuffer) 775 { 776 int offset = bytebuffer.arrayOffset() + bytebuffer.position(); 777 int length = bytebuffer.limit() - bytebuffer.position(); 778 engineUpdateAAD(bytebuffer.array(), offset, length); 779 } 780 engineUpdate( byte[] input, int inputOffset, int inputLen)781 protected byte[] engineUpdate( 782 byte[] input, 783 int inputOffset, 784 int inputLen) 785 { 786 int length = cipher.getUpdateOutputSize(inputLen); 787 788 if (length > 0) 789 { 790 byte[] out = new byte[length]; 791 792 int len = cipher.processBytes(input, inputOffset, inputLen, out, 0); 793 794 if (len == 0) 795 { 796 return null; 797 } 798 else if (len != out.length) 799 { 800 byte[] tmp = new byte[len]; 801 802 System.arraycopy(out, 0, tmp, 0, len); 803 804 return tmp; 805 } 806 807 return out; 808 } 809 810 cipher.processBytes(input, inputOffset, inputLen, null, 0); 811 812 return null; 813 } 814 engineUpdate( byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)815 protected int engineUpdate( 816 byte[] input, 817 int inputOffset, 818 int inputLen, 819 byte[] output, 820 int outputOffset) 821 throws ShortBufferException 822 { 823 try 824 { 825 return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset); 826 } 827 catch (DataLengthException e) 828 { 829 throw new ShortBufferException(e.getMessage()); 830 } 831 } 832 engineDoFinal( byte[] input, int inputOffset, int inputLen)833 protected byte[] engineDoFinal( 834 byte[] input, 835 int inputOffset, 836 int inputLen) 837 throws IllegalBlockSizeException, BadPaddingException 838 { 839 int len = 0; 840 byte[] tmp = new byte[engineGetOutputSize(inputLen)]; 841 842 if (inputLen != 0) 843 { 844 len = cipher.processBytes(input, inputOffset, inputLen, tmp, 0); 845 } 846 847 try 848 { 849 len += cipher.doFinal(tmp, len); 850 } 851 catch (DataLengthException e) 852 { 853 throw new IllegalBlockSizeException(e.getMessage()); 854 } 855 856 if (len == tmp.length) 857 { 858 return tmp; 859 } 860 861 byte[] out = new byte[len]; 862 863 System.arraycopy(tmp, 0, out, 0, len); 864 865 return out; 866 } 867 engineDoFinal( byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)868 protected int engineDoFinal( 869 byte[] input, 870 int inputOffset, 871 int inputLen, 872 byte[] output, 873 int outputOffset) 874 throws IllegalBlockSizeException, BadPaddingException, ShortBufferException 875 { 876 try 877 { 878 int len = 0; 879 880 if (inputLen != 0) 881 { 882 len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset); 883 } 884 885 return (len + cipher.doFinal(output, outputOffset + len)); 886 } 887 catch (OutputLengthException e) 888 { 889 throw new ShortBufferException(e.getMessage()); 890 } 891 catch (DataLengthException e) 892 { 893 throw new IllegalBlockSizeException(e.getMessage()); 894 } 895 } 896 isAEADModeName( String modeName)897 private boolean isAEADModeName( 898 String modeName) 899 { 900 // BEGIN android-changed 901 return "CCM".equals(modeName) || "GCM".equals(modeName); 902 // END android-changed 903 } 904 905 /* 906 * The ciphers that inherit from us. 907 */ 908 909 static private interface GenericBlockCipher 910 { init(boolean forEncryption, CipherParameters params)911 public void init(boolean forEncryption, CipherParameters params) 912 throws IllegalArgumentException; 913 wrapOnNoPadding()914 public boolean wrapOnNoPadding(); 915 getAlgorithmName()916 public String getAlgorithmName(); 917 getUnderlyingCipher()918 public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher(); 919 getOutputSize(int len)920 public int getOutputSize(int len); 921 getUpdateOutputSize(int len)922 public int getUpdateOutputSize(int len); 923 updateAAD(byte[] input, int offset, int length)924 public void updateAAD(byte[] input, int offset, int length); 925 processByte(byte in, byte[] out, int outOff)926 public int processByte(byte in, byte[] out, int outOff) 927 throws DataLengthException; 928 processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)929 public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) 930 throws DataLengthException; 931 doFinal(byte[] out, int outOff)932 public int doFinal(byte[] out, int outOff) 933 throws IllegalStateException, 934 BadPaddingException; 935 } 936 937 private static class BufferedGenericBlockCipher 938 implements GenericBlockCipher 939 { 940 private BufferedBlockCipher cipher; 941 BufferedGenericBlockCipher(BufferedBlockCipher cipher)942 BufferedGenericBlockCipher(BufferedBlockCipher cipher) 943 { 944 this.cipher = cipher; 945 } 946 BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher)947 BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher) 948 { 949 this.cipher = new PaddedBufferedBlockCipher(cipher); 950 } 951 BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher, BlockCipherPadding padding)952 BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher, BlockCipherPadding padding) 953 { 954 this.cipher = new PaddedBufferedBlockCipher(cipher, padding); 955 } 956 init(boolean forEncryption, CipherParameters params)957 public void init(boolean forEncryption, CipherParameters params) 958 throws IllegalArgumentException 959 { 960 cipher.init(forEncryption, params); 961 } 962 wrapOnNoPadding()963 public boolean wrapOnNoPadding() 964 { 965 return !(cipher instanceof CTSBlockCipher); 966 } 967 getAlgorithmName()968 public String getAlgorithmName() 969 { 970 return cipher.getUnderlyingCipher().getAlgorithmName(); 971 } 972 getUnderlyingCipher()973 public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher() 974 { 975 return cipher.getUnderlyingCipher(); 976 } 977 getOutputSize(int len)978 public int getOutputSize(int len) 979 { 980 return cipher.getOutputSize(len); 981 } 982 getUpdateOutputSize(int len)983 public int getUpdateOutputSize(int len) 984 { 985 return cipher.getUpdateOutputSize(len); 986 } 987 updateAAD(byte[] input, int offset, int length)988 public void updateAAD(byte[] input, int offset, int length) 989 { 990 throw new UnsupportedOperationException("AAD is not supported in the current mode."); 991 } 992 processByte(byte in, byte[] out, int outOff)993 public int processByte(byte in, byte[] out, int outOff) throws DataLengthException 994 { 995 return cipher.processByte(in, out, outOff); 996 } 997 processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)998 public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException 999 { 1000 return cipher.processBytes(in, inOff, len, out, outOff); 1001 } 1002 doFinal(byte[] out, int outOff)1003 public int doFinal(byte[] out, int outOff) throws IllegalStateException, BadPaddingException 1004 { 1005 try 1006 { 1007 return cipher.doFinal(out, outOff); 1008 } 1009 catch (InvalidCipherTextException e) 1010 { 1011 throw new BadPaddingException(e.getMessage()); 1012 } 1013 } 1014 } 1015 1016 private static class AEADGenericBlockCipher 1017 implements GenericBlockCipher 1018 { 1019 private static final Constructor aeadBadTagConstructor; 1020 1021 static { 1022 Class aeadBadTagClass = lookup("javax.crypto.AEADBadTagException"); 1023 if (aeadBadTagClass != null) 1024 { 1025 aeadBadTagConstructor = findExceptionConstructor(aeadBadTagClass); 1026 } 1027 else 1028 { 1029 aeadBadTagConstructor = null; 1030 } 1031 } 1032 findExceptionConstructor(Class clazz)1033 private static Constructor findExceptionConstructor(Class clazz) 1034 { 1035 try 1036 { 1037 return clazz.getConstructor(new Class[]{String.class}); 1038 } 1039 catch (Exception e) 1040 { 1041 return null; 1042 } 1043 } 1044 1045 private AEADBlockCipher cipher; 1046 AEADGenericBlockCipher(AEADBlockCipher cipher)1047 AEADGenericBlockCipher(AEADBlockCipher cipher) 1048 { 1049 this.cipher = cipher; 1050 } 1051 init(boolean forEncryption, CipherParameters params)1052 public void init(boolean forEncryption, CipherParameters params) 1053 throws IllegalArgumentException 1054 { 1055 cipher.init(forEncryption, params); 1056 } 1057 getAlgorithmName()1058 public String getAlgorithmName() 1059 { 1060 return cipher.getUnderlyingCipher().getAlgorithmName(); 1061 } 1062 wrapOnNoPadding()1063 public boolean wrapOnNoPadding() 1064 { 1065 return false; 1066 } 1067 getUnderlyingCipher()1068 public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher() 1069 { 1070 return cipher.getUnderlyingCipher(); 1071 } 1072 getOutputSize(int len)1073 public int getOutputSize(int len) 1074 { 1075 return cipher.getOutputSize(len); 1076 } 1077 getUpdateOutputSize(int len)1078 public int getUpdateOutputSize(int len) 1079 { 1080 return cipher.getUpdateOutputSize(len); 1081 } 1082 updateAAD(byte[] input, int offset, int length)1083 public void updateAAD(byte[] input, int offset, int length) 1084 { 1085 cipher.processAADBytes(input, offset, length); 1086 } 1087 processByte(byte in, byte[] out, int outOff)1088 public int processByte(byte in, byte[] out, int outOff) throws DataLengthException 1089 { 1090 return cipher.processByte(in, out, outOff); 1091 } 1092 processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)1093 public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException 1094 { 1095 return cipher.processBytes(in, inOff, len, out, outOff); 1096 } 1097 doFinal(byte[] out, int outOff)1098 public int doFinal(byte[] out, int outOff) throws IllegalStateException, BadPaddingException 1099 { 1100 try 1101 { 1102 return cipher.doFinal(out, outOff); 1103 } 1104 catch (InvalidCipherTextException e) 1105 { 1106 if (aeadBadTagConstructor != null) 1107 { 1108 BadPaddingException aeadBadTag = null; 1109 try 1110 { 1111 aeadBadTag = (BadPaddingException)aeadBadTagConstructor 1112 .newInstance(new Object[]{e.getMessage()}); 1113 } 1114 catch (Exception i) 1115 { 1116 // Shouldn't happen, but fall through to BadPaddingException 1117 } 1118 if (aeadBadTag != null) 1119 { 1120 throw aeadBadTag; 1121 } 1122 } 1123 throw new BadPaddingException(e.getMessage()); 1124 } 1125 } 1126 } 1127 } 1128