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.SecureRandom; 9import java.security.spec.AlgorithmParameterSpec; 10 11import javax.crypto.Cipher; 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; 27import org.bouncycastle.crypto.params.KeyParameter; 28import org.bouncycastle.crypto.params.ParametersWithIV; 29import org.bouncycastle.jce.provider.BouncyCastleProvider; 30 31public class BaseStreamCipher 32 extends BaseWrapCipher 33 implements PBE 34{ 35 // 36 // specs we can handle. 37 // 38 private Class[] availableSpecs = 39 { 40 // BEGIN android-removed 41 // RC2ParameterSpec.class, 42 // RC5ParameterSpec.class, 43 // END android-removed 44 IvParameterSpec.class, 45 PBEParameterSpec.class 46 }; 47 48 private StreamCipher cipher; 49 private ParametersWithIV ivParam; 50 51 private int ivLength = 0; 52 53 private PBEParameterSpec pbeSpec = null; 54 private String pbeAlgorithm = null; 55 56 protected BaseStreamCipher( 57 StreamCipher engine, 58 int ivLength) 59 { 60 cipher = engine; 61 this.ivLength = ivLength; 62 } 63 64 protected BaseStreamCipher( 65 BlockCipher engine, 66 int ivLength) 67 { 68 this.ivLength = ivLength; 69 70 cipher = new StreamBlockCipher(engine); 71 } 72 73 protected int engineGetBlockSize() 74 { 75 return 0; 76 } 77 78 protected byte[] engineGetIV() 79 { 80 return (ivParam != null) ? ivParam.getIV() : null; 81 } 82 83 protected int engineGetKeySize( 84 Key key) 85 { 86 return key.getEncoded().length * 8; 87 } 88 89 protected int engineGetOutputSize( 90 int inputLen) 91 { 92 return inputLen; 93 } 94 95 protected AlgorithmParameters engineGetParameters() 96 { 97 if (engineParams == null) 98 { 99 if (pbeSpec != null) 100 { 101 try 102 { 103 AlgorithmParameters engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME); 104 engineParams.init(pbeSpec); 105 106 return engineParams; 107 } 108 catch (Exception e) 109 { 110 return null; 111 } 112 } 113 } 114 115 return engineParams; 116 } 117 118 /** 119 * should never be called. 120 */ 121 protected void engineSetMode( 122 String mode) 123 { 124 if (!mode.equalsIgnoreCase("ECB")) 125 { 126 throw new IllegalArgumentException("can't support mode " + mode); 127 } 128 } 129 130 /** 131 * should never be called. 132 */ 133 protected void engineSetPadding( 134 String padding) 135 throws NoSuchPaddingException 136 { 137 if (!padding.equalsIgnoreCase("NoPadding")) 138 { 139 throw new NoSuchPaddingException("Padding " + padding + " unknown."); 140 } 141 } 142 143 protected void engineInit( 144 int opmode, 145 Key key, 146 AlgorithmParameterSpec params, 147 SecureRandom random) 148 throws InvalidKeyException, InvalidAlgorithmParameterException 149 { 150 CipherParameters param; 151 152 this.pbeSpec = null; 153 this.pbeAlgorithm = null; 154 155 this.engineParams = null; 156 157 // 158 // basic key check 159 // 160 if (!(key instanceof SecretKey)) 161 { 162 throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption."); 163 } 164 165 if (key instanceof BCPBEKey) 166 { 167 BCPBEKey k = (BCPBEKey)key; 168 169 if (k.getOID() != null) 170 { 171 pbeAlgorithm = k.getOID().getId(); 172 } 173 else 174 { 175 pbeAlgorithm = k.getAlgorithm(); 176 } 177 178 if (k.getParam() != null) 179 { 180 param = k.getParam(); 181 pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount()); 182 } 183 else if (params instanceof PBEParameterSpec) 184 { 185 param = PBE.Util.makePBEParameters(k, params, cipher.getAlgorithmName()); 186 pbeSpec = (PBEParameterSpec)params; 187 } 188 else 189 { 190 throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set."); 191 } 192 193 if (k.getIvSize() != 0) 194 { 195 ivParam = (ParametersWithIV)param; 196 } 197 } 198 else if (params == null) 199 { 200 param = new KeyParameter(key.getEncoded()); 201 } 202 else if (params instanceof IvParameterSpec) 203 { 204 param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV()); 205 ivParam = (ParametersWithIV)param; 206 } 207 else 208 { 209 throw new InvalidAlgorithmParameterException("unknown parameter type."); 210 } 211 212 if ((ivLength != 0) && !(param instanceof ParametersWithIV)) 213 { 214 SecureRandom ivRandom = random; 215 216 if (ivRandom == null) 217 { 218 ivRandom = new SecureRandom(); 219 } 220 221 if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE)) 222 { 223 byte[] iv = new byte[ivLength]; 224 225 ivRandom.nextBytes(iv); 226 param = new ParametersWithIV(param, iv); 227 ivParam = (ParametersWithIV)param; 228 } 229 else 230 { 231 throw new InvalidAlgorithmParameterException("no IV set when one expected"); 232 } 233 } 234 235 try 236 { 237 switch (opmode) 238 { 239 case Cipher.ENCRYPT_MODE: 240 case Cipher.WRAP_MODE: 241 cipher.init(true, param); 242 break; 243 case Cipher.DECRYPT_MODE: 244 case Cipher.UNWRAP_MODE: 245 cipher.init(false, param); 246 break; 247 default: 248 throw new InvalidParameterException("unknown opmode " + opmode + " passed"); 249 } 250 } 251 catch (Exception e) 252 { 253 throw new InvalidKeyException(e.getMessage()); 254 } 255 } 256 257 protected void engineInit( 258 int opmode, 259 Key key, 260 AlgorithmParameters params, 261 SecureRandom random) 262 throws InvalidKeyException, InvalidAlgorithmParameterException 263 { 264 AlgorithmParameterSpec paramSpec = null; 265 266 if (params != null) 267 { 268 for (int i = 0; i != availableSpecs.length; i++) 269 { 270 try 271 { 272 paramSpec = params.getParameterSpec(availableSpecs[i]); 273 break; 274 } 275 catch (Exception e) 276 { 277 continue; 278 } 279 } 280 281 if (paramSpec == null) 282 { 283 throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString()); 284 } 285 } 286 287 engineInit(opmode, key, paramSpec, random); 288 engineParams = params; 289 } 290 291 protected void engineInit( 292 int opmode, 293 Key key, 294 SecureRandom random) 295 throws InvalidKeyException 296 { 297 try 298 { 299 engineInit(opmode, key, (AlgorithmParameterSpec)null, random); 300 } 301 catch (InvalidAlgorithmParameterException e) 302 { 303 throw new InvalidKeyException(e.getMessage()); 304 } 305 } 306 307 protected byte[] engineUpdate( 308 byte[] input, 309 int inputOffset, 310 int inputLen) 311 { 312 byte[] out = new byte[inputLen]; 313 314 cipher.processBytes(input, inputOffset, inputLen, out, 0); 315 316 return out; 317 } 318 319 protected int engineUpdate( 320 byte[] input, 321 int inputOffset, 322 int inputLen, 323 byte[] output, 324 int outputOffset) 325 throws ShortBufferException 326 { 327 try 328 { 329 cipher.processBytes(input, inputOffset, inputLen, output, outputOffset); 330 331 return inputLen; 332 } 333 catch (DataLengthException e) 334 { 335 throw new ShortBufferException(e.getMessage()); 336 } 337 } 338 339 protected byte[] engineDoFinal( 340 byte[] input, 341 int inputOffset, 342 int inputLen) 343 { 344 if (inputLen != 0) 345 { 346 byte[] out = engineUpdate(input, inputOffset, inputLen); 347 348 cipher.reset(); 349 350 return out; 351 } 352 353 cipher.reset(); 354 355 return new byte[0]; 356 } 357 358 protected int engineDoFinal( 359 byte[] input, 360 int inputOffset, 361 int inputLen, 362 byte[] output, 363 int outputOffset) 364 { 365 if (inputLen != 0) 366 { 367 cipher.processBytes(input, inputOffset, inputLen, output, outputOffset); 368 } 369 370 cipher.reset(); 371 372 return inputLen; 373 } 374} 375