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