001: package org.bouncycastle.jce.provider;
002:
003: import java.security.spec.AlgorithmParameterSpec;
004:
005: import javax.crypto.spec.PBEParameterSpec;
006:
007: import org.bouncycastle.crypto.CipherParameters;
008: import org.bouncycastle.crypto.Digest;
009: import org.bouncycastle.crypto.PBEParametersGenerator;
010: import org.bouncycastle.crypto.digests.MD5Digest;
011: import org.bouncycastle.crypto.digests.RIPEMD160Digest;
012: import org.bouncycastle.crypto.digests.SHA1Digest;
013: import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
014: import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator;
015: import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
016: import org.bouncycastle.crypto.params.KeyParameter;
017: import org.bouncycastle.crypto.params.ParametersWithIV;
018:
019: /**
020: * Generator for PBE derived keys and ivs as defined by PKCS 12 V1.0,
021: * with a bug affecting 180 bit plus keys - this class is only here to
022: * allow smooth migration of the version 0 keystore to version 1. Don't
023: * use it (it won't be staying around).
024: * <p>
025: * The document this implementation is based on can be found at
026: * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html>
027: * RSA's PKCS12 Page</a>
028: */
029: class OldPKCS12ParametersGenerator extends PBEParametersGenerator {
030: public static final int KEY_MATERIAL = 1;
031: public static final int IV_MATERIAL = 2;
032: public static final int MAC_MATERIAL = 3;
033:
034: private Digest digest;
035:
036: private int u;
037: private int v;
038:
039: /**
040: * Construct a PKCS 12 Parameters generator. This constructor will
041: * accept MD5, SHA1, and RIPEMD160.
042: *
043: * @param digest the digest to be used as the source of derived keys.
044: * @exception IllegalArgumentException if an unknown digest is passed in.
045: */
046: public OldPKCS12ParametersGenerator(Digest digest) {
047: this .digest = digest;
048: if (digest instanceof MD5Digest) {
049: u = 128 / 8;
050: v = 512 / 8;
051: } else if (digest instanceof SHA1Digest) {
052: u = 160 / 8;
053: v = 512 / 8;
054: } else if (digest instanceof RIPEMD160Digest) {
055: u = 160 / 8;
056: v = 512 / 8;
057: } else {
058: throw new IllegalArgumentException("Digest "
059: + digest.getAlgorithmName() + " unsupported");
060: }
061: }
062:
063: /**
064: * add a + b + 1, returning the result in a. The a value is treated
065: * as a BigInteger of length (b.length * 8) bits. The result is
066: * modulo 2^b.length in case of overflow.
067: */
068: private void adjust(byte[] a, int aOff, byte[] b) {
069: int x = (b[b.length - 1] & 0xff)
070: + (a[aOff + b.length - 1] & 0xff) + 1;
071:
072: a[aOff + b.length - 1] = (byte) x;
073: x >>>= 8;
074:
075: for (int i = b.length - 2; i >= 0; i--) {
076: x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
077: a[aOff + i] = (byte) x;
078: x >>>= 8;
079: }
080: }
081:
082: /**
083: * generation of a derived key ala PKCS12 V1.0.
084: */
085: private byte[] generateDerivedKey(int idByte, int n) {
086: byte[] D = new byte[v];
087: byte[] dKey = new byte[n];
088:
089: for (int i = 0; i != D.length; i++) {
090: D[i] = (byte) idByte;
091: }
092:
093: byte[] S;
094:
095: if ((salt != null) && (salt.length != 0)) {
096: S = new byte[v * ((salt.length + v - 1) / v)];
097:
098: for (int i = 0; i != S.length; i++) {
099: S[i] = salt[i % salt.length];
100: }
101: } else {
102: S = new byte[0];
103: }
104:
105: byte[] P;
106:
107: if ((password != null) && (password.length != 0)) {
108: P = new byte[v * ((password.length + v - 1) / v)];
109:
110: for (int i = 0; i != P.length; i++) {
111: P[i] = password[i % password.length];
112: }
113: } else {
114: P = new byte[0];
115: }
116:
117: byte[] I = new byte[S.length + P.length];
118:
119: System.arraycopy(S, 0, I, 0, S.length);
120: System.arraycopy(P, 0, I, S.length, P.length);
121:
122: byte[] B = new byte[v];
123: int c = (n + u - 1) / u;
124:
125: for (int i = 1; i <= c; i++) {
126: byte[] A = new byte[u];
127:
128: digest.update(D, 0, D.length);
129: digest.update(I, 0, I.length);
130: digest.doFinal(A, 0);
131: for (int j = 1; j != iterationCount; j++) {
132: digest.update(A, 0, A.length);
133: digest.doFinal(A, 0);
134: }
135:
136: for (int j = 0; j != B.length; j++) {
137: B[i] = A[j % A.length];
138: }
139:
140: for (int j = 0; j != I.length / v; j++) {
141: adjust(I, j * v, B);
142: }
143:
144: if (i == c) {
145: System.arraycopy(A, 0, dKey, (i - 1) * u, dKey.length
146: - ((i - 1) * u));
147: } else {
148: System.arraycopy(A, 0, dKey, (i - 1) * u, A.length);
149: }
150: }
151:
152: return dKey;
153: }
154:
155: /**
156: * Generate a key parameter derived from the password, salt, and iteration
157: * count we are currently initialised with.
158: *
159: * @param keySize the size of the key we want (in bits)
160: * @return a KeyParameter object.
161: */
162: public CipherParameters generateDerivedParameters(int keySize) {
163: keySize = keySize / 8;
164:
165: byte[] dKey = generateDerivedKey(KEY_MATERIAL, keySize);
166:
167: return new KeyParameter(dKey, 0, keySize);
168: }
169:
170: /**
171: * Generate a key with initialisation vector parameter derived from
172: * the password, salt, and iteration count we are currently initialised
173: * with.
174: *
175: * @param keySize the size of the key we want (in bits)
176: * @param ivSize the size of the iv we want (in bits)
177: * @return a ParametersWithIV object.
178: */
179: public CipherParameters generateDerivedParameters(int keySize,
180: int ivSize) {
181: keySize = keySize / 8;
182: ivSize = ivSize / 8;
183:
184: byte[] dKey = generateDerivedKey(KEY_MATERIAL, keySize);
185:
186: byte[] iv = generateDerivedKey(IV_MATERIAL, ivSize);
187:
188: return new ParametersWithIV(new KeyParameter(dKey, 0, keySize),
189: iv, 0, ivSize);
190: }
191:
192: /**
193: * Generate a key parameter for use with a MAC derived from the password,
194: * salt, and iteration count we are currently initialised with.
195: *
196: * @param keySize the size of the key we want (in bits)
197: * @return a KeyParameter object.
198: */
199: public CipherParameters generateDerivedMacParameters(int keySize) {
200: keySize = keySize / 8;
201:
202: byte[] dKey = generateDerivedKey(MAC_MATERIAL, keySize);
203:
204: return new KeyParameter(dKey, 0, keySize);
205: }
206: }
207:
208: public interface BrokenPBE {
209: //
210: // PBE Based encryption constants - by default we do PKCS12 with SHA-1
211: //
212: static final int MD5 = 0;
213: static final int SHA1 = 1;
214: static final int RIPEMD160 = 2;
215:
216: static final int PKCS5S1 = 0;
217: static final int PKCS5S2 = 1;
218: static final int PKCS12 = 2;
219: static final int OLD_PKCS12 = 3;
220:
221: /**
222: * uses the appropriate mixer to generate the key and IV if neccessary.
223: */
224: static class Util {
225: /**
226: * a faulty parity routine...
227: *
228: * @param bytes the byte array to set the parity on.
229: */
230: static private void setOddParity(byte[] bytes) {
231: for (int i = 0; i < bytes.length; i++) {
232: int b = bytes[i];
233: bytes[i] = (byte) ((b & 0xfe) | (((b >> 1) ^ (b >> 2)
234: ^ (b >> 3) ^ (b >> 4) ^ (b >> 5) ^ (b >> 6) ^ (b >> 7)) ^ 0x01));
235: }
236: }
237:
238: static private PBEParametersGenerator makePBEGenerator(
239: int type, int hash) {
240: PBEParametersGenerator generator;
241:
242: if (type == PKCS5S1) {
243: switch (hash) {
244: case MD5:
245: generator = new PKCS5S1ParametersGenerator(
246: new MD5Digest());
247: break;
248: case SHA1:
249: generator = new PKCS5S1ParametersGenerator(
250: new SHA1Digest());
251: break;
252: default:
253: throw new IllegalStateException(
254: "PKCS5 scheme 1 only supports only MD5 and SHA1.");
255: }
256: } else if (type == PKCS5S2) {
257: generator = new PKCS5S2ParametersGenerator();
258: } else if (type == OLD_PKCS12) {
259: switch (hash) {
260: case MD5:
261: generator = new OldPKCS12ParametersGenerator(
262: new MD5Digest());
263: break;
264: case SHA1:
265: generator = new OldPKCS12ParametersGenerator(
266: new SHA1Digest());
267: break;
268: case RIPEMD160:
269: generator = new OldPKCS12ParametersGenerator(
270: new RIPEMD160Digest());
271: break;
272: default:
273: throw new IllegalStateException(
274: "unknown digest scheme for PBE encryption.");
275: }
276: } else {
277: switch (hash) {
278: case MD5:
279: generator = new PKCS12ParametersGenerator(
280: new MD5Digest());
281: break;
282: case SHA1:
283: generator = new PKCS12ParametersGenerator(
284: new SHA1Digest());
285: break;
286: case RIPEMD160:
287: generator = new PKCS12ParametersGenerator(
288: new RIPEMD160Digest());
289: break;
290: default:
291: throw new IllegalStateException(
292: "unknown digest scheme for PBE encryption.");
293: }
294: }
295:
296: return generator;
297: }
298:
299: /**
300: * construct a key and iv (if neccessary) suitable for use with a
301: * Cipher.
302: */
303: static CipherParameters makePBEParameters(JCEPBEKey pbeKey,
304: AlgorithmParameterSpec spec, int type, int hash,
305: String targetAlgorithm, int keySize, int ivSize) {
306: if ((spec == null) || !(spec instanceof PBEParameterSpec)) {
307: throw new IllegalArgumentException(
308: "Need a PBEParameter spec with a PBE key.");
309: }
310:
311: PBEParameterSpec pbeParam = (PBEParameterSpec) spec;
312: PBEParametersGenerator generator = makePBEGenerator(type,
313: hash);
314: byte[] key = pbeKey.getEncoded();
315: CipherParameters param;
316:
317: generator.init(key, pbeParam.getSalt(), pbeParam
318: .getIterationCount());
319:
320: if (ivSize != 0) {
321: param = generator.generateDerivedParameters(keySize,
322: ivSize);
323: } else {
324: param = generator.generateDerivedParameters(keySize);
325: }
326:
327: if (targetAlgorithm.startsWith("DES")) {
328: if (param instanceof ParametersWithIV) {
329: KeyParameter kParam = (KeyParameter) ((ParametersWithIV) param)
330: .getParameters();
331:
332: setOddParity(kParam.getKey());
333: } else {
334: KeyParameter kParam = (KeyParameter) param;
335:
336: setOddParity(kParam.getKey());
337: }
338: }
339:
340: for (int i = 0; i != key.length; i++) {
341: key[i] = 0;
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: */
352: static CipherParameters makePBEMacParameters(JCEPBEKey pbeKey,
353: AlgorithmParameterSpec spec, int type, int hash,
354: int keySize) {
355: if ((spec == null) || !(spec instanceof PBEParameterSpec)) {
356: throw new IllegalArgumentException(
357: "Need a PBEParameter spec with a PBE key.");
358: }
359:
360: PBEParameterSpec pbeParam = (PBEParameterSpec) spec;
361: PBEParametersGenerator generator = makePBEGenerator(type,
362: hash);
363: byte[] key = pbeKey.getEncoded();
364: CipherParameters param;
365:
366: generator.init(key, pbeParam.getSalt(), pbeParam
367: .getIterationCount());
368:
369: param = generator.generateDerivedMacParameters(keySize);
370:
371: for (int i = 0; i != key.length; i++) {
372: key[i] = 0;
373: }
374:
375: return param;
376: }
377: }
378: }
|