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