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