1 package org.bouncycastle.jce.provider; 2 3 import java.security.spec.AlgorithmParameterSpec; 4 5 import javax.crypto.spec.PBEParameterSpec; 6 7 import org.bouncycastle.crypto.CipherParameters; 8 import org.bouncycastle.crypto.Digest; 9 import org.bouncycastle.crypto.PBEParametersGenerator; 10 import org.bouncycastle.crypto.digests.MD5Digest; 11 // BEGIN android-removed 12 // import org.bouncycastle.crypto.digests.RIPEMD160Digest; 13 // END android-removed 14 import org.bouncycastle.crypto.digests.SHA1Digest; 15 import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; 16 import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator; 17 import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; 18 import org.bouncycastle.crypto.params.KeyParameter; 19 import org.bouncycastle.crypto.params.ParametersWithIV; 20 21 /** 22 * Generator for PBE derived keys and ivs as defined by PKCS 12 V1.0, 23 * with a bug affecting 180 bit plus keys - this class is only here to 24 * allow smooth migration of the version 0 keystore to version 1. Don't 25 * use it (it won't be staying around). 26 * <p> 27 * The document this implementation is based on can be found at 28 * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html> 29 * RSA's PKCS12 Page</a> 30 */ 31 class OldPKCS12ParametersGenerator 32 extends PBEParametersGenerator 33 { 34 public static final int KEY_MATERIAL = 1; 35 public static final int IV_MATERIAL = 2; 36 public static final int MAC_MATERIAL = 3; 37 38 private Digest digest; 39 40 private int u; 41 private int v; 42 43 /** 44 * Construct a PKCS 12 Parameters generator. This constructor will 45 * accept MD5, SHA1, and RIPEMD160. 46 * 47 * @param digest the digest to be used as the source of derived keys. 48 * @exception IllegalArgumentException if an unknown digest is passed in. 49 */ 50 public OldPKCS12ParametersGenerator( 51 Digest digest) 52 { 53 this.digest = digest; 54 if (digest instanceof MD5Digest) 55 { 56 u = 128 / 8; 57 v = 512 / 8; 58 } 59 else if (digest instanceof SHA1Digest) 60 { 61 u = 160 / 8; 62 v = 512 / 8; 63 } 64 // BEGIN android-removed 65 // else if (digest instanceof RIPEMD160Digest) 66 // { 67 // u = 160 / 8; 68 // v = 512 / 8; 69 // } 70 // END android-removed 71 else 72 { 73 throw new IllegalArgumentException("Digest " + digest.getAlgorithmName() + " unsupported"); 74 } 75 } 76 77 /** 78 * add a + b + 1, returning the result in a. The a value is treated 79 * as a BigInteger of length (b.length * 8) bits. The result is 80 * modulo 2^b.length in case of overflow. 81 */ 82 private void adjust( 83 byte[] a, 84 int aOff, 85 byte[] b) 86 { 87 int x = (b[b.length - 1] & 0xff) + (a[aOff + b.length - 1] & 0xff) + 1; 88 89 a[aOff + b.length - 1] = (byte)x; 90 x >>>= 8; 91 92 for (int i = b.length - 2; i >= 0; i--) 93 { 94 x += (b[i] & 0xff) + (a[aOff + i] & 0xff); 95 a[aOff + i] = (byte)x; 96 x >>>= 8; 97 } 98 } 99 100 /** 101 * generation of a derived key ala PKCS12 V1.0. 102 */ 103 private byte[] generateDerivedKey( 104 int idByte, 105 int n) 106 { 107 byte[] D = new byte[v]; 108 byte[] dKey = new byte[n]; 109 110 for (int i = 0; i != D.length; i++) 111 { 112 D[i] = (byte)idByte; 113 } 114 115 byte[] S; 116 117 if ((salt != null) && (salt.length != 0)) 118 { 119 S = new byte[v * ((salt.length + v - 1) / v)]; 120 121 for (int i = 0; i != S.length; i++) 122 { 123 S[i] = salt[i % salt.length]; 124 } 125 } 126 else 127 { 128 S = new byte[0]; 129 } 130 131 byte[] P; 132 133 if ((password != null) && (password.length != 0)) 134 { 135 P = new byte[v * ((password.length + v - 1) / v)]; 136 137 for (int i = 0; i != P.length; i++) 138 { 139 P[i] = password[i % password.length]; 140 } 141 } 142 else 143 { 144 P = new byte[0]; 145 } 146 147 byte[] I = new byte[S.length + P.length]; 148 149 System.arraycopy(S, 0, I, 0, S.length); 150 System.arraycopy(P, 0, I, S.length, P.length); 151 152 byte[] B = new byte[v]; 153 int c = (n + u - 1) / u; 154 155 for (int i = 1; i <= c; i++) 156 { 157 byte[] A = new byte[u]; 158 159 digest.update(D, 0, D.length); 160 digest.update(I, 0, I.length); 161 digest.doFinal(A, 0); 162 for (int j = 1; j != iterationCount; j++) 163 { 164 digest.update(A, 0, A.length); 165 digest.doFinal(A, 0); 166 } 167 168 for (int j = 0; j != B.length; j++) 169 { 170 B[i] = A[j % A.length]; 171 } 172 173 for (int j = 0; j != I.length / v; j++) 174 { 175 adjust(I, j * v, B); 176 } 177 178 if (i == c) 179 { 180 System.arraycopy(A, 0, dKey, (i - 1) * u, dKey.length - ((i - 1) * u)); 181 } 182 else 183 { 184 System.arraycopy(A, 0, dKey, (i - 1) * u, A.length); 185 } 186 } 187 188 return dKey; 189 } 190 191 /** 192 * Generate a key parameter derived from the password, salt, and iteration 193 * count we are currently initialised with. 194 * 195 * @param keySize the size of the key we want (in bits) 196 * @return a KeyParameter object. 197 */ 198 public CipherParameters generateDerivedParameters( 199 int keySize) 200 { 201 keySize = keySize / 8; 202 203 byte[] dKey = generateDerivedKey(KEY_MATERIAL, keySize); 204 205 return new KeyParameter(dKey, 0, keySize); 206 } 207 208 /** 209 * Generate a key with initialisation vector parameter derived from 210 * the password, salt, and iteration count we are currently initialised 211 * with. 212 * 213 * @param keySize the size of the key we want (in bits) 214 * @param ivSize the size of the iv we want (in bits) 215 * @return a ParametersWithIV object. 216 */ 217 public CipherParameters generateDerivedParameters( 218 int keySize, 219 int ivSize) 220 { 221 keySize = keySize / 8; 222 ivSize = ivSize / 8; 223 224 byte[] dKey = generateDerivedKey(KEY_MATERIAL, keySize); 225 226 byte[] iv = generateDerivedKey(IV_MATERIAL, ivSize); 227 228 return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize); 229 } 230 231 /** 232 * Generate a key parameter for use with a MAC derived from the password, 233 * salt, and iteration count we are currently initialised with. 234 * 235 * @param keySize the size of the key we want (in bits) 236 * @return a KeyParameter object. 237 */ 238 public CipherParameters generateDerivedMacParameters( 239 int keySize) 240 { 241 keySize = keySize / 8; 242 243 byte[] dKey = generateDerivedKey(MAC_MATERIAL, keySize); 244 245 return new KeyParameter(dKey, 0, keySize); 246 } 247 } 248 249 public interface BrokenPBE 250 { 251 // 252 // PBE Based encryption constants - by default we do PKCS12 with SHA-1 253 // 254 static final int MD5 = 0; 255 static final int SHA1 = 1; 256 static final int RIPEMD160 = 2; 257 258 static final int PKCS5S1 = 0; 259 static final int PKCS5S2 = 1; 260 static final int PKCS12 = 2; 261 static final int OLD_PKCS12 = 3; 262 263 /** 264 * uses the appropriate mixer to generate the key and IV if neccessary. 265 */ 266 static class Util 267 { 268 /** 269 * a faulty parity routine... 270 * 271 * @param bytes the byte array to set the parity on. 272 */ 273 static private void setOddParity( 274 byte[] bytes) 275 { 276 for (int i = 0; i < bytes.length; i++) 277 { 278 int b = bytes[i]; 279 bytes[i] = (byte)((b & 0xfe) | 280 (((b >> 1) ^ 281 (b >> 2) ^ 282 (b >> 3) ^ 283 (b >> 4) ^ 284 (b >> 5) ^ 285 (b >> 6) ^ 286 (b >> 7)) ^ 0x01)); 287 } 288 } 289 290 static private PBEParametersGenerator makePBEGenerator( 291 int type, 292 int hash) 293 { 294 PBEParametersGenerator generator; 295 296 if (type == PKCS5S1) 297 { 298 switch (hash) 299 { 300 case MD5: 301 generator = new PKCS5S1ParametersGenerator(new MD5Digest()); 302 break; 303 case SHA1: 304 generator = new PKCS5S1ParametersGenerator(new SHA1Digest()); 305 break; 306 default: 307 throw new IllegalStateException("PKCS5 scheme 1 only supports only MD5 and SHA1."); 308 } 309 } 310 else if (type == PKCS5S2) 311 { 312 generator = new PKCS5S2ParametersGenerator(); 313 } 314 else if (type == OLD_PKCS12) 315 { 316 switch (hash) 317 { 318 case MD5: 319 generator = new OldPKCS12ParametersGenerator(new MD5Digest()); 320 break; 321 case SHA1: 322 generator = new OldPKCS12ParametersGenerator(new SHA1Digest()); 323 break; 324 // BEGIN android-removed 325 // case RIPEMD160: 326 // generator = new OldPKCS12ParametersGenerator(new RIPEMD160Digest()); 327 // break; 328 // END android-removed 329 default: 330 throw new IllegalStateException("unknown digest scheme for PBE encryption."); 331 } 332 } 333 else 334 { 335 switch (hash) 336 { 337 case MD5: 338 generator = new PKCS12ParametersGenerator(new MD5Digest()); 339 break; 340 case SHA1: 341 generator = new PKCS12ParametersGenerator(new SHA1Digest()); 342 break; 343 // BEGIN android-removed 344 // case RIPEMD160: 345 // generator = new PKCS12ParametersGenerator(new RIPEMD160Digest()); 346 // break; 347 // END android-removed 348 default: 349 throw new IllegalStateException("unknown digest scheme for PBE encryption."); 350 } 351 } 352 353 return generator; 354 } 355 356 /** 357 * construct a key and iv (if neccessary) suitable for use with a 358 * Cipher. 359 */ 360 static CipherParameters makePBEParameters( 361 JCEPBEKey pbeKey, 362 AlgorithmParameterSpec spec, 363 int type, 364 int hash, 365 String targetAlgorithm, 366 int keySize, 367 int ivSize) 368 { 369 if ((spec == null) || !(spec instanceof PBEParameterSpec)) 370 { 371 throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key."); 372 } 373 374 PBEParameterSpec pbeParam = (PBEParameterSpec)spec; 375 PBEParametersGenerator generator = makePBEGenerator(type, hash); 376 byte[] key = pbeKey.getEncoded(); 377 CipherParameters param; 378 379 generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount()); 380 381 if (ivSize != 0) 382 { 383 param = generator.generateDerivedParameters(keySize, ivSize); 384 } 385 else 386 { 387 param = generator.generateDerivedParameters(keySize); 388 } 389 390 if (targetAlgorithm.startsWith("DES")) 391 { 392 if (param instanceof ParametersWithIV) 393 { 394 KeyParameter kParam = (KeyParameter)((ParametersWithIV)param).getParameters(); 395 396 setOddParity(kParam.getKey()); 397 } 398 else 399 { 400 KeyParameter kParam = (KeyParameter)param; 401 402 setOddParity(kParam.getKey()); 403 } 404 } 405 406 for (int i = 0; i != key.length; i++) 407 { 408 key[i] = 0; 409 } 410 411 return param; 412 } 413 414 /** 415 * generate a PBE based key suitable for a MAC algorithm, the 416 * key size is chosen according the MAC size, or the hashing algorithm, 417 * whichever is greater. 418 */ 419 static CipherParameters makePBEMacParameters( 420 JCEPBEKey pbeKey, 421 AlgorithmParameterSpec spec, 422 int type, 423 int hash, 424 int keySize) 425 { 426 if ((spec == null) || !(spec instanceof PBEParameterSpec)) 427 { 428 throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key."); 429 } 430 431 PBEParameterSpec pbeParam = (PBEParameterSpec)spec; 432 PBEParametersGenerator generator = makePBEGenerator(type, hash); 433 byte[] key = pbeKey.getEncoded(); 434 CipherParameters param; 435 436 generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount()); 437 438 param = generator.generateDerivedMacParameters(keySize); 439 440 for (int i = 0; i != key.length; i++) 441 { 442 key[i] = 0; 443 } 444 445 return param; 446 } 447 } 448 } 449