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