1package org.bouncycastle.jcajce.provider.symmetric.util; 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.ShortBufferException; 23import javax.crypto.spec.IvParameterSpec; 24import javax.crypto.spec.PBEParameterSpec; 25// Android-removed: Unsupported algorithms 26// import javax.crypto.spec.RC2ParameterSpec; 27// import javax.crypto.spec.RC5ParameterSpec; 28import javax.crypto.spec.SecretKeySpec; 29 30import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; 31import org.bouncycastle.crypto.CipherParameters; 32import org.bouncycastle.crypto.InvalidCipherTextException; 33import org.bouncycastle.crypto.Wrapper; 34import org.bouncycastle.crypto.params.KeyParameter; 35import org.bouncycastle.crypto.params.ParametersWithIV; 36import org.bouncycastle.crypto.params.ParametersWithRandom; 37// Android-changed: Use default provider for JCA algorithms instead of BC 38// Was: import org.bouncycastle.jcajce.util.BCJcaJceHelper; 39import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; 40import org.bouncycastle.jcajce.util.JcaJceHelper; 41import org.bouncycastle.jce.provider.BouncyCastleProvider; 42import org.bouncycastle.util.Arrays; 43 44public abstract class BaseWrapCipher 45 extends CipherSpi 46 implements PBE 47{ 48 // 49 // specs we can handle. 50 // 51 private Class[] availableSpecs = 52 { 53 IvParameterSpec.class, 54 PBEParameterSpec.class, 55 // Android-removed: Unsupported algorithms 56 // RC2ParameterSpec.class, 57 // RC5ParameterSpec.class 58 }; 59 60 protected int pbeType = PKCS12; 61 protected int pbeHash = SHA1; 62 protected int pbeKeySize; 63 protected int pbeIvSize; 64 65 protected AlgorithmParameters engineParams = null; 66 67 protected Wrapper wrapEngine = null; 68 69 private int ivSize; 70 private byte[] iv; 71 72 // Android-changed: Use default provider for JCA algorithms instead of BC 73 // Was: private final JcaJceHelper helper = new BCJcaJceHelper(); 74 private final JcaJceHelper helper = new DefaultJcaJceHelper(); 75 76 protected BaseWrapCipher() 77 { 78 } 79 80 protected BaseWrapCipher( 81 Wrapper wrapEngine) 82 { 83 this(wrapEngine, 0); 84 } 85 86 protected BaseWrapCipher( 87 Wrapper wrapEngine, 88 int ivSize) 89 { 90 this.wrapEngine = wrapEngine; 91 this.ivSize = ivSize; 92 } 93 94 protected int engineGetBlockSize() 95 { 96 return 0; 97 } 98 99 protected byte[] engineGetIV() 100 { 101 return Arrays.clone(iv); 102 } 103 104 protected int engineGetKeySize( 105 Key key) 106 { 107 return key.getEncoded().length * 8; 108 } 109 110 protected int engineGetOutputSize( 111 int inputLen) 112 { 113 return -1; 114 } 115 116 protected AlgorithmParameters engineGetParameters() 117 { 118 return null; 119 } 120 121 protected final AlgorithmParameters createParametersInstance(String algorithm) 122 throws NoSuchAlgorithmException, NoSuchProviderException 123 { 124 return helper.createAlgorithmParameters(algorithm); 125 } 126 127 protected void engineSetMode( 128 String mode) 129 throws NoSuchAlgorithmException 130 { 131 throw new NoSuchAlgorithmException("can't support mode " + mode); 132 } 133 134 protected void engineSetPadding( 135 String padding) 136 throws NoSuchPaddingException 137 { 138 throw new NoSuchPaddingException("Padding " + padding + " unknown."); 139 } 140 141 protected void engineInit( 142 int opmode, 143 Key key, 144 AlgorithmParameterSpec params, 145 SecureRandom random) 146 throws InvalidKeyException, InvalidAlgorithmParameterException 147 { 148 CipherParameters param; 149 150 if (key instanceof BCPBEKey) 151 { 152 BCPBEKey k = (BCPBEKey)key; 153 154 if (params instanceof PBEParameterSpec) 155 { 156 param = PBE.Util.makePBEParameters(k, params, wrapEngine.getAlgorithmName()); 157 } 158 else if (k.getParam() != null) 159 { 160 param = k.getParam(); 161 } 162 else 163 { 164 throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set."); 165 } 166 } 167 else 168 { 169 param = new KeyParameter(key.getEncoded()); 170 } 171 172 if (params instanceof IvParameterSpec) 173 { 174 IvParameterSpec iv = (IvParameterSpec) params; 175 param = new ParametersWithIV(param, iv.getIV()); 176 } 177 178 if (param instanceof KeyParameter && ivSize != 0) 179 { 180 iv = new byte[ivSize]; 181 random.nextBytes(iv); 182 param = new ParametersWithIV(param, iv); 183 } 184 185 if (random != null) 186 { 187 param = new ParametersWithRandom(param, random); 188 } 189 190 switch (opmode) 191 { 192 case Cipher.WRAP_MODE: 193 wrapEngine.init(true, param); 194 break; 195 case Cipher.UNWRAP_MODE: 196 wrapEngine.init(false, param); 197 break; 198 case Cipher.ENCRYPT_MODE: 199 case Cipher.DECRYPT_MODE: 200 throw new IllegalArgumentException("engine only valid for wrapping"); 201 default: 202 System.out.println("eeek!"); 203 } 204 } 205 206 protected void engineInit( 207 int opmode, 208 Key key, 209 AlgorithmParameters params, 210 SecureRandom random) 211 throws InvalidKeyException, InvalidAlgorithmParameterException 212 { 213 AlgorithmParameterSpec paramSpec = null; 214 215 if (params != null) 216 { 217 for (int i = 0; i != availableSpecs.length; i++) 218 { 219 try 220 { 221 paramSpec = params.getParameterSpec(availableSpecs[i]); 222 break; 223 } 224 catch (Exception e) 225 { 226 // try next spec 227 } 228 } 229 230 if (paramSpec == null) 231 { 232 throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString()); 233 } 234 } 235 236 engineParams = params; 237 engineInit(opmode, key, paramSpec, random); 238 } 239 240 protected void engineInit( 241 int opmode, 242 Key key, 243 SecureRandom random) 244 throws InvalidKeyException 245 { 246 try 247 { 248 engineInit(opmode, key, (AlgorithmParameterSpec)null, random); 249 } 250 catch (InvalidAlgorithmParameterException e) 251 { 252 throw new IllegalArgumentException(e.getMessage()); 253 } 254 } 255 256 protected byte[] engineUpdate( 257 byte[] input, 258 int inputOffset, 259 int inputLen) 260 { 261 throw new RuntimeException("not supported for wrapping"); 262 } 263 264 protected int engineUpdate( 265 byte[] input, 266 int inputOffset, 267 int inputLen, 268 byte[] output, 269 int outputOffset) 270 throws ShortBufferException 271 { 272 throw new RuntimeException("not supported for wrapping"); 273 } 274 275 protected byte[] engineDoFinal( 276 byte[] input, 277 int inputOffset, 278 int inputLen) 279 throws IllegalBlockSizeException, BadPaddingException 280 { 281 return null; 282 } 283 284 protected int engineDoFinal( 285 byte[] input, 286 int inputOffset, 287 int inputLen, 288 byte[] output, 289 int outputOffset) 290 throws IllegalBlockSizeException, BadPaddingException, ShortBufferException 291 { 292 return 0; 293 } 294 295 protected byte[] engineWrap( 296 Key key) 297 throws IllegalBlockSizeException, InvalidKeyException 298 { 299 byte[] encoded = key.getEncoded(); 300 if (encoded == null) 301 { 302 throw new InvalidKeyException("Cannot wrap key, null encoding."); 303 } 304 305 try 306 { 307 if (wrapEngine == null) 308 { 309 return engineDoFinal(encoded, 0, encoded.length); 310 } 311 else 312 { 313 return wrapEngine.wrap(encoded, 0, encoded.length); 314 } 315 } 316 catch (BadPaddingException e) 317 { 318 throw new IllegalBlockSizeException(e.getMessage()); 319 } 320 } 321 322 protected Key engineUnwrap( 323 byte[] wrappedKey, 324 String wrappedKeyAlgorithm, 325 int wrappedKeyType) 326 throws InvalidKeyException, NoSuchAlgorithmException 327 { 328 byte[] encoded; 329 try 330 { 331 if (wrapEngine == null) 332 { 333 encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length); 334 } 335 else 336 { 337 encoded = wrapEngine.unwrap(wrappedKey, 0, wrappedKey.length); 338 } 339 } 340 catch (InvalidCipherTextException e) 341 { 342 throw new InvalidKeyException(e.getMessage()); 343 } 344 catch (BadPaddingException e) 345 { 346 throw new InvalidKeyException(e.getMessage()); 347 } 348 catch (IllegalBlockSizeException e2) 349 { 350 throw new InvalidKeyException(e2.getMessage()); 351 } 352 353 if (wrappedKeyType == Cipher.SECRET_KEY) 354 { 355 return new SecretKeySpec(encoded, wrappedKeyAlgorithm); 356 } 357 else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY) 358 { 359 /* 360 * The caller doesn't know the algorithm as it is part of 361 * the encrypted data. 362 */ 363 try 364 { 365 PrivateKeyInfo in = PrivateKeyInfo.getInstance(encoded); 366 367 PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in); 368 369 if (privKey != null) 370 { 371 return privKey; 372 } 373 else 374 { 375 throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported"); 376 } 377 } 378 catch (Exception e) 379 { 380 throw new InvalidKeyException("Invalid key encoding."); 381 } 382 } 383 else 384 { 385 try 386 { 387 KeyFactory kf = helper.createKeyFactory(wrappedKeyAlgorithm); 388 389 if (wrappedKeyType == Cipher.PUBLIC_KEY) 390 { 391 return kf.generatePublic(new X509EncodedKeySpec(encoded)); 392 } 393 else if (wrappedKeyType == Cipher.PRIVATE_KEY) 394 { 395 return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded)); 396 } 397 } 398 catch (NoSuchProviderException e) 399 { 400 throw new InvalidKeyException("Unknown key type " + e.getMessage()); 401 } 402 catch (InvalidKeySpecException e2) 403 { 404 throw new InvalidKeyException("Unknown key type " + e2.getMessage()); 405 } 406 407 throw new InvalidKeyException("Unknown key type " + wrappedKeyType); 408 } 409 } 410 411} 412