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