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