1 package org.bouncycastle.jcajce.provider.symmetric.util; 2 3 import java.io.ByteArrayOutputStream; 4 import java.lang.reflect.Constructor; 5 import java.security.AlgorithmParameters; 6 import java.security.InvalidAlgorithmParameterException; 7 import java.security.InvalidKeyException; 8 import java.security.InvalidParameterException; 9 import java.security.Key; 10 import java.security.NoSuchAlgorithmException; 11 import java.security.SecureRandom; 12 import java.security.spec.AlgorithmParameterSpec; 13 14 import javax.crypto.BadPaddingException; 15 import javax.crypto.Cipher; 16 import javax.crypto.IllegalBlockSizeException; 17 import javax.crypto.NoSuchPaddingException; 18 import javax.crypto.SecretKey; 19 import javax.crypto.ShortBufferException; 20 import javax.crypto.interfaces.PBEKey; 21 import javax.crypto.spec.IvParameterSpec; 22 import javax.crypto.spec.PBEParameterSpec; 23 import javax.crypto.spec.RC2ParameterSpec; 24 import javax.crypto.spec.RC5ParameterSpec; 25 26 import org.bouncycastle.asn1.DEROctetString; 27 import org.bouncycastle.crypto.fpe.FPEEngine; 28 import org.bouncycastle.crypto.fpe.FPEFF1Engine; 29 import org.bouncycastle.crypto.fpe.FPEFF3_1Engine; 30 import org.bouncycastle.crypto.params.FPEParameters; 31 import org.bouncycastle.internal.asn1.cms.GCMParameters; 32 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 33 import org.bouncycastle.crypto.BlockCipher; 34 import org.bouncycastle.crypto.BufferedBlockCipher; 35 import org.bouncycastle.crypto.CipherParameters; 36 import org.bouncycastle.crypto.CryptoServicesRegistrar; 37 import org.bouncycastle.crypto.DataLengthException; 38 import org.bouncycastle.crypto.InvalidCipherTextException; 39 import org.bouncycastle.crypto.OutputLengthException; 40 import org.bouncycastle.crypto.engines.DSTU7624Engine; 41 import org.bouncycastle.crypto.modes.AEADBlockCipher; 42 import org.bouncycastle.crypto.modes.AEADCipher; 43 import org.bouncycastle.crypto.modes.CBCBlockCipher; 44 import org.bouncycastle.crypto.modes.CCMBlockCipher; 45 import org.bouncycastle.crypto.modes.CFBBlockCipher; 46 import org.bouncycastle.crypto.modes.CTSBlockCipher; 47 import org.bouncycastle.crypto.modes.EAXBlockCipher; 48 import org.bouncycastle.crypto.modes.GCFBBlockCipher; 49 import org.bouncycastle.crypto.modes.GCMBlockCipher; 50 import org.bouncycastle.crypto.modes.GCMSIVBlockCipher; 51 import org.bouncycastle.crypto.modes.GOFBBlockCipher; 52 import org.bouncycastle.crypto.modes.KCCMBlockCipher; 53 import org.bouncycastle.crypto.modes.KCTRBlockCipher; 54 import org.bouncycastle.crypto.modes.KGCMBlockCipher; 55 import org.bouncycastle.crypto.modes.OCBBlockCipher; 56 import org.bouncycastle.crypto.modes.OFBBlockCipher; 57 import org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher; 58 import org.bouncycastle.crypto.modes.PGPCFBBlockCipher; 59 import org.bouncycastle.crypto.modes.SICBlockCipher; 60 import org.bouncycastle.crypto.paddings.BlockCipherPadding; 61 import org.bouncycastle.crypto.paddings.ISO10126d2Padding; 62 import org.bouncycastle.crypto.paddings.ISO7816d4Padding; 63 import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; 64 import org.bouncycastle.crypto.paddings.TBCPadding; 65 import org.bouncycastle.crypto.paddings.X923Padding; 66 import org.bouncycastle.crypto.paddings.ZeroBytePadding; 67 import org.bouncycastle.crypto.params.AEADParameters; 68 import org.bouncycastle.crypto.params.KeyParameter; 69 import org.bouncycastle.crypto.params.ParametersWithIV; 70 import org.bouncycastle.crypto.params.ParametersWithRandom; 71 import org.bouncycastle.crypto.params.ParametersWithSBox; 72 import org.bouncycastle.crypto.params.RC2Parameters; 73 import org.bouncycastle.crypto.params.RC5Parameters; 74 import org.bouncycastle.jcajce.PBKDF1Key; 75 import org.bouncycastle.jcajce.PBKDF1KeyWithParameters; 76 import org.bouncycastle.jcajce.PKCS12Key; 77 import org.bouncycastle.jcajce.PKCS12KeyWithParameters; 78 import org.bouncycastle.jcajce.spec.AEADParameterSpec; 79 import org.bouncycastle.jcajce.spec.FPEParameterSpec; 80 import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec; 81 import org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec; 82 import org.bouncycastle.util.Arrays; 83 import org.bouncycastle.util.Strings; 84 85 public class BaseBlockCipher 86 extends BaseWrapCipher 87 implements PBE 88 { 89 private static final int BUF_SIZE = 512; 90 private static final Class gcmSpecClass = ClassUtil.loadClass(BaseBlockCipher.class, "javax.crypto.spec.GCMParameterSpec"); 91 92 // 93 // specs we can handle. 94 // 95 private Class[] availableSpecs = 96 { 97 RC2ParameterSpec.class, 98 RC5ParameterSpec.class, 99 gcmSpecClass, 100 GOST28147ParameterSpec.class, 101 IvParameterSpec.class, 102 PBEParameterSpec.class 103 }; 104 105 private BlockCipher baseEngine; 106 private BlockCipherProvider engineProvider; 107 private GenericBlockCipher cipher; 108 private ParametersWithIV ivParam; 109 private AEADParameters aeadParams; 110 111 private int keySizeInBits; 112 private int scheme = -1; 113 private int digest; 114 115 private int ivLength = 0; 116 117 private boolean padded; 118 private boolean fixedIv = true; 119 private PBEParameterSpec pbeSpec = null; 120 private String pbeAlgorithm = null; 121 122 private String modeName = null; 123 BaseBlockCipher( BlockCipher engine)124 protected BaseBlockCipher( 125 BlockCipher engine) 126 { 127 baseEngine = engine; 128 129 cipher = new BufferedGenericBlockCipher(engine); 130 } 131 BaseBlockCipher( BlockCipher engine, int scheme, int digest, int keySizeInBits, int ivLength)132 protected BaseBlockCipher( 133 BlockCipher engine, 134 int scheme, 135 int digest, 136 int keySizeInBits, 137 int ivLength) 138 { 139 baseEngine = engine; 140 141 this.scheme = scheme; 142 this.digest = digest; 143 this.keySizeInBits = keySizeInBits; 144 this.ivLength = ivLength; 145 146 cipher = new BufferedGenericBlockCipher(engine); 147 } 148 BaseBlockCipher( BlockCipherProvider provider)149 protected BaseBlockCipher( 150 BlockCipherProvider provider) 151 { 152 baseEngine = provider.get(); 153 engineProvider = provider; 154 155 cipher = new BufferedGenericBlockCipher(provider.get()); 156 } 157 BaseBlockCipher( AEADBlockCipher engine)158 protected BaseBlockCipher( 159 AEADBlockCipher engine) 160 { 161 this.baseEngine = engine.getUnderlyingCipher(); 162 if (engine.getAlgorithmName().indexOf("GCM") >= 0) 163 { 164 this.ivLength = 12; 165 } 166 else 167 { 168 this.ivLength = baseEngine.getBlockSize(); 169 } 170 this.cipher = new AEADGenericBlockCipher(engine); 171 } 172 BaseBlockCipher( AEADCipher engine, boolean fixedIv, int ivLength)173 protected BaseBlockCipher( 174 AEADCipher engine, 175 boolean fixedIv, 176 int ivLength) 177 { 178 this.baseEngine = null; 179 this.fixedIv = fixedIv; 180 this.ivLength = ivLength; 181 this.cipher = new AEADGenericBlockCipher(engine); 182 } 183 BaseBlockCipher( AEADBlockCipher engine, boolean fixedIv, int ivLength)184 protected BaseBlockCipher( 185 AEADBlockCipher engine, 186 boolean fixedIv, 187 int ivLength) 188 { 189 this.baseEngine = engine.getUnderlyingCipher(); 190 this.fixedIv = fixedIv; 191 this.ivLength = ivLength; 192 this.cipher = new AEADGenericBlockCipher(engine); 193 } 194 BaseBlockCipher( org.bouncycastle.crypto.BlockCipher engine, int ivLength)195 protected BaseBlockCipher( 196 org.bouncycastle.crypto.BlockCipher engine, 197 int ivLength) 198 { 199 this(engine, true, ivLength); 200 } 201 BaseBlockCipher( org.bouncycastle.crypto.BlockCipher engine, boolean fixedIv, int ivLength)202 protected BaseBlockCipher( 203 org.bouncycastle.crypto.BlockCipher engine, 204 boolean fixedIv, 205 int ivLength) 206 { 207 baseEngine = engine; 208 209 this.fixedIv = fixedIv; 210 this.cipher = new BufferedGenericBlockCipher(engine); 211 this.ivLength = ivLength / 8; 212 } 213 BaseBlockCipher( BufferedBlockCipher engine, int ivLength)214 protected BaseBlockCipher( 215 BufferedBlockCipher engine, 216 int ivLength) 217 { 218 this(engine, true, ivLength); 219 } 220 BaseBlockCipher( BufferedBlockCipher engine, boolean fixedIv, int ivLength)221 protected BaseBlockCipher( 222 BufferedBlockCipher engine, 223 boolean fixedIv, 224 int ivLength) 225 { 226 baseEngine = engine.getUnderlyingCipher(); 227 228 this.cipher = new BufferedGenericBlockCipher(engine); 229 this.fixedIv = fixedIv; 230 this.ivLength = ivLength / 8; 231 } 232 engineGetBlockSize()233 protected int engineGetBlockSize() 234 { 235 if (baseEngine == null) 236 { 237 return -1; 238 } 239 return baseEngine.getBlockSize(); 240 } 241 engineGetIV()242 protected byte[] engineGetIV() 243 { 244 if (aeadParams != null) 245 { 246 return aeadParams.getNonce(); 247 } 248 249 return (ivParam != null) ? ivParam.getIV() : null; 250 } 251 engineGetKeySize( Key key)252 protected int engineGetKeySize( 253 Key key) 254 { 255 return key.getEncoded().length * 8; 256 } 257 engineGetOutputSize( int inputLen)258 protected int engineGetOutputSize( 259 int inputLen) 260 { 261 return cipher.getOutputSize(inputLen); 262 } 263 engineGetParameters()264 protected AlgorithmParameters engineGetParameters() 265 { 266 if (engineParams == null) 267 { 268 if (pbeSpec != null) 269 { 270 try 271 { 272 engineParams = createParametersInstance(pbeAlgorithm); 273 engineParams.init(pbeSpec); 274 } 275 catch (Exception e) 276 { 277 return null; 278 } 279 } 280 else if (aeadParams != null) 281 { 282 // CHACHA20-Poly1305 283 if (baseEngine == null) 284 { 285 try 286 { 287 engineParams = createParametersInstance(PKCSObjectIdentifiers.id_alg_AEADChaCha20Poly1305.getId()); 288 engineParams.init(new DEROctetString(aeadParams.getNonce()).getEncoded()); 289 } 290 catch (Exception e) 291 { 292 throw new RuntimeException(e.toString()); 293 } 294 } 295 else 296 { 297 try 298 { 299 engineParams = createParametersInstance("GCM"); 300 engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize() / 8).getEncoded()); 301 } 302 catch (Exception e) 303 { 304 throw new RuntimeException(e.toString()); 305 } 306 } 307 } 308 else if (ivParam != null) 309 { 310 String name = cipher.getUnderlyingCipher().getAlgorithmName(); 311 312 if (name.indexOf('/') >= 0) 313 { 314 name = name.substring(0, name.indexOf('/')); 315 } 316 317 try 318 { 319 engineParams = createParametersInstance(name); 320 engineParams.init(new IvParameterSpec(ivParam.getIV())); 321 } 322 catch (Exception e) 323 { 324 throw new RuntimeException(e.toString()); 325 } 326 } 327 } 328 329 return engineParams; 330 } 331 engineSetMode( String mode)332 protected void engineSetMode( 333 String mode) 334 throws NoSuchAlgorithmException 335 { 336 if (baseEngine == null) 337 { 338 throw new NoSuchAlgorithmException("no mode supported for this algorithm"); 339 } 340 modeName = Strings.toUpperCase(mode); 341 342 try 343 { 344 if (modeName.equals("ECB")) 345 { 346 ivLength = 0; 347 cipher = new BufferedGenericBlockCipher(baseEngine); 348 } 349 else if (modeName.equals("CBC")) 350 { 351 ivLength = baseEngine.getBlockSize(); 352 cipher = new BufferedGenericBlockCipher( 353 new CBCBlockCipher(baseEngine)); 354 } 355 else if (modeName.startsWith("OFB")) 356 { 357 ivLength = baseEngine.getBlockSize(); 358 if (modeName.length() != 3) 359 { 360 int wordSize = Integer.parseInt(modeName.substring(3)); 361 362 cipher = new BufferedGenericBlockCipher( 363 new OFBBlockCipher(baseEngine, wordSize)); 364 } 365 else 366 { 367 cipher = new BufferedGenericBlockCipher( 368 new OFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize())); 369 } 370 } 371 else if (modeName.startsWith("CFB")) 372 { 373 ivLength = baseEngine.getBlockSize(); 374 if (modeName.length() != 3) 375 { 376 int wordSize = Integer.parseInt(modeName.substring(3)); 377 378 cipher = new BufferedGenericBlockCipher( 379 new CFBBlockCipher(baseEngine, wordSize)); 380 } 381 else 382 { 383 cipher = new BufferedGenericBlockCipher( 384 new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize())); 385 } 386 } 387 else if (modeName.startsWith("PGPCFB")) 388 { 389 boolean inlineIV = modeName.equals("PGPCFBWITHIV"); 390 391 if (!inlineIV && modeName.length() != 6) 392 { 393 throw new NoSuchAlgorithmException("no mode support for " + modeName); 394 } 395 396 ivLength = baseEngine.getBlockSize(); 397 cipher = new BufferedGenericBlockCipher( 398 new PGPCFBBlockCipher(baseEngine, inlineIV)); 399 } 400 else if (modeName.equals("OPENPGPCFB")) 401 { 402 ivLength = 0; 403 cipher = new BufferedGenericBlockCipher( 404 new OpenPGPCFBBlockCipher(baseEngine)); 405 } 406 else if (modeName.equals("FF1")) 407 { 408 ivLength = 0; 409 cipher = new BufferedFPEBlockCipher( 410 new FPEFF1Engine(baseEngine)); 411 } 412 else if (modeName.equals("FF3-1")) 413 { 414 ivLength = 0; 415 cipher = new BufferedFPEBlockCipher( 416 new FPEFF3_1Engine(baseEngine)); 417 } 418 else if (modeName.equals("SIC")) 419 { 420 ivLength = baseEngine.getBlockSize(); 421 if (ivLength < 16) 422 { 423 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)"); 424 } 425 fixedIv = false; 426 cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( 427 new SICBlockCipher(baseEngine))); 428 } 429 else if (modeName.equals("CTR")) 430 { 431 ivLength = baseEngine.getBlockSize(); 432 fixedIv = false; 433 if (baseEngine instanceof DSTU7624Engine) 434 { 435 cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( 436 new KCTRBlockCipher(baseEngine))); 437 } 438 else 439 { 440 cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( 441 new SICBlockCipher(baseEngine))); 442 } 443 } 444 else if (modeName.equals("GOFB")) 445 { 446 ivLength = baseEngine.getBlockSize(); 447 cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( 448 new GOFBBlockCipher(baseEngine))); 449 } 450 else if (modeName.equals("GCFB")) 451 { 452 ivLength = baseEngine.getBlockSize(); 453 cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( 454 new GCFBBlockCipher(baseEngine))); 455 } 456 else if (modeName.equals("CTS")) 457 { 458 ivLength = baseEngine.getBlockSize(); 459 cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(new CBCBlockCipher(baseEngine))); 460 } 461 else if (modeName.equals("CCM")) 462 { 463 ivLength = 12; // CCM nonce 7..13 bytes 464 if (baseEngine instanceof DSTU7624Engine) 465 { 466 cipher = new AEADGenericBlockCipher(new KCCMBlockCipher(baseEngine)); 467 } 468 else 469 { 470 cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine)); 471 } 472 } 473 else if (modeName.equals("OCB")) 474 { 475 if (engineProvider != null) 476 { 477 /* 478 * RFC 7253 4.2. Nonce is a string of no more than 120 bits 479 */ 480 ivLength = 15; 481 cipher = new AEADGenericBlockCipher(new OCBBlockCipher(baseEngine, engineProvider.get())); 482 } 483 else 484 { 485 throw new NoSuchAlgorithmException("can't support mode " + mode); 486 } 487 } 488 else if (modeName.equals("EAX")) 489 { 490 ivLength = baseEngine.getBlockSize(); 491 cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine)); 492 } 493 else if (modeName.equals("GCM-SIV")) 494 { 495 ivLength = 12; 496 cipher = new AEADGenericBlockCipher(new GCMSIVBlockCipher(baseEngine)); 497 } 498 else if (modeName.equals("GCM")) 499 { 500 if (baseEngine instanceof DSTU7624Engine) 501 { 502 ivLength = baseEngine.getBlockSize(); 503 cipher = new AEADGenericBlockCipher(new KGCMBlockCipher(baseEngine)); 504 } 505 else 506 { 507 ivLength = 12; 508 cipher = new AEADGenericBlockCipher(new GCMBlockCipher(baseEngine)); 509 } 510 } 511 else 512 { 513 throw new NoSuchAlgorithmException("can't support mode " + mode); 514 } 515 } 516 catch (NumberFormatException e) 517 { 518 throw new NoSuchAlgorithmException("can't support mode " + mode); 519 } 520 catch (IllegalArgumentException e) 521 { 522 throw new NoSuchAlgorithmException("can't support mode " + mode); 523 } 524 } 525 engineSetPadding( String padding)526 protected void engineSetPadding( 527 String padding) 528 throws NoSuchPaddingException 529 { 530 if (baseEngine == null) 531 { 532 throw new NoSuchPaddingException("no padding supported for this algorithm"); 533 } 534 535 String paddingName = Strings.toUpperCase(padding); 536 537 if (paddingName.equals("NOPADDING")) 538 { 539 if (cipher.wrapOnNoPadding()) 540 { 541 cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(cipher.getUnderlyingCipher())); 542 } 543 } 544 else if (paddingName.equals("WITHCTS") || paddingName.equals("CTSPADDING") || paddingName.equals("CS3PADDING")) 545 { 546 cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(cipher.getUnderlyingCipher())); 547 } 548 else 549 { 550 padded = true; 551 552 if (isAEADModeName(modeName)) 553 { 554 throw new NoSuchPaddingException("Only NoPadding can be used with AEAD modes."); 555 } 556 else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING")) 557 { 558 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher()); 559 } 560 else if (paddingName.equals("ZEROBYTEPADDING")) 561 { 562 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ZeroBytePadding()); 563 } 564 else if (paddingName.equals("ISO10126PADDING") || paddingName.equals("ISO10126-2PADDING")) 565 { 566 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO10126d2Padding()); 567 } 568 else if (paddingName.equals("X9.23PADDING") || paddingName.equals("X923PADDING")) 569 { 570 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new X923Padding()); 571 } 572 else if (paddingName.equals("ISO7816-4PADDING") || paddingName.equals("ISO9797-1PADDING")) 573 { 574 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO7816d4Padding()); 575 } 576 else if (paddingName.equals("TBCPADDING")) 577 { 578 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new TBCPadding()); 579 } 580 else 581 { 582 throw new NoSuchPaddingException("Padding " + padding + " unknown."); 583 } 584 } 585 } 586 engineInit( int opmode, Key key, final AlgorithmParameterSpec params, SecureRandom random)587 protected void engineInit( 588 int opmode, 589 Key key, 590 final AlgorithmParameterSpec params, 591 SecureRandom random) 592 throws InvalidKeyException, InvalidAlgorithmParameterException 593 { 594 CipherParameters param; 595 596 this.pbeSpec = null; 597 this.pbeAlgorithm = null; 598 this.engineParams = null; 599 this.aeadParams = null; 600 601 // 602 // basic key check 603 // 604 if (!(key instanceof SecretKey)) 605 { 606 throw new InvalidKeyException("Key for algorithm " + ((key != null) ? key.getAlgorithm() : null) + " not suitable for symmetric enryption."); 607 } 608 609 // 610 // for RC5-64 we must have some default parameters 611 // 612 if (params == null && (baseEngine != null && baseEngine.getAlgorithmName().startsWith("RC5-64"))) 613 { 614 throw new InvalidAlgorithmParameterException("RC5 requires an RC5ParametersSpec to be passed in."); 615 } 616 617 // 618 // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it). 619 // 620 if (scheme == PKCS12 || key instanceof PKCS12Key) 621 { 622 SecretKey k; 623 try 624 { 625 k = (SecretKey)key; 626 } 627 catch (Exception e) 628 { 629 throw new InvalidKeyException("PKCS12 requires a SecretKey/PBEKey"); 630 } 631 632 if (params instanceof PBEParameterSpec) 633 { 634 pbeSpec = (PBEParameterSpec)params; 635 } 636 637 if (k instanceof PBEKey && pbeSpec == null) 638 { 639 PBEKey pbeKey = (PBEKey)k; 640 if (pbeKey.getSalt() == null) 641 { 642 throw new InvalidAlgorithmParameterException("PBEKey requires parameters to specify salt"); 643 } 644 pbeSpec = new PBEParameterSpec(pbeKey.getSalt(), pbeKey.getIterationCount()); 645 } 646 647 if (pbeSpec == null && !(k instanceof PBEKey)) 648 { 649 throw new InvalidKeyException("Algorithm requires a PBE key"); 650 } 651 652 if (key instanceof BCPBEKey) 653 { 654 // PKCS#12 sets an IV, if we get a key that doesn't have ParametersWithIV we need to reject it. If the 655 // key has no parameters it means it's an old-school JCE PBE Key - we use getEncoded() on it. 656 CipherParameters pbeKeyParam = ((BCPBEKey)key).getParam(); 657 if (pbeKeyParam instanceof ParametersWithIV) 658 { 659 param = pbeKeyParam; 660 } 661 else if (pbeKeyParam == null) 662 { 663 param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS12, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName()); 664 } 665 else 666 { 667 throw new InvalidKeyException("Algorithm requires a PBE key suitable for PKCS12"); 668 } 669 } 670 else 671 { 672 param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS12, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName()); 673 } 674 if (param instanceof ParametersWithIV) 675 { 676 ivParam = (ParametersWithIV)param; 677 } 678 } 679 else if (key instanceof PBKDF1Key) 680 { 681 PBKDF1Key k = (PBKDF1Key)key; 682 683 if (params instanceof PBEParameterSpec) 684 { 685 pbeSpec = (PBEParameterSpec)params; 686 } 687 if (k instanceof PBKDF1KeyWithParameters && pbeSpec == null) 688 { 689 pbeSpec = new PBEParameterSpec(((PBKDF1KeyWithParameters)k).getSalt(), ((PBKDF1KeyWithParameters)k).getIterationCount()); 690 } 691 692 param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS5S1, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName()); 693 if (param instanceof ParametersWithIV) 694 { 695 ivParam = (ParametersWithIV)param; 696 } 697 } 698 else if (key instanceof BCPBEKey) 699 { 700 BCPBEKey k = (BCPBEKey)key; 701 702 if (k.getOID() != null) 703 { 704 pbeAlgorithm = k.getOID().getId(); 705 } 706 else 707 { 708 pbeAlgorithm = k.getAlgorithm(); 709 } 710 711 if (k.getParam() != null) 712 { 713 param = adjustParameters(params, k.getParam()); 714 } 715 else if (params instanceof PBEParameterSpec) 716 { 717 pbeSpec = (PBEParameterSpec)params; 718 param = PBE.Util.makePBEParameters(k, params, cipher.getUnderlyingCipher().getAlgorithmName()); 719 } 720 else 721 { 722 throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set."); 723 } 724 725 if (param instanceof ParametersWithIV) 726 { 727 ivParam = (ParametersWithIV)param; 728 } 729 } 730 else if (key instanceof PBEKey) 731 { 732 PBEKey k = (PBEKey)key; 733 pbeSpec = (PBEParameterSpec)params; 734 if (k instanceof PKCS12KeyWithParameters && pbeSpec == null) 735 { 736 pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount()); 737 } 738 739 param = PBE.Util.makePBEParameters(k.getEncoded(), scheme, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName()); 740 if (param instanceof ParametersWithIV) 741 { 742 ivParam = (ParametersWithIV)param; 743 } 744 } 745 else if (!(key instanceof RepeatedSecretKeySpec)) 746 { 747 if (scheme == PKCS5S1 || scheme == PKCS5S1_UTF8 || scheme == PKCS5S2 || scheme == PKCS5S2_UTF8) 748 { 749 throw new InvalidKeyException("Algorithm requires a PBE key"); 750 } 751 param = new KeyParameter(key.getEncoded()); 752 } 753 else 754 { 755 param = null; 756 } 757 758 if (params instanceof AEADParameterSpec) 759 { 760 if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher)) 761 { 762 throw new InvalidAlgorithmParameterException("AEADParameterSpec can only be used with AEAD modes."); 763 } 764 765 AEADParameterSpec aeadSpec = (AEADParameterSpec)params; 766 767 KeyParameter keyParam; 768 if (param instanceof ParametersWithIV) 769 { 770 keyParam = (KeyParameter)((ParametersWithIV)param).getParameters(); 771 } 772 else 773 { 774 keyParam = (KeyParameter)param; 775 } 776 param = aeadParams = new AEADParameters(keyParam, aeadSpec.getMacSizeInBits(), aeadSpec.getNonce(), aeadSpec.getAssociatedData()); 777 } 778 else if (params instanceof IvParameterSpec) 779 { 780 if (ivLength != 0) 781 { 782 IvParameterSpec p = (IvParameterSpec)params; 783 784 if (p.getIV().length != ivLength && !(cipher instanceof AEADGenericBlockCipher) && fixedIv) 785 { 786 throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long."); 787 } 788 789 if (param instanceof ParametersWithIV) 790 { 791 param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), p.getIV()); 792 } 793 else 794 { 795 param = new ParametersWithIV(param, p.getIV()); 796 } 797 ivParam = (ParametersWithIV)param; 798 } 799 else 800 { 801 if (modeName != null && modeName.equals("ECB")) 802 { 803 throw new InvalidAlgorithmParameterException("ECB mode does not use an IV"); 804 } 805 } 806 } 807 else if (params instanceof GOST28147ParameterSpec) 808 { 809 GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params; 810 811 param = new ParametersWithSBox( 812 new KeyParameter(key.getEncoded()), ((GOST28147ParameterSpec)params).getSbox()); 813 814 if (gost28147Param.getIV() != null && ivLength != 0) 815 { 816 if (param instanceof ParametersWithIV) 817 { 818 param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), gost28147Param.getIV()); 819 } 820 else 821 { 822 param = new ParametersWithIV(param, gost28147Param.getIV()); 823 } 824 ivParam = (ParametersWithIV)param; 825 } 826 } 827 else if (params instanceof RC2ParameterSpec) 828 { 829 RC2ParameterSpec rc2Param = (RC2ParameterSpec)params; 830 831 param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits()); 832 833 if (rc2Param.getIV() != null && ivLength != 0) 834 { 835 if (param instanceof ParametersWithIV) 836 { 837 param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), rc2Param.getIV()); 838 } 839 else 840 { 841 param = new ParametersWithIV(param, rc2Param.getIV()); 842 } 843 ivParam = (ParametersWithIV)param; 844 } 845 } 846 else if (params instanceof RC5ParameterSpec) 847 { 848 RC5ParameterSpec rc5Param = (RC5ParameterSpec)params; 849 850 param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds()); 851 if (baseEngine.getAlgorithmName().startsWith("RC5")) 852 { 853 if (baseEngine.getAlgorithmName().equals("RC5-32")) 854 { 855 if (rc5Param.getWordSize() != 32) 856 { 857 throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 32 not " + rc5Param.getWordSize() + "."); 858 } 859 } 860 else if (baseEngine.getAlgorithmName().equals("RC5-64")) 861 { 862 if (rc5Param.getWordSize() != 64) 863 { 864 throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 64 not " + rc5Param.getWordSize() + "."); 865 } 866 } 867 } 868 else 869 { 870 throw new InvalidAlgorithmParameterException("RC5 parameters passed to a cipher that is not RC5."); 871 } 872 if ((rc5Param.getIV() != null) && (ivLength != 0)) 873 { 874 if (param instanceof ParametersWithIV) 875 { 876 param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), rc5Param.getIV()); 877 } 878 else 879 { 880 param = new ParametersWithIV(param, rc5Param.getIV()); 881 } 882 ivParam = (ParametersWithIV)param; 883 } 884 } 885 else if (params instanceof FPEParameterSpec) 886 { 887 FPEParameterSpec spec = (FPEParameterSpec)params; 888 889 param = new FPEParameters((KeyParameter)param, spec.getRadix(), spec.getTweak(), spec.isUsingInverseFunction()); 890 } 891 else if (gcmSpecClass != null && gcmSpecClass.isInstance(params)) 892 { 893 if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher)) 894 { 895 throw new InvalidAlgorithmParameterException("GCMParameterSpec can only be used with AEAD modes."); 896 } 897 898 final KeyParameter keyParam; 899 if (param instanceof ParametersWithIV) 900 { 901 keyParam = (KeyParameter)((ParametersWithIV)param).getParameters(); 902 } 903 else 904 { 905 keyParam = (KeyParameter)param; 906 } 907 908 param = aeadParams = GcmSpecUtil.extractAeadParameters(keyParam, params); 909 } 910 else if (params != null && !(params instanceof PBEParameterSpec)) 911 { 912 throw new InvalidAlgorithmParameterException("unknown parameter type."); 913 } 914 915 if ((ivLength != 0) && !(param instanceof ParametersWithIV) && !(param instanceof AEADParameters)) 916 { 917 SecureRandom ivRandom = random; 918 919 if (ivRandom == null) 920 { 921 ivRandom = CryptoServicesRegistrar.getSecureRandom(); 922 } 923 924 if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE)) 925 { 926 byte[] iv = new byte[ivLength]; 927 928 ivRandom.nextBytes(iv); 929 param = new ParametersWithIV(param, iv); 930 ivParam = (ParametersWithIV)param; 931 } 932 else if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0) 933 { 934 throw new InvalidAlgorithmParameterException("no IV set when one expected"); 935 } 936 } 937 938 939 if (random != null && padded) 940 { 941 param = new ParametersWithRandom(param, random); 942 } 943 944 try 945 { 946 switch (opmode) 947 { 948 case Cipher.ENCRYPT_MODE: 949 case Cipher.WRAP_MODE: 950 cipher.init(true, param); 951 break; 952 case Cipher.DECRYPT_MODE: 953 case Cipher.UNWRAP_MODE: 954 cipher.init(false, param); 955 break; 956 default: 957 throw new InvalidParameterException("unknown opmode " + opmode + " passed"); 958 } 959 960 if (cipher instanceof AEADGenericBlockCipher && aeadParams == null) 961 { 962 AEADCipher aeadCipher = ((AEADGenericBlockCipher)cipher).cipher; 963 964 aeadParams = new AEADParameters((KeyParameter)ivParam.getParameters(), aeadCipher.getMac().length * 8, ivParam.getIV()); 965 } 966 } 967 catch (IllegalArgumentException e) 968 { 969 throw new InvalidAlgorithmParameterException(e.getMessage()); 970 } 971 catch (Exception e) 972 { 973 throw new InvalidKeyOrParametersException(e.getMessage(), e); 974 } 975 } 976 adjustParameters(AlgorithmParameterSpec params, CipherParameters param)977 private CipherParameters adjustParameters(AlgorithmParameterSpec params, CipherParameters param) 978 { 979 CipherParameters key; 980 981 if (param instanceof ParametersWithIV) 982 { 983 key = ((ParametersWithIV)param).getParameters(); 984 if (params instanceof IvParameterSpec) 985 { 986 IvParameterSpec iv = (IvParameterSpec)params; 987 988 ivParam = new ParametersWithIV(key, iv.getIV()); 989 param = ivParam; 990 } 991 else if (params instanceof GOST28147ParameterSpec) 992 { 993 // need to pick up IV and SBox. 994 GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params; 995 996 param = new ParametersWithSBox(param, gost28147Param.getSbox()); 997 998 if (gost28147Param.getIV() != null && ivLength != 0) 999 { 1000 ivParam = new ParametersWithIV(key, gost28147Param.getIV()); 1001 param = ivParam; 1002 } 1003 } 1004 } 1005 else 1006 { 1007 if (params instanceof IvParameterSpec) 1008 { 1009 IvParameterSpec iv = (IvParameterSpec)params; 1010 1011 ivParam = new ParametersWithIV(param, iv.getIV()); 1012 param = ivParam; 1013 } 1014 else if (params instanceof GOST28147ParameterSpec) 1015 { 1016 // need to pick up IV and SBox. 1017 GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params; 1018 1019 param = new ParametersWithSBox(param, gost28147Param.getSbox()); 1020 1021 if (gost28147Param.getIV() != null && ivLength != 0) 1022 { 1023 param = new ParametersWithIV(param, gost28147Param.getIV()); 1024 } 1025 } 1026 } 1027 return param; 1028 } 1029 engineInit( int opmode, Key key, AlgorithmParameters params, SecureRandom random)1030 protected void engineInit( 1031 int opmode, 1032 Key key, 1033 AlgorithmParameters params, 1034 SecureRandom random) 1035 throws InvalidKeyException, InvalidAlgorithmParameterException 1036 { 1037 AlgorithmParameterSpec paramSpec = null; 1038 1039 if (params != null) 1040 { 1041 paramSpec = SpecUtil.extractSpec(params, availableSpecs); 1042 1043 if (paramSpec == null) 1044 { 1045 throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString()); 1046 } 1047 } 1048 1049 engineInit(opmode, key, paramSpec, random); 1050 1051 engineParams = params; 1052 } 1053 engineInit( int opmode, Key key, SecureRandom random)1054 protected void engineInit( 1055 int opmode, 1056 Key key, 1057 SecureRandom random) 1058 throws InvalidKeyException 1059 { 1060 try 1061 { 1062 engineInit(opmode, key, (AlgorithmParameterSpec)null, random); 1063 } 1064 catch (InvalidAlgorithmParameterException e) 1065 { 1066 throw new InvalidKeyException(e.getMessage()); 1067 } 1068 } 1069 engineUpdateAAD(byte[] input, int offset, int length)1070 protected void engineUpdateAAD(byte[] input, int offset, int length) 1071 { 1072 cipher.updateAAD(input, offset, length); 1073 } 1074 engineUpdate( byte[] input, int inputOffset, int inputLen)1075 protected byte[] engineUpdate( 1076 byte[] input, 1077 int inputOffset, 1078 int inputLen) 1079 { 1080 int length = cipher.getUpdateOutputSize(inputLen); 1081 1082 if (length > 0) 1083 { 1084 byte[] out = new byte[length]; 1085 1086 int len = cipher.processBytes(input, inputOffset, inputLen, out, 0); 1087 1088 if (len == 0) 1089 { 1090 return null; 1091 } 1092 else if (len != out.length) 1093 { 1094 byte[] tmp = new byte[len]; 1095 1096 System.arraycopy(out, 0, tmp, 0, len); 1097 1098 return tmp; 1099 } 1100 1101 return out; 1102 } 1103 1104 cipher.processBytes(input, inputOffset, inputLen, null, 0); 1105 1106 return null; 1107 } 1108 engineUpdate( byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)1109 protected int engineUpdate( 1110 byte[] input, 1111 int inputOffset, 1112 int inputLen, 1113 byte[] output, 1114 int outputOffset) 1115 throws ShortBufferException 1116 { 1117 if (outputOffset + cipher.getUpdateOutputSize(inputLen) > output.length) 1118 { 1119 throw new ShortBufferException("output buffer too short for input."); 1120 } 1121 1122 try 1123 { 1124 return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset); 1125 } 1126 catch (DataLengthException e) 1127 { 1128 // should never occur 1129 throw new IllegalStateException(e.toString()); 1130 } 1131 } 1132 engineDoFinal( byte[] input, int inputOffset, int inputLen)1133 protected byte[] engineDoFinal( 1134 byte[] input, 1135 int inputOffset, 1136 int inputLen) 1137 throws IllegalBlockSizeException, BadPaddingException 1138 { 1139 int len = 0; 1140 byte[] tmp = new byte[engineGetOutputSize(inputLen)]; 1141 1142 if (inputLen != 0) 1143 { 1144 len = cipher.processBytes(input, inputOffset, inputLen, tmp, 0); 1145 } 1146 1147 try 1148 { 1149 len += cipher.doFinal(tmp, len); 1150 } 1151 catch (DataLengthException e) 1152 { 1153 throw new IllegalBlockSizeException(e.getMessage()); 1154 } 1155 1156 if (len == tmp.length) 1157 { 1158 return tmp; 1159 } 1160 1161 if (len > tmp.length) 1162 { 1163 throw new IllegalBlockSizeException("internal buffer overflow"); 1164 } 1165 1166 byte[] out = new byte[len]; 1167 1168 System.arraycopy(tmp, 0, out, 0, len); 1169 1170 return out; 1171 } 1172 engineDoFinal( byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)1173 protected int engineDoFinal( 1174 byte[] input, 1175 int inputOffset, 1176 int inputLen, 1177 byte[] output, 1178 int outputOffset) 1179 throws IllegalBlockSizeException, BadPaddingException, ShortBufferException 1180 { 1181 int len = 0; 1182 1183 if (outputOffset + engineGetOutputSize(inputLen) > output.length) 1184 { 1185 throw new ShortBufferException("output buffer too short for input."); 1186 } 1187 1188 try 1189 { 1190 if (inputLen != 0) 1191 { 1192 len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset); 1193 } 1194 1195 return (len + cipher.doFinal(output, outputOffset + len)); 1196 } 1197 catch (OutputLengthException e) 1198 { 1199 throw new IllegalBlockSizeException(e.getMessage()); 1200 } 1201 catch (DataLengthException e) 1202 { 1203 throw new IllegalBlockSizeException(e.getMessage()); 1204 } 1205 } 1206 isAEADModeName( String modeName)1207 private boolean isAEADModeName( 1208 String modeName) 1209 { 1210 return "CCM".equals(modeName) || "EAX".equals(modeName) || "GCM".equals(modeName) || "GCM-SIV".equals(modeName) || "OCB".equals(modeName); 1211 } 1212 1213 /* 1214 * The ciphers that inherit from us. 1215 */ 1216 1217 static private interface GenericBlockCipher 1218 { init(boolean forEncryption, CipherParameters params)1219 public void init(boolean forEncryption, CipherParameters params) 1220 throws IllegalArgumentException; 1221 wrapOnNoPadding()1222 public boolean wrapOnNoPadding(); 1223 getAlgorithmName()1224 public String getAlgorithmName(); 1225 getUnderlyingCipher()1226 public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher(); 1227 getOutputSize(int len)1228 public int getOutputSize(int len); 1229 getUpdateOutputSize(int len)1230 public int getUpdateOutputSize(int len); 1231 updateAAD(byte[] input, int offset, int length)1232 public void updateAAD(byte[] input, int offset, int length); 1233 processByte(byte in, byte[] out, int outOff)1234 public int processByte(byte in, byte[] out, int outOff) 1235 throws DataLengthException; 1236 processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)1237 public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) 1238 throws DataLengthException; 1239 doFinal(byte[] out, int outOff)1240 public int doFinal(byte[] out, int outOff) 1241 throws IllegalStateException, 1242 BadPaddingException; 1243 } 1244 1245 private static class BufferedGenericBlockCipher 1246 implements GenericBlockCipher 1247 { 1248 private BufferedBlockCipher cipher; 1249 BufferedGenericBlockCipher(BufferedBlockCipher cipher)1250 BufferedGenericBlockCipher(BufferedBlockCipher cipher) 1251 { 1252 this.cipher = cipher; 1253 } 1254 BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher)1255 BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher) 1256 { 1257 this.cipher = new PaddedBufferedBlockCipher(cipher); 1258 } 1259 BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher, BlockCipherPadding padding)1260 BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher, BlockCipherPadding padding) 1261 { 1262 this.cipher = new PaddedBufferedBlockCipher(cipher, padding); 1263 } 1264 init(boolean forEncryption, CipherParameters params)1265 public void init(boolean forEncryption, CipherParameters params) 1266 throws IllegalArgumentException 1267 { 1268 cipher.init(forEncryption, params); 1269 } 1270 wrapOnNoPadding()1271 public boolean wrapOnNoPadding() 1272 { 1273 return !(cipher instanceof CTSBlockCipher); 1274 } 1275 getAlgorithmName()1276 public String getAlgorithmName() 1277 { 1278 return cipher.getUnderlyingCipher().getAlgorithmName(); 1279 } 1280 getUnderlyingCipher()1281 public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher() 1282 { 1283 return cipher.getUnderlyingCipher(); 1284 } 1285 getOutputSize(int len)1286 public int getOutputSize(int len) 1287 { 1288 return cipher.getOutputSize(len); 1289 } 1290 getUpdateOutputSize(int len)1291 public int getUpdateOutputSize(int len) 1292 { 1293 return cipher.getUpdateOutputSize(len); 1294 } 1295 updateAAD(byte[] input, int offset, int length)1296 public void updateAAD(byte[] input, int offset, int length) 1297 { 1298 throw new UnsupportedOperationException("AAD is not supported in the current mode."); 1299 } 1300 processByte(byte in, byte[] out, int outOff)1301 public int processByte(byte in, byte[] out, int outOff) 1302 throws DataLengthException 1303 { 1304 return cipher.processByte(in, out, outOff); 1305 } 1306 processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)1307 public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) 1308 throws DataLengthException 1309 { 1310 return cipher.processBytes(in, inOff, len, out, outOff); 1311 } 1312 doFinal(byte[] out, int outOff)1313 public int doFinal(byte[] out, int outOff) 1314 throws IllegalStateException, BadPaddingException 1315 { 1316 try 1317 { 1318 return cipher.doFinal(out, outOff); 1319 } 1320 catch (InvalidCipherTextException e) 1321 { 1322 throw new BadPaddingException(e.getMessage()); 1323 } 1324 } 1325 } 1326 1327 private static class BufferedFPEBlockCipher 1328 implements GenericBlockCipher 1329 { 1330 private FPEEngine cipher; 1331 private ErasableOutputStream eOut = new ErasableOutputStream(); 1332 BufferedFPEBlockCipher(FPEEngine cipher)1333 BufferedFPEBlockCipher(FPEEngine cipher) 1334 { 1335 this.cipher = cipher; 1336 } 1337 init(boolean forEncryption, CipherParameters params)1338 public void init(boolean forEncryption, CipherParameters params) 1339 throws IllegalArgumentException 1340 { 1341 cipher.init(forEncryption, params); 1342 } 1343 wrapOnNoPadding()1344 public boolean wrapOnNoPadding() 1345 { 1346 return false; 1347 } 1348 getAlgorithmName()1349 public String getAlgorithmName() 1350 { 1351 return cipher.getAlgorithmName(); 1352 } 1353 getUnderlyingCipher()1354 public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher() 1355 { 1356 throw new IllegalStateException("not applicable for FPE"); 1357 } 1358 getOutputSize(int len)1359 public int getOutputSize(int len) 1360 { 1361 return eOut.size() + len; 1362 } 1363 getUpdateOutputSize(int len)1364 public int getUpdateOutputSize(int len) 1365 { 1366 return 0; 1367 } 1368 updateAAD(byte[] input, int offset, int length)1369 public void updateAAD(byte[] input, int offset, int length) 1370 { 1371 throw new UnsupportedOperationException("AAD is not supported in the current mode."); 1372 } 1373 processByte(byte in, byte[] out, int outOff)1374 public int processByte(byte in, byte[] out, int outOff) 1375 throws DataLengthException 1376 { 1377 eOut.write(in); 1378 1379 return 0; 1380 } 1381 processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)1382 public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) 1383 throws DataLengthException 1384 { 1385 eOut.write(in, inOff, len); 1386 1387 return 0; 1388 } 1389 doFinal(byte[] out, int outOff)1390 public int doFinal(byte[] out, int outOff) 1391 throws IllegalStateException, BadPaddingException 1392 { 1393 try 1394 { 1395 return cipher.processBlock(eOut.getBuf(), 0, eOut.size(), out, outOff); 1396 } 1397 finally 1398 { 1399 eOut.erase(); 1400 } 1401 } 1402 } 1403 1404 private static class AEADGenericBlockCipher 1405 implements GenericBlockCipher 1406 { 1407 private static final Constructor aeadBadTagConstructor; 1408 1409 static 1410 { 1411 Class aeadBadTagClass = ClassUtil.loadClass(BaseBlockCipher.class, "javax.crypto.AEADBadTagException"); 1412 if (aeadBadTagClass != null) 1413 { 1414 aeadBadTagConstructor = findExceptionConstructor(aeadBadTagClass); 1415 } 1416 else 1417 { 1418 aeadBadTagConstructor = null; 1419 } 1420 } 1421 findExceptionConstructor(Class clazz)1422 private static Constructor findExceptionConstructor(Class clazz) 1423 { 1424 try 1425 { 1426 return clazz.getConstructor(new Class[]{String.class}); 1427 } 1428 catch (Exception e) 1429 { 1430 return null; 1431 } 1432 } 1433 1434 private AEADCipher cipher; 1435 AEADGenericBlockCipher(AEADCipher cipher)1436 AEADGenericBlockCipher(AEADCipher cipher) 1437 { 1438 this.cipher = cipher; 1439 } 1440 init(boolean forEncryption, CipherParameters params)1441 public void init(boolean forEncryption, CipherParameters params) 1442 throws IllegalArgumentException 1443 { 1444 cipher.init(forEncryption, params); 1445 } 1446 getAlgorithmName()1447 public String getAlgorithmName() 1448 { 1449 if (cipher instanceof AEADBlockCipher) 1450 { 1451 return ((AEADBlockCipher)cipher).getUnderlyingCipher().getAlgorithmName(); 1452 } 1453 1454 return cipher.getAlgorithmName(); 1455 } 1456 wrapOnNoPadding()1457 public boolean wrapOnNoPadding() 1458 { 1459 return false; 1460 } 1461 getUnderlyingCipher()1462 public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher() 1463 { 1464 if (cipher instanceof AEADBlockCipher) 1465 { 1466 return ((AEADBlockCipher)cipher).getUnderlyingCipher(); 1467 } 1468 1469 return null; 1470 } 1471 getOutputSize(int len)1472 public int getOutputSize(int len) 1473 { 1474 return cipher.getOutputSize(len); 1475 } 1476 getUpdateOutputSize(int len)1477 public int getUpdateOutputSize(int len) 1478 { 1479 return cipher.getUpdateOutputSize(len); 1480 } 1481 updateAAD(byte[] input, int offset, int length)1482 public void updateAAD(byte[] input, int offset, int length) 1483 { 1484 cipher.processAADBytes(input, offset, length); 1485 } 1486 processByte(byte in, byte[] out, int outOff)1487 public int processByte(byte in, byte[] out, int outOff) 1488 throws DataLengthException 1489 { 1490 return cipher.processByte(in, out, outOff); 1491 } 1492 processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)1493 public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) 1494 throws DataLengthException 1495 { 1496 return cipher.processBytes(in, inOff, len, out, outOff); 1497 } 1498 doFinal(byte[] out, int outOff)1499 public int doFinal(byte[] out, int outOff) 1500 throws IllegalStateException, BadPaddingException 1501 { 1502 try 1503 { 1504 return cipher.doFinal(out, outOff); 1505 } 1506 catch (InvalidCipherTextException e) 1507 { 1508 if (aeadBadTagConstructor != null) 1509 { 1510 BadPaddingException aeadBadTag = null; 1511 try 1512 { 1513 aeadBadTag = (BadPaddingException)aeadBadTagConstructor 1514 .newInstance(new Object[]{e.getMessage()}); 1515 } 1516 catch (Exception i) 1517 { 1518 // Shouldn't happen, but fall through to BadPaddingException 1519 } 1520 if (aeadBadTag != null) 1521 { 1522 throw aeadBadTag; 1523 } 1524 } 1525 throw new BadPaddingException(e.getMessage()); 1526 } 1527 } 1528 } 1529 } 1530