1 package org.bouncycastle.jcajce.provider.symmetric.util; 2 3 // BEGIN Android-added: Needed for compatibility helper 4 import java.lang.reflect.Method; 5 // END Android-added: Needed for compatibility helper 6 import java.security.InvalidAlgorithmParameterException; 7 import java.security.spec.AlgorithmParameterSpec; 8 9 import javax.crypto.SecretKey; 10 // BEGIN Android-added: Allow IVs specified in parameters. 11 import javax.crypto.spec.IvParameterSpec; 12 // END Android-added: Allow IVs specified in parameters. 13 import javax.crypto.spec.PBEKeySpec; 14 import javax.crypto.spec.PBEParameterSpec; 15 16 import org.bouncycastle.crypto.CipherParameters; 17 import org.bouncycastle.crypto.PBEParametersGenerator; 18 // Android-removed: Unsupported algorithms 19 // import org.bouncycastle.crypto.digests.GOST3411Digest; 20 // import org.bouncycastle.crypto.digests.MD2Digest; 21 // import org.bouncycastle.crypto.digests.RIPEMD160Digest; 22 // import org.bouncycastle.crypto.digests.TigerDigest; 23 import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator; 24 import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; 25 import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator; 26 import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; 27 import org.bouncycastle.crypto.params.DESParameters; 28 import org.bouncycastle.crypto.params.KeyParameter; 29 import org.bouncycastle.crypto.params.ParametersWithIV; 30 // BEGIN Android-changed: Use Android digests 31 // import org.bouncycastle.crypto.util.DigestFactory; 32 import org.bouncycastle.crypto.digests.AndroidDigestFactory; 33 // END Android-changed: Use Android digests 34 35 public interface PBE 36 { 37 // 38 // PBE Based encryption constants - by default we do PKCS12 with SHA-1 39 // 40 static final int MD5 = 0; 41 static final int SHA1 = 1; 42 // Android-removed: Unsupported algorithms 43 // static final int RIPEMD160 = 2; 44 // static final int TIGER = 3; 45 static final int SHA256 = 4; 46 // Android-removed: Unsupported algorithms 47 // static final int MD2 = 5; 48 // static final int GOST3411 = 6; 49 static final int SHA224 = 7; 50 static final int SHA384 = 8; 51 static final int SHA512 = 9; 52 53 static final int PKCS5S1 = 0; 54 static final int PKCS5S2 = 1; 55 static final int PKCS12 = 2; 56 static final int OPENSSL = 3; 57 static final int PKCS5S1_UTF8 = 4; 58 static final int PKCS5S2_UTF8 = 5; 59 60 /** 61 * uses the appropriate mixer to generate the key and IV if necessary. 62 */ 63 static class Util 64 { makePBEGenerator( int type, int hash)65 static private PBEParametersGenerator makePBEGenerator( 66 int type, 67 int hash) 68 { 69 PBEParametersGenerator generator; 70 71 if (type == PKCS5S1 || type == PKCS5S1_UTF8) 72 { 73 switch (hash) 74 { 75 // Android-removed: Unsupported algorithms 76 // case MD2: 77 // generator = new PKCS5S1ParametersGenerator(new MD2Digest()); 78 // break; 79 case MD5: 80 // Android-changed: Use Android digests 81 // generator = new PKCS5S1ParametersGenerator(DigestFactory.createMD5()); 82 generator = new PKCS5S1ParametersGenerator(AndroidDigestFactory.getMD5()); 83 break; 84 case SHA1: 85 // Android-changed: Use Android digests 86 // generator = new PKCS5S1ParametersGenerator(DigestFactory.createSHA1()); 87 generator = new PKCS5S1ParametersGenerator(AndroidDigestFactory.getSHA1()); 88 break; 89 default: 90 throw new IllegalStateException("PKCS5 scheme 1 only supports MD2, MD5 and SHA1."); 91 } 92 } 93 else if (type == PKCS5S2 || type == PKCS5S2_UTF8) 94 { 95 switch (hash) 96 { 97 // Android-removed: Unsupported algorithms 98 // case MD2: 99 // generator = new PKCS5S2ParametersGenerator(new MD2Digest()); 100 // break; 101 case MD5: 102 // Android-changed: Use Android digests 103 // generator = new PKCS5S2ParametersGenerator(DigestFactory.createMD5()); 104 generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getMD5()); 105 break; 106 case SHA1: 107 // Android-changed: Use Android digests 108 // generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA1()); 109 generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA1()); 110 break; 111 // BEGIN Android-removed: Unsupported algorithms 112 /* 113 case RIPEMD160: 114 generator = new PKCS5S2ParametersGenerator(new RIPEMD160Digest()); 115 break; 116 case TIGER: 117 generator = new PKCS5S2ParametersGenerator(new TigerDigest()); 118 break; 119 */ 120 // END Android-removed: Unsupported algorithms 121 case SHA256: 122 // Android-changed: Use Android digests 123 // generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA256()); 124 generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA256()); 125 break; 126 // Android-removed: Unsupported algorithms 127 // case GOST3411: 128 // generator = new PKCS5S2ParametersGenerator(new GOST3411Digest()); 129 // break; 130 case SHA224: 131 // Android-changed: Use Android digests 132 // generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA224()); 133 generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA224()); 134 break; 135 case SHA384: 136 // Android-changed: Use Android digests 137 // generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA384()); 138 generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA384()); 139 break; 140 case SHA512: 141 // Android-changed: Use Android digests 142 // generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA512()); 143 generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA512()); 144 break; 145 default: 146 throw new IllegalStateException("unknown digest scheme for PBE PKCS5S2 encryption."); 147 } 148 } 149 else if (type == PKCS12) 150 { 151 switch (hash) 152 { 153 // Android-removed: Unsupported algorithms 154 // case MD2: 155 // generator = new PKCS12ParametersGenerator(new MD2Digest()); 156 // break; 157 case MD5: 158 // Android-changed: Use Android digests 159 // generator = new PKCS12ParametersGenerator(DigestFactory.createMD5()); 160 generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getMD5()); 161 break; 162 case SHA1: 163 // Android-changed: Use Android digests 164 // generator = new PKCS12ParametersGenerator(DigestFactory.createSHA1()); 165 generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA1()); 166 break; 167 // BEGIN Android-removed: Unsupported algorithms 168 /* 169 case RIPEMD160: 170 generator = new PKCS12ParametersGenerator(new RIPEMD160Digest()); 171 break; 172 case TIGER: 173 generator = new PKCS12ParametersGenerator(new TigerDigest()); 174 break; 175 */ 176 // END Android-removed: Unsupported algorithms 177 case SHA256: 178 // Android-changed: Use Android digests 179 // generator = new PKCS12ParametersGenerator(DigestFactory.createSHA256()); 180 generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA256()); 181 break; 182 // Android-removed: Unsupported algorithms 183 // case GOST3411: 184 // generator = new PKCS12ParametersGenerator(new GOST3411Digest()); 185 // break; 186 case SHA224: 187 // Android-changed: Use Android digests 188 // generator = new PKCS12ParametersGenerator(DigestFactory.createSHA224()); 189 generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA224()); 190 break; 191 case SHA384: 192 // Android-changed: Use Android digests 193 // generator = new PKCS12ParametersGenerator(DigestFactory.createSHA384()); 194 generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA384()); 195 break; 196 case SHA512: 197 // Android-changed: Use Android digests 198 // generator = new PKCS12ParametersGenerator(DigestFactory.createSHA512()); 199 generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA512()); 200 break; 201 default: 202 throw new IllegalStateException("unknown digest scheme for PBE encryption."); 203 } 204 } 205 else 206 { 207 generator = new OpenSSLPBEParametersGenerator(); 208 } 209 210 return generator; 211 } 212 213 /** 214 * construct a key and iv (if necessary) suitable for use with a 215 * Cipher. 216 */ makePBEParameters( byte[] pbeKey, int scheme, int digest, int keySize, int ivSize, AlgorithmParameterSpec spec, String targetAlgorithm)217 public static CipherParameters makePBEParameters( 218 byte[] pbeKey, 219 int scheme, 220 int digest, 221 int keySize, 222 int ivSize, 223 AlgorithmParameterSpec spec, 224 String targetAlgorithm) 225 throws InvalidAlgorithmParameterException 226 { 227 if ((spec == null) || !(spec instanceof PBEParameterSpec)) 228 { 229 throw new InvalidAlgorithmParameterException("Need a PBEParameter spec with a PBE key."); 230 } 231 232 PBEParameterSpec pbeParam = (PBEParameterSpec)spec; 233 PBEParametersGenerator generator = makePBEGenerator(scheme, digest); 234 byte[] key = pbeKey; 235 CipherParameters param; 236 237 // if (pbeKey.shouldTryWrongPKCS12()) 238 // { 239 // key = new byte[2]; 240 // } 241 242 generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount()); 243 244 if (ivSize != 0) 245 { 246 param = generator.generateDerivedParameters(keySize, ivSize); 247 // BEGIN Android-added: Allow IVs specified in parameters. 248 // PKCS5S2 doesn't specify that the IV must be generated from the password. If the 249 // IV is passed as a parameter, use it. 250 AlgorithmParameterSpec parameterSpecFromPBEParameterSpec = 251 getParameterSpecFromPBEParameterSpec(pbeParam); 252 if ((scheme == PKCS5S2 || scheme == PKCS5S2_UTF8) 253 && parameterSpecFromPBEParameterSpec instanceof IvParameterSpec) { 254 ParametersWithIV parametersWithIV = (ParametersWithIV) param; 255 IvParameterSpec ivParameterSpec = 256 (IvParameterSpec) parameterSpecFromPBEParameterSpec; 257 param = new ParametersWithIV( 258 (KeyParameter) parametersWithIV.getParameters(), 259 ivParameterSpec.getIV()); 260 } 261 // END Android-added: Allow IVs specified in parameters. 262 } 263 else 264 { 265 param = generator.generateDerivedParameters(keySize); 266 } 267 268 if (targetAlgorithm.startsWith("DES")) 269 { 270 if (param instanceof ParametersWithIV) 271 { 272 KeyParameter kParam = (KeyParameter)((ParametersWithIV)param).getParameters(); 273 274 DESParameters.setOddParity(kParam.getKey()); 275 } 276 else 277 { 278 KeyParameter kParam = (KeyParameter)param; 279 280 DESParameters.setOddParity(kParam.getKey()); 281 } 282 } 283 284 return param; 285 } 286 287 /** 288 * construct a key and iv (if necessary) suitable for use with a 289 * Cipher. 290 */ makePBEParameters( BCPBEKey pbeKey, AlgorithmParameterSpec spec, String targetAlgorithm)291 public static CipherParameters makePBEParameters( 292 BCPBEKey pbeKey, 293 AlgorithmParameterSpec spec, 294 String targetAlgorithm) 295 { 296 if ((spec == null) || !(spec instanceof PBEParameterSpec)) 297 { 298 throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key."); 299 } 300 301 PBEParameterSpec pbeParam = (PBEParameterSpec)spec; 302 PBEParametersGenerator generator = makePBEGenerator(pbeKey.getType(), pbeKey.getDigest()); 303 byte[] key = pbeKey.getEncoded(); 304 CipherParameters param; 305 306 if (pbeKey.shouldTryWrongPKCS12()) 307 { 308 key = new byte[2]; 309 } 310 311 generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount()); 312 313 if (pbeKey.getIvSize() != 0) 314 { 315 param = generator.generateDerivedParameters(pbeKey.getKeySize(), pbeKey.getIvSize()); 316 // BEGIN Android-added: Allow IVs specified in parameters. 317 // PKCS5S2 doesn't specify that the IV must be generated from the password. If the 318 // IV is passed as a parameter, use it. 319 AlgorithmParameterSpec parameterSpecFromPBEParameterSpec = 320 getParameterSpecFromPBEParameterSpec(pbeParam); 321 if ((pbeKey.getType() == PKCS5S2 || pbeKey.getType() == PKCS5S2_UTF8) 322 && parameterSpecFromPBEParameterSpec instanceof IvParameterSpec) { 323 ParametersWithIV parametersWithIV = (ParametersWithIV) param; 324 IvParameterSpec ivParameterSpec = 325 (IvParameterSpec) parameterSpecFromPBEParameterSpec; 326 param = new ParametersWithIV( 327 (KeyParameter) parametersWithIV.getParameters(), 328 ivParameterSpec.getIV()); 329 } 330 // END Android-added: Allow IVs specified in parameters. 331 } 332 else 333 { 334 param = generator.generateDerivedParameters(pbeKey.getKeySize()); 335 } 336 337 if (targetAlgorithm.startsWith("DES")) 338 { 339 if (param instanceof ParametersWithIV) 340 { 341 KeyParameter kParam = (KeyParameter)((ParametersWithIV)param).getParameters(); 342 343 DESParameters.setOddParity(kParam.getKey()); 344 } 345 else 346 { 347 KeyParameter kParam = (KeyParameter)param; 348 349 DESParameters.setOddParity(kParam.getKey()); 350 } 351 } 352 353 return param; 354 } 355 356 /** 357 * generate a PBE based key suitable for a MAC algorithm, the 358 * key size is chosen according the MAC size, or the hashing algorithm, 359 * whichever is greater. 360 */ makePBEMacParameters( BCPBEKey pbeKey, AlgorithmParameterSpec spec)361 public static CipherParameters makePBEMacParameters( 362 BCPBEKey pbeKey, 363 AlgorithmParameterSpec spec) 364 { 365 if ((spec == null) || !(spec instanceof PBEParameterSpec)) 366 { 367 throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key."); 368 } 369 370 PBEParameterSpec pbeParam = (PBEParameterSpec)spec; 371 PBEParametersGenerator generator = makePBEGenerator(pbeKey.getType(), pbeKey.getDigest()); 372 byte[] key = pbeKey.getEncoded(); 373 CipherParameters param; 374 375 generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount()); 376 377 param = generator.generateDerivedMacParameters(pbeKey.getKeySize()); 378 379 return param; 380 } 381 382 /** 383 * generate a PBE based key suitable for a MAC algorithm, the 384 * key size is chosen according the MAC size, or the hashing algorithm, 385 * whichever is greater. 386 */ makePBEMacParameters( PBEKeySpec keySpec, int type, int hash, int keySize)387 public static CipherParameters makePBEMacParameters( 388 PBEKeySpec keySpec, 389 int type, 390 int hash, 391 int keySize) 392 { 393 PBEParametersGenerator generator = makePBEGenerator(type, hash); 394 byte[] key; 395 CipherParameters param; 396 397 key = convertPassword(type, keySpec); 398 399 generator.init(key, keySpec.getSalt(), keySpec.getIterationCount()); 400 401 param = generator.generateDerivedMacParameters(keySize); 402 403 for (int i = 0; i != key.length; i++) 404 { 405 key[i] = 0; 406 } 407 408 return param; 409 } 410 411 /** 412 * construct a key and iv (if necessary) suitable for use with a 413 * Cipher. 414 */ makePBEParameters( PBEKeySpec keySpec, int type, int hash, int keySize, int ivSize)415 public static CipherParameters makePBEParameters( 416 PBEKeySpec keySpec, 417 int type, 418 int hash, 419 int keySize, 420 int ivSize) 421 { 422 PBEParametersGenerator generator = makePBEGenerator(type, hash); 423 byte[] key; 424 CipherParameters param; 425 426 key = convertPassword(type, keySpec); 427 428 generator.init(key, keySpec.getSalt(), keySpec.getIterationCount()); 429 430 if (ivSize != 0) 431 { 432 param = generator.generateDerivedParameters(keySize, ivSize); 433 } 434 else 435 { 436 param = generator.generateDerivedParameters(keySize); 437 } 438 439 for (int i = 0; i != key.length; i++) 440 { 441 key[i] = 0; 442 } 443 444 return param; 445 } 446 447 /** 448 * generate a PBE based key suitable for a MAC algorithm, the 449 * key size is chosen according the MAC size, or the hashing algorithm, 450 * whichever is greater. 451 */ makePBEMacParameters( SecretKey key, int type, int hash, int keySize, PBEParameterSpec pbeSpec)452 public static CipherParameters makePBEMacParameters( 453 SecretKey key, 454 int type, 455 int hash, 456 int keySize, 457 PBEParameterSpec pbeSpec) 458 { 459 PBEParametersGenerator generator = makePBEGenerator(type, hash); 460 CipherParameters param; 461 462 byte[] keyBytes = key.getEncoded(); 463 464 generator.init(key.getEncoded(), pbeSpec.getSalt(), pbeSpec.getIterationCount()); 465 466 param = generator.generateDerivedMacParameters(keySize); 467 468 for (int i = 0; i != keyBytes.length; i++) 469 { 470 keyBytes[i] = 0; 471 } 472 473 return param; 474 } 475 476 // BEGIN Android-added: Add helper for 1.8 compatibility. 477 /** 478 * Invokes the method {@link PBEParameterSpec#getParameterSpec()} via reflection. 479 * 480 * Needed as the method was introduced in Java 1.8 and Bouncycastle level is 1.5. 481 * 482 * @return the parameter spec, or null if the method is not available. 483 */ getParameterSpecFromPBEParameterSpec( PBEParameterSpec pbeParameterSpec)484 public static AlgorithmParameterSpec getParameterSpecFromPBEParameterSpec( 485 PBEParameterSpec pbeParameterSpec) { 486 try { 487 Method getParameterSpecMethod = PBE.class.getClassLoader() 488 .loadClass("javax.crypto.spec.PBEParameterSpec") 489 .getMethod("getParameterSpec"); 490 return (AlgorithmParameterSpec) getParameterSpecMethod.invoke(pbeParameterSpec); 491 } catch (Exception e) { 492 return null; 493 } 494 } 495 // END Android-added: Add helper for 1.8 compatibility. 496 497 convertPassword(int type, PBEKeySpec keySpec)498 private static byte[] convertPassword(int type, PBEKeySpec keySpec) 499 { 500 byte[] key; 501 502 if (type == PKCS12) 503 { 504 key = PBEParametersGenerator.PKCS12PasswordToBytes(keySpec.getPassword()); 505 } 506 else if (type == PKCS5S2_UTF8 || type == PKCS5S1_UTF8) 507 { 508 key = PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(keySpec.getPassword()); 509 } 510 else 511 { 512 key = PBEParametersGenerator.PKCS5PasswordToBytes(keySpec.getPassword()); 513 } 514 return key; 515 } 516 } 517 } 518