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