001: package org.bouncycastle.jce.provider;
002:
003: import java.security.AlgorithmParameters;
004: import java.security.InvalidAlgorithmParameterException;
005: import java.security.InvalidKeyException;
006: import java.security.Key;
007: import java.security.KeyFactory;
008: import java.security.NoSuchAlgorithmException;
009: import java.security.NoSuchProviderException;
010: import java.security.SecureRandom;
011: import java.security.spec.AlgorithmParameterSpec;
012: import java.security.spec.InvalidKeySpecException;
013: import java.security.spec.PKCS8EncodedKeySpec;
014: import java.security.spec.X509EncodedKeySpec;
015:
016: import javax.crypto.BadPaddingException;
017: import javax.crypto.Cipher;
018: import javax.crypto.IllegalBlockSizeException;
019: import javax.crypto.NoSuchPaddingException;
020: import javax.crypto.spec.IvParameterSpec;
021: import javax.crypto.spec.PBEParameterSpec;
022: import javax.crypto.spec.RC2ParameterSpec;
023: import javax.crypto.spec.RC5ParameterSpec;
024: import javax.crypto.spec.SecretKeySpec;
025:
026: import org.bouncycastle.crypto.BlockCipher;
027: import org.bouncycastle.crypto.BufferedBlockCipher;
028: import org.bouncycastle.crypto.CipherParameters;
029: import org.bouncycastle.crypto.DataLengthException;
030: import org.bouncycastle.crypto.InvalidCipherTextException;
031: import org.bouncycastle.crypto.engines.DESEngine;
032: import org.bouncycastle.crypto.engines.DESedeEngine;
033: import org.bouncycastle.crypto.engines.TwofishEngine;
034: import org.bouncycastle.crypto.modes.CBCBlockCipher;
035: import org.bouncycastle.crypto.modes.CFBBlockCipher;
036: import org.bouncycastle.crypto.modes.CTSBlockCipher;
037: import org.bouncycastle.crypto.modes.OFBBlockCipher;
038: import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
039: import org.bouncycastle.crypto.params.KeyParameter;
040: import org.bouncycastle.crypto.params.ParametersWithIV;
041: import org.bouncycastle.crypto.params.RC2Parameters;
042: import org.bouncycastle.crypto.params.RC5Parameters;
043: import org.bouncycastle.util.Strings;
044:
045: public class BrokenJCEBlockCipher implements BrokenPBE {
046: //
047: // specs we can handle.
048: //
049: private Class[] availableSpecs = { IvParameterSpec.class,
050: PBEParameterSpec.class, RC2ParameterSpec.class,
051: RC5ParameterSpec.class };
052:
053: private BufferedBlockCipher cipher;
054: private ParametersWithIV ivParam;
055:
056: private int pbeType = PKCS12;
057: private int pbeHash = SHA1;
058: private int pbeKeySize;
059: private int pbeIvSize;
060:
061: private int ivLength = 0;
062:
063: private AlgorithmParameters engineParams = null;
064:
065: protected BrokenJCEBlockCipher(BlockCipher engine) {
066: cipher = new PaddedBufferedBlockCipher(engine);
067: }
068:
069: protected BrokenJCEBlockCipher(BlockCipher engine, int pbeType,
070: int pbeHash, int pbeKeySize, int pbeIvSize) {
071: cipher = new PaddedBufferedBlockCipher(engine);
072:
073: this .pbeType = pbeType;
074: this .pbeHash = pbeHash;
075: this .pbeKeySize = pbeKeySize;
076: this .pbeIvSize = pbeIvSize;
077: }
078:
079: protected int engineGetBlockSize() {
080: return cipher.getBlockSize();
081: }
082:
083: protected byte[] engineGetIV() {
084: return (ivParam != null) ? ivParam.getIV() : null;
085: }
086:
087: protected int engineGetKeySize(Key key) {
088: return key.getEncoded().length;
089: }
090:
091: protected int engineGetOutputSize(int inputLen) {
092: return cipher.getOutputSize(inputLen);
093: }
094:
095: protected AlgorithmParameters engineGetParameters() {
096: if (engineParams == null) {
097: if (ivParam != null) {
098: String name = cipher.getUnderlyingCipher()
099: .getAlgorithmName();
100:
101: if (name.indexOf('/') >= 0) {
102: name = name.substring(0, name.indexOf('/'));
103: }
104:
105: try {
106: engineParams = AlgorithmParameters.getInstance(
107: name, "BC");
108: engineParams.init(ivParam.getIV());
109: } catch (Exception e) {
110: throw new RuntimeException(e.toString());
111: }
112: }
113: }
114:
115: return engineParams;
116: }
117:
118: protected void engineSetMode(String mode) {
119: String modeName = Strings.toUpperCase(mode);
120:
121: if (modeName.equals("ECB")) {
122: ivLength = 0;
123: cipher = new PaddedBufferedBlockCipher(cipher
124: .getUnderlyingCipher());
125: } else if (modeName.equals("CBC")) {
126: ivLength = cipher.getUnderlyingCipher().getBlockSize();
127: cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(
128: cipher.getUnderlyingCipher()));
129: } else if (modeName.startsWith("OFB")) {
130: ivLength = cipher.getUnderlyingCipher().getBlockSize();
131: if (modeName.length() != 3) {
132: int wordSize = Integer.parseInt(modeName.substring(3));
133:
134: cipher = new PaddedBufferedBlockCipher(
135: new OFBBlockCipher(
136: cipher.getUnderlyingCipher(), wordSize));
137: } else {
138: cipher = new PaddedBufferedBlockCipher(
139: new OFBBlockCipher(
140: cipher.getUnderlyingCipher(),
141: 8 * cipher.getBlockSize()));
142: }
143: } else if (modeName.startsWith("CFB")) {
144: ivLength = cipher.getUnderlyingCipher().getBlockSize();
145: if (modeName.length() != 3) {
146: int wordSize = Integer.parseInt(modeName.substring(3));
147:
148: cipher = new PaddedBufferedBlockCipher(
149: new CFBBlockCipher(
150: cipher.getUnderlyingCipher(), wordSize));
151: } else {
152: cipher = new PaddedBufferedBlockCipher(
153: new CFBBlockCipher(
154: cipher.getUnderlyingCipher(),
155: 8 * cipher.getBlockSize()));
156: }
157: } else {
158: throw new IllegalArgumentException("can't support mode "
159: + mode);
160: }
161: }
162:
163: protected void engineSetPadding(String padding)
164: throws NoSuchPaddingException {
165: String paddingName = Strings.toUpperCase(padding);
166:
167: if (paddingName.equals("NOPADDING")) {
168: cipher = new BufferedBlockCipher(cipher
169: .getUnderlyingCipher());
170: } else if (paddingName.equals("PKCS5PADDING")
171: || paddingName.equals("PKCS7PADDING")
172: || paddingName.equals("ISO10126PADDING")) {
173: cipher = new PaddedBufferedBlockCipher(cipher
174: .getUnderlyingCipher());
175: } else if (paddingName.equals("WITHCTS")) {
176: cipher = new CTSBlockCipher(cipher.getUnderlyingCipher());
177: } else {
178: throw new NoSuchPaddingException("Padding " + padding
179: + " unknown.");
180: }
181: }
182:
183: protected void engineInit(int opmode, Key key,
184: AlgorithmParameterSpec params, SecureRandom random)
185: throws InvalidKeyException,
186: InvalidAlgorithmParameterException {
187: CipherParameters param;
188:
189: //
190: // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
191: //
192: if (key instanceof JCEPBEKey) {
193: param = BrokenPBE.Util.makePBEParameters((JCEPBEKey) key,
194: params, pbeType, pbeHash, cipher
195: .getUnderlyingCipher().getAlgorithmName(),
196: pbeKeySize, pbeIvSize);
197:
198: if (pbeIvSize != 0) {
199: ivParam = (ParametersWithIV) param;
200: }
201: } else if (params == null) {
202: param = new KeyParameter(key.getEncoded());
203: } else if (params instanceof IvParameterSpec) {
204: if (ivLength != 0) {
205: param = new ParametersWithIV(new KeyParameter(key
206: .getEncoded()), ((IvParameterSpec) params)
207: .getIV());
208: ivParam = (ParametersWithIV) param;
209: } else {
210: param = new KeyParameter(key.getEncoded());
211: }
212: } else if (params instanceof RC2ParameterSpec) {
213: RC2ParameterSpec rc2Param = (RC2ParameterSpec) params;
214:
215: param = new RC2Parameters(key.getEncoded(),
216: ((RC2ParameterSpec) params).getEffectiveKeyBits());
217:
218: if (rc2Param.getIV() != null && ivLength != 0) {
219: param = new ParametersWithIV(param, rc2Param.getIV());
220: ivParam = (ParametersWithIV) param;
221: }
222: } else if (params instanceof RC5ParameterSpec) {
223: RC5ParameterSpec rc5Param = (RC5ParameterSpec) params;
224:
225: param = new RC5Parameters(key.getEncoded(),
226: ((RC5ParameterSpec) params).getRounds());
227: if (rc5Param.getWordSize() != 32) {
228: throw new IllegalArgumentException(
229: "can only accept RC5 word size 32 (at the moment...)");
230: }
231: if ((rc5Param.getIV() != null) && (ivLength != 0)) {
232: param = new ParametersWithIV(param, rc5Param.getIV());
233: ivParam = (ParametersWithIV) param;
234: }
235: } else {
236: throw new InvalidAlgorithmParameterException(
237: "unknown parameter type.");
238: }
239:
240: if ((ivLength != 0) && !(param instanceof ParametersWithIV)) {
241: if (random == null) {
242: random = new SecureRandom();
243: }
244:
245: if ((opmode == Cipher.ENCRYPT_MODE)
246: || (opmode == Cipher.WRAP_MODE)) {
247: byte[] iv = new byte[ivLength];
248:
249: random.nextBytes(iv);
250: param = new ParametersWithIV(param, iv);
251: ivParam = (ParametersWithIV) param;
252: } else {
253: throw new InvalidAlgorithmParameterException(
254: "no IV set when one expected");
255: }
256: }
257:
258: switch (opmode) {
259: case Cipher.ENCRYPT_MODE:
260: case Cipher.WRAP_MODE:
261: cipher.init(true, param);
262: break;
263: case Cipher.DECRYPT_MODE:
264: case Cipher.UNWRAP_MODE:
265: cipher.init(false, param);
266: break;
267: default:
268: System.out.println("eeek!");
269: }
270: }
271:
272: protected void engineInit(int opmode, Key key,
273: AlgorithmParameters params, SecureRandom random)
274: throws InvalidKeyException,
275: InvalidAlgorithmParameterException {
276: AlgorithmParameterSpec paramSpec = null;
277:
278: if (params != null) {
279: for (int i = 0; i != availableSpecs.length; i++) {
280: try {
281: paramSpec = params
282: .getParameterSpec(availableSpecs[i]);
283: break;
284: } catch (Exception e) {
285: continue;
286: }
287: }
288:
289: if (paramSpec == null) {
290: throw new InvalidAlgorithmParameterException(
291: "can't handle parameter " + params.toString());
292: }
293: }
294:
295: engineParams = params;
296: engineInit(opmode, key, paramSpec, random);
297: }
298:
299: protected void engineInit(int opmode, Key key, SecureRandom random)
300: throws InvalidKeyException {
301: try {
302: engineInit(opmode, key, (AlgorithmParameterSpec) null,
303: random);
304: } catch (InvalidAlgorithmParameterException e) {
305: throw new IllegalArgumentException(e.getMessage());
306: }
307: }
308:
309: protected byte[] engineUpdate(byte[] input, int inputOffset,
310: int inputLen) {
311: int length = cipher.getUpdateOutputSize(inputLen);
312:
313: if (length > 0) {
314: byte[] out = new byte[length];
315:
316: cipher.processBytes(input, inputOffset, inputLen, out, 0);
317: return out;
318: }
319:
320: cipher.processBytes(input, inputOffset, inputLen, null, 0);
321:
322: return null;
323: }
324:
325: protected int engineUpdate(byte[] input, int inputOffset,
326: int inputLen, byte[] output, int outputOffset) {
327: return cipher.processBytes(input, inputOffset, inputLen,
328: output, outputOffset);
329: }
330:
331: protected byte[] engineDoFinal(byte[] input, int inputOffset,
332: int inputLen) throws IllegalBlockSizeException,
333: BadPaddingException {
334: int len = 0;
335: byte[] tmp = new byte[engineGetOutputSize(inputLen)];
336:
337: if (inputLen != 0) {
338: len = cipher.processBytes(input, inputOffset, inputLen,
339: tmp, 0);
340: }
341:
342: try {
343: len += cipher.doFinal(tmp, len);
344: } catch (DataLengthException e) {
345: throw new IllegalBlockSizeException(e.getMessage());
346: } catch (InvalidCipherTextException e) {
347: throw new BadPaddingException(e.getMessage());
348: }
349:
350: byte[] out = new byte[len];
351:
352: System.arraycopy(tmp, 0, out, 0, len);
353:
354: return out;
355: }
356:
357: protected int engineDoFinal(byte[] input, int inputOffset,
358: int inputLen, byte[] output, int outputOffset)
359: throws IllegalBlockSizeException, BadPaddingException {
360: int len = 0;
361:
362: if (inputLen != 0) {
363: len = cipher.processBytes(input, inputOffset, inputLen,
364: output, outputOffset);
365: }
366:
367: try {
368: return len + cipher.doFinal(output, outputOffset + len);
369: } catch (DataLengthException e) {
370: throw new IllegalBlockSizeException(e.getMessage());
371: } catch (InvalidCipherTextException e) {
372: throw new BadPaddingException(e.getMessage());
373: }
374: }
375:
376: protected byte[] engineWrap(Key key)
377: throws IllegalBlockSizeException,
378: java.security.InvalidKeyException {
379: byte[] encoded = key.getEncoded();
380: if (encoded == null) {
381: throw new InvalidKeyException(
382: "Cannot wrap key, null encoding.");
383: }
384:
385: try {
386: return engineDoFinal(encoded, 0, encoded.length);
387: } catch (BadPaddingException e) {
388: throw new IllegalBlockSizeException(e.getMessage());
389: }
390: }
391:
392: protected Key engineUnwrap(byte[] wrappedKey,
393: String wrappedKeyAlgorithm, int wrappedKeyType)
394: throws InvalidKeyException {
395: byte[] encoded = null;
396: try {
397: encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
398: } catch (BadPaddingException e) {
399: throw new InvalidKeyException(e.getMessage());
400: } catch (IllegalBlockSizeException e2) {
401: throw new InvalidKeyException(e2.getMessage());
402: }
403:
404: if (wrappedKeyType == Cipher.SECRET_KEY) {
405: return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
406: } else {
407: try {
408: KeyFactory kf = KeyFactory.getInstance(
409: wrappedKeyAlgorithm, "BC");
410:
411: if (wrappedKeyType == Cipher.PUBLIC_KEY) {
412: return kf.generatePublic(new X509EncodedKeySpec(
413: encoded));
414: } else if (wrappedKeyType == Cipher.PRIVATE_KEY) {
415: return kf.generatePrivate(new PKCS8EncodedKeySpec(
416: encoded));
417: }
418: } catch (NoSuchProviderException e) {
419: throw new InvalidKeyException("Unknown key type "
420: + e.getMessage());
421: } catch (NoSuchAlgorithmException e) {
422: throw new InvalidKeyException("Unknown key type "
423: + e.getMessage());
424: } catch (InvalidKeySpecException e2) {
425: throw new InvalidKeyException("Unknown key type "
426: + e2.getMessage());
427: }
428:
429: throw new InvalidKeyException("Unknown key type "
430: + wrappedKeyType);
431: }
432: }
433:
434: /*
435: * The ciphers that inherit from us.
436: */
437:
438: /**
439: * PBEWithMD5AndDES
440: */
441: static public class BrokePBEWithMD5AndDES extends
442: BrokenJCEBlockCipher {
443: public BrokePBEWithMD5AndDES() {
444: super (new CBCBlockCipher(new DESEngine()), PKCS5S1, MD5,
445: 64, 64);
446: }
447: }
448:
449: /**
450: * PBEWithSHA1AndDES
451: */
452: static public class BrokePBEWithSHA1AndDES extends
453: BrokenJCEBlockCipher {
454: public BrokePBEWithSHA1AndDES() {
455: super (new CBCBlockCipher(new DESEngine()), PKCS5S1, SHA1,
456: 64, 64);
457: }
458: }
459:
460: /**
461: * PBEWithSHAAnd3-KeyTripleDES-CBC
462: */
463: static public class BrokePBEWithSHAAndDES3Key extends
464: BrokenJCEBlockCipher {
465: public BrokePBEWithSHAAndDES3Key() {
466: super (new CBCBlockCipher(new DESedeEngine()), PKCS12, SHA1,
467: 192, 64);
468: }
469: }
470:
471: /**
472: * OldPBEWithSHAAnd3-KeyTripleDES-CBC
473: */
474: static public class OldPBEWithSHAAndDES3Key extends
475: BrokenJCEBlockCipher {
476: public OldPBEWithSHAAndDES3Key() {
477: super (new CBCBlockCipher(new DESedeEngine()), OLD_PKCS12,
478: SHA1, 192, 64);
479: }
480: }
481:
482: /**
483: * PBEWithSHAAnd2-KeyTripleDES-CBC
484: */
485: static public class BrokePBEWithSHAAndDES2Key extends
486: BrokenJCEBlockCipher {
487: public BrokePBEWithSHAAndDES2Key() {
488: super (new CBCBlockCipher(new DESedeEngine()), PKCS12, SHA1,
489: 128, 64);
490: }
491: }
492:
493: /**
494: * OldPBEWithSHAAndTwofish-CBC
495: */
496: static public class OldPBEWithSHAAndTwofish extends
497: BrokenJCEBlockCipher {
498: public OldPBEWithSHAAndTwofish() {
499: super (new CBCBlockCipher(new TwofishEngine()), OLD_PKCS12,
500: SHA1, 256, 128);
501: }
502: }
503: }
|