JCEStreamCipher.java revision aea1f1224e7ad62991b68c485f086abcb289f82b
1package org.bouncycastle.jce.provider; 2 3import java.security.AlgorithmParameters; 4import java.security.InvalidAlgorithmParameterException; 5import java.security.InvalidKeyException; 6import java.security.Key; 7import java.security.KeyFactory; 8import java.security.NoSuchAlgorithmException; 9import java.security.NoSuchProviderException; 10import java.security.PrivateKey; 11import java.security.SecureRandom; 12import java.security.spec.AlgorithmParameterSpec; 13import java.security.spec.InvalidKeySpecException; 14import java.security.spec.PKCS8EncodedKeySpec; 15import java.security.spec.X509EncodedKeySpec; 16 17import javax.crypto.BadPaddingException; 18import javax.crypto.Cipher; 19import javax.crypto.CipherSpi; 20import javax.crypto.IllegalBlockSizeException; 21import javax.crypto.NoSuchPaddingException; 22import javax.crypto.SecretKey; 23import javax.crypto.ShortBufferException; 24import javax.crypto.spec.IvParameterSpec; 25import javax.crypto.spec.PBEParameterSpec; 26// BEGIN android-removed 27// import javax.crypto.spec.RC2ParameterSpec; 28// import javax.crypto.spec.RC5ParameterSpec; 29// END android-removed 30import javax.crypto.spec.SecretKeySpec; 31 32import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; 33import org.bouncycastle.crypto.BlockCipher; 34import org.bouncycastle.crypto.CipherParameters; 35import org.bouncycastle.crypto.DataLengthException; 36import org.bouncycastle.crypto.StreamBlockCipher; 37import org.bouncycastle.crypto.StreamCipher; 38// BEGIN android-removed 39// import org.bouncycastle.crypto.engines.BlowfishEngine; 40// import org.bouncycastle.crypto.engines.DESEngine; 41// import org.bouncycastle.crypto.engines.DESedeEngine; 42// END android-removed 43import org.bouncycastle.crypto.engines.RC4Engine; 44// BEGIN android-removed 45// import org.bouncycastle.crypto.engines.SkipjackEngine; 46// import org.bouncycastle.crypto.engines.TwofishEngine; 47// END android-removed 48import org.bouncycastle.crypto.modes.CFBBlockCipher; 49import org.bouncycastle.crypto.modes.OFBBlockCipher; 50import org.bouncycastle.crypto.params.KeyParameter; 51import org.bouncycastle.crypto.params.ParametersWithIV; 52import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey; 53import org.bouncycastle.jcajce.provider.symmetric.util.PBE; 54 55public class JCEStreamCipher 56 extends CipherSpi 57 implements PBE 58{ 59 // 60 // specs we can handle. 61 // 62 private Class[] availableSpecs = 63 { 64 // BEGIN android-removed 65 // RC2ParameterSpec.class, 66 // RC5ParameterSpec.class, 67 // END android-removed 68 IvParameterSpec.class, 69 PBEParameterSpec.class 70 }; 71 72 private StreamCipher cipher; 73 private ParametersWithIV ivParam; 74 75 private int ivLength = 0; 76 77 private PBEParameterSpec pbeSpec = null; 78 private String pbeAlgorithm = null; 79 80 private AlgorithmParameters engineParams; 81 82 protected JCEStreamCipher( 83 StreamCipher engine, 84 int ivLength) 85 { 86 cipher = engine; 87 this.ivLength = ivLength; 88 } 89 90 protected JCEStreamCipher( 91 BlockCipher engine, 92 int ivLength) 93 { 94 this.ivLength = ivLength; 95 96 cipher = new StreamBlockCipher(engine); 97 } 98 99 protected int engineGetBlockSize() 100 { 101 return 0; 102 } 103 104 protected byte[] engineGetIV() 105 { 106 return (ivParam != null) ? ivParam.getIV() : null; 107 } 108 109 protected int engineGetKeySize( 110 Key key) 111 { 112 return key.getEncoded().length * 8; 113 } 114 115 protected int engineGetOutputSize( 116 int inputLen) 117 { 118 return inputLen; 119 } 120 121 protected AlgorithmParameters engineGetParameters() 122 { 123 if (engineParams == null) 124 { 125 if (pbeSpec != null) 126 { 127 try 128 { 129 AlgorithmParameters engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME); 130 engineParams.init(pbeSpec); 131 132 return engineParams; 133 } 134 catch (Exception e) 135 { 136 return null; 137 } 138 } 139 } 140 141 return engineParams; 142 } 143 144 /** 145 * should never be called. 146 */ 147 protected void engineSetMode( 148 String mode) 149 { 150 if (!mode.equalsIgnoreCase("ECB")) 151 { 152 throw new IllegalArgumentException("can't support mode " + mode); 153 } 154 } 155 156 /** 157 * should never be called. 158 */ 159 protected void engineSetPadding( 160 String padding) 161 throws NoSuchPaddingException 162 { 163 if (!padding.equalsIgnoreCase("NoPadding")) 164 { 165 throw new NoSuchPaddingException("Padding " + padding + " unknown."); 166 } 167 } 168 169 protected void engineInit( 170 int opmode, 171 Key key, 172 AlgorithmParameterSpec params, 173 SecureRandom random) 174 throws InvalidKeyException, InvalidAlgorithmParameterException 175 { 176 CipherParameters param; 177 178 this.pbeSpec = null; 179 this.pbeAlgorithm = null; 180 181 this.engineParams = null; 182 183 // 184 // basic key check 185 // 186 if (!(key instanceof SecretKey)) 187 { 188 throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption."); 189 } 190 191 if (key instanceof BCPBEKey) 192 { 193 BCPBEKey k = (BCPBEKey)key; 194 195 if (k.getOID() != null) 196 { 197 pbeAlgorithm = k.getOID().getId(); 198 } 199 else 200 { 201 pbeAlgorithm = k.getAlgorithm(); 202 } 203 204 if (k.getParam() != null) 205 { 206 param = k.getParam(); 207 pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount()); 208 } 209 else if (params instanceof PBEParameterSpec) 210 { 211 param = PBE.Util.makePBEParameters(k, params, cipher.getAlgorithmName()); 212 pbeSpec = (PBEParameterSpec)params; 213 } 214 else 215 { 216 throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set."); 217 } 218 219 if (k.getIvSize() != 0) 220 { 221 ivParam = (ParametersWithIV)param; 222 } 223 } 224 else if (params == null) 225 { 226 param = new KeyParameter(key.getEncoded()); 227 } 228 else if (params instanceof IvParameterSpec) 229 { 230 param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV()); 231 ivParam = (ParametersWithIV)param; 232 } 233 else 234 { 235 throw new IllegalArgumentException("unknown parameter type."); 236 } 237 238 if ((ivLength != 0) && !(param instanceof ParametersWithIV)) 239 { 240 SecureRandom ivRandom = random; 241 242 if (ivRandom == null) 243 { 244 ivRandom = new SecureRandom(); 245 } 246 247 if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE)) 248 { 249 byte[] iv = new byte[ivLength]; 250 251 ivRandom.nextBytes(iv); 252 param = new ParametersWithIV(param, iv); 253 ivParam = (ParametersWithIV)param; 254 } 255 else 256 { 257 throw new InvalidAlgorithmParameterException("no IV set when one expected"); 258 } 259 } 260 261 switch (opmode) 262 { 263 case Cipher.ENCRYPT_MODE: 264 case Cipher.WRAP_MODE: 265 cipher.init(true, param); 266 break; 267 case Cipher.DECRYPT_MODE: 268 case Cipher.UNWRAP_MODE: 269 cipher.init(false, param); 270 break; 271 default: 272 System.out.println("eeek!"); 273 } 274 } 275 276 protected void engineInit( 277 int opmode, 278 Key key, 279 AlgorithmParameters params, 280 SecureRandom random) 281 throws InvalidKeyException, InvalidAlgorithmParameterException 282 { 283 AlgorithmParameterSpec paramSpec = null; 284 285 if (params != null) 286 { 287 for (int i = 0; i != availableSpecs.length; i++) 288 { 289 try 290 { 291 paramSpec = params.getParameterSpec(availableSpecs[i]); 292 break; 293 } 294 catch (Exception e) 295 { 296 continue; 297 } 298 } 299 300 if (paramSpec == null) 301 { 302 throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString()); 303 } 304 } 305 306 engineInit(opmode, key, paramSpec, random); 307 engineParams = params; 308 } 309 310 protected void engineInit( 311 int opmode, 312 Key key, 313 SecureRandom random) 314 throws InvalidKeyException 315 { 316 try 317 { 318 engineInit(opmode, key, (AlgorithmParameterSpec)null, random); 319 } 320 catch (InvalidAlgorithmParameterException e) 321 { 322 throw new InvalidKeyException(e.getMessage()); 323 } 324 } 325 326 protected byte[] engineUpdate( 327 byte[] input, 328 int inputOffset, 329 int inputLen) 330 { 331 byte[] out = new byte[inputLen]; 332 333 cipher.processBytes(input, inputOffset, inputLen, out, 0); 334 335 return out; 336 } 337 338 protected int engineUpdate( 339 byte[] input, 340 int inputOffset, 341 int inputLen, 342 byte[] output, 343 int outputOffset) 344 throws ShortBufferException 345 { 346 try 347 { 348 cipher.processBytes(input, inputOffset, inputLen, output, outputOffset); 349 350 return inputLen; 351 } 352 catch (DataLengthException e) 353 { 354 throw new ShortBufferException(e.getMessage()); 355 } 356 } 357 358 protected byte[] engineDoFinal( 359 byte[] input, 360 int inputOffset, 361 int inputLen) 362 throws BadPaddingException, IllegalBlockSizeException 363 { 364 if (inputLen != 0) 365 { 366 byte[] out = engineUpdate(input, inputOffset, inputLen); 367 368 cipher.reset(); 369 370 return out; 371 } 372 373 cipher.reset(); 374 375 return new byte[0]; 376 } 377 378 protected int engineDoFinal( 379 byte[] input, 380 int inputOffset, 381 int inputLen, 382 byte[] output, 383 int outputOffset) 384 throws BadPaddingException 385 { 386 if (inputLen != 0) 387 { 388 cipher.processBytes(input, inputOffset, inputLen, output, outputOffset); 389 } 390 391 cipher.reset(); 392 393 return inputLen; 394 } 395 396 protected byte[] engineWrap( 397 Key key) 398 throws IllegalBlockSizeException, InvalidKeyException 399 { 400 byte[] encoded = key.getEncoded(); 401 if (encoded == null) 402 { 403 throw new InvalidKeyException("Cannot wrap key, null encoding."); 404 } 405 406 try 407 { 408 return engineDoFinal(encoded, 0, encoded.length); 409 } 410 catch (BadPaddingException e) 411 { 412 throw new IllegalBlockSizeException(e.getMessage()); 413 } 414 } 415 416 protected Key engineUnwrap( 417 byte[] wrappedKey, 418 String wrappedKeyAlgorithm, 419 int wrappedKeyType) 420 throws InvalidKeyException 421 { 422 byte[] encoded; 423 try 424 { 425 encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length); 426 } 427 catch (BadPaddingException e) 428 { 429 throw new InvalidKeyException(e.getMessage()); 430 } 431 catch (IllegalBlockSizeException e2) 432 { 433 throw new InvalidKeyException(e2.getMessage()); 434 } 435 436 if (wrappedKeyType == Cipher.SECRET_KEY) 437 { 438 return new SecretKeySpec(encoded, wrappedKeyAlgorithm); 439 } 440 else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY) 441 { 442 /* 443 * The caller doesn't know the algorithm as it is part of 444 * the encrypted data. 445 */ 446 try 447 { 448 PrivateKeyInfo in = PrivateKeyInfo.getInstance(encoded); 449 450 PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in); 451 452 if (privKey != null) 453 { 454 return privKey; 455 } 456 else 457 { 458 throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported"); 459 } 460 } 461 catch (Exception e) 462 { 463 throw new InvalidKeyException("Invalid key encoding."); 464 } 465 } 466 else 467 { 468 try 469 { 470 KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME); 471 472 if (wrappedKeyType == Cipher.PUBLIC_KEY) 473 { 474 return kf.generatePublic(new X509EncodedKeySpec(encoded)); 475 } 476 else if (wrappedKeyType == Cipher.PRIVATE_KEY) 477 { 478 return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded)); 479 } 480 } 481 catch (NoSuchProviderException e) 482 { 483 throw new InvalidKeyException("Unknown key type " + e.getMessage()); 484 } 485 catch (NoSuchAlgorithmException e) 486 { 487 throw new InvalidKeyException("Unknown key type " + e.getMessage()); 488 } 489 catch (InvalidKeySpecException e2) 490 { 491 throw new InvalidKeyException("Unknown key type " + e2.getMessage()); 492 } 493 494 throw new InvalidKeyException("Unknown key type " + wrappedKeyType); 495 } 496 } 497 498 /* 499 * The ciphers that inherit from us. 500 */ 501 502 // BEGIN android-removed 503 // /** 504 // * DES 505 // */ 506 // static public class DES_CFB8 507 // extends JCEStreamCipher 508 // { 509 // public DES_CFB8() 510 // { 511 // super(new CFBBlockCipher(new DESEngine(), 8), 64); 512 // } 513 // } 514 // 515 // /** 516 // * DESede 517 // */ 518 // static public class DESede_CFB8 519 // extends JCEStreamCipher 520 // { 521 // public DESede_CFB8() 522 // { 523 // super(new CFBBlockCipher(new DESedeEngine(), 8), 64); 524 // } 525 // } 526 // 527 // /** 528 // * SKIPJACK 529 // */ 530 // static public class Skipjack_CFB8 531 // extends JCEStreamCipher 532 // { 533 // public Skipjack_CFB8() 534 // { 535 // super(new CFBBlockCipher(new SkipjackEngine(), 8), 64); 536 // } 537 // } 538 // 539 // /** 540 // * Blowfish 541 // */ 542 // static public class Blowfish_CFB8 543 // extends JCEStreamCipher 544 // { 545 // public Blowfish_CFB8() 546 // { 547 // super(new CFBBlockCipher(new BlowfishEngine(), 8), 64); 548 // } 549 // } 550 // 551 // /** 552 // * Twofish 553 // */ 554 // static public class Twofish_CFB8 555 // extends JCEStreamCipher 556 // { 557 // public Twofish_CFB8() 558 // { 559 // super(new CFBBlockCipher(new TwofishEngine(), 8), 128); 560 // } 561 // } 562 // 563 // /** 564 // * DES 565 // */ 566 // static public class DES_OFB8 567 // extends JCEStreamCipher 568 // { 569 // public DES_OFB8() 570 // { 571 // super(new OFBBlockCipher(new DESEngine(), 8), 64); 572 // } 573 // } 574 // 575 // /** 576 // * DESede 577 // */ 578 // static public class DESede_OFB8 579 // extends JCEStreamCipher 580 // { 581 // public DESede_OFB8() 582 // { 583 // super(new OFBBlockCipher(new DESedeEngine(), 8), 64); 584 // } 585 // } 586 // 587 // /** 588 // * SKIPJACK 589 // */ 590 // static public class Skipjack_OFB8 591 // extends JCEStreamCipher 592 // { 593 // public Skipjack_OFB8() 594 // { 595 // super(new OFBBlockCipher(new SkipjackEngine(), 8), 64); 596 // } 597 // } 598 // 599 // /** 600 // * Blowfish 601 // */ 602 // static public class Blowfish_OFB8 603 // extends JCEStreamCipher 604 // { 605 // public Blowfish_OFB8() 606 // { 607 // super(new OFBBlockCipher(new BlowfishEngine(), 8), 64); 608 // } 609 // } 610 // 611 // /** 612 // * Twofish 613 // */ 614 // static public class Twofish_OFB8 615 // extends JCEStreamCipher 616 // { 617 // public Twofish_OFB8() 618 // { 619 // super(new OFBBlockCipher(new TwofishEngine(), 8), 128); 620 // } 621 // } 622 // END android-removed 623 624 /** 625 * PBEWithSHAAnd128BitRC4 626 */ 627 static public class PBEWithSHAAnd128BitRC4 628 extends JCEStreamCipher 629 { 630 public PBEWithSHAAnd128BitRC4() 631 { 632 super(new RC4Engine(), 0); 633 } 634 } 635 636 /** 637 * PBEWithSHAAnd40BitRC4 638 */ 639 static public class PBEWithSHAAnd40BitRC4 640 extends JCEStreamCipher 641 { 642 public PBEWithSHAAnd40BitRC4() 643 { 644 super(new RC4Engine(), 0); 645 } 646 } 647} 648